Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Dynamic Font Size Using HTML and JavaScript

4.50/5 (5 votes)
8 Dec 2010CPOL5 min read 77.6K   690  
Describes a method to build web pages that provide the ability for the user to change the font size dynamically.
Dynamic Font Size

Introduction

Many web pages can benefit from an ability for the user to change the font size dynamically. This article describes a method to build web pages that provide that functionality using HTML and JavaScript.

Background

Quite often, I find myself using the Ctrl-Plus shortcut (in Internet Explorer) to increase the size of a web page font. Unfortunately, that shortcut increases the size of all web page components (e.g., figures, text boxes, etc.), some of which I do not want increased.

Providing the ability to increase the font size of only selected portions of the web page text requires some relatively advanced JavaScript interaction with the Document Object Model that underlies all web pages. But once mastered, developing the method is relatively straightforward.

Using the Code

The pertinent directory structure of my website is:

GGGustafson
    CSS
      CSS.css
    Images
      favicon.ico
      Lenna.png
      Melitta_teapot.png
      Utah_teapot.png
      ValidXHTML10.png
    Scripts
      control_font_size.js
      cookies.js
      next_page.js
    Default.html

Note that I am hosting my site on Microsoft Office Live (MSOL). MSOL expects web pages to be ASPX or HTML pages. For this article, I will be using an HTML page in the DynamicFontSize downloadable source. However, if the reader uses Visual Studio to build web site pages, choose ASPX pages. Once a new page is defined, you may, if desired, delete the aspx.cs and designer.cs pages that are automatically generated by Visual Studio. You may also change the web page extension from .aspx to .html (replying "Yes" in the following dialog box).

Rename Dialog Box

The variable_font Class

To limit text font sizing to specific HTML elements, we need a mechanism to identify those text elements that we want to allow to be resized. I chose to assign a class named variable_font to each element that was to participate in resizing.

First, in the CSS file, define a selector for variable_font.

CSS
.variable_font
{
    font-size:13pt;
}

This rule assigns the default font size for all elements to which the class applies. Note that the value chosen here should be the same as that chosen for the DEFAULT_FONT_SIZE global variable declared at the top of the control_font_size script.

Then assign the class to each element that will participate in the text font sizing. For example:

HTML
<p class="variable_font" ></p>

This class may be applied to any element that allows a font size attribute (e.g., input, p, td, span, etc.).

Initialization

On window load, the initialize_font_size function must be invoked. For our purposes, I'll simply attach it as the body onload event handler.

HTML
<body onload="initialize_font_size('CSS.css', '.variable_font');">

The initialize_font_size function is found in the control_font_size script:

JavaScript
// ********************************************* initialize_font_size

/// <summary>
///     initializes the variable 'variable_font_rule' to point to the 
///     rule that controls the font size for all elements that are 
///     declared as "class='selector'" in the cascading style sheet 
///     named 'css_sheet_name'; reads a cookie to determine the 
///     current font size; sets all such elements to the default font 
///     size, either read from the cookie or specified by the global 
///     variable DEFAULT_FONT_SIZE
/// </summary>
///
/// <param name="css_sheet_name">
///     a string containing the name of the cascading style sheet 
///     file name, including the extension
/// </param>
///
/// <param name="selector">
///     a the string containing the selector (class name), found in 
///     the specified cascading style sheet; it must include the 
///     selector prefix (i.e., '.' for classes)
/// </param>
///

function initialize_font_size ( css_sheet_name,
                                selector )
{

  if ( document.styleSheets && css_sheet_name && selector )
    {
    var done = false;
    var found = false;
    var i = 0;
    var sheet_rules;
    var sheets = document.styleSheets;
    var the_rules = new Array();

    css_sheet_name = css_sheet_name.toLowerCase ( );

    i = 0;
    done = ( i >= sheets.length );
    while ( ! ( done || found ) )
      {
      var sheet_name = sheets [ i ].href.substring ( 
                         sheets [ i ].href.lastIndexOf ( '/' ) + 1 ).
                           toLowerCase ( );
      if ( sheet_name == css_sheet_name )
        {
        the_rules = sheets [ i ].cssRules || sheets [ i ].rules;
        found = true;
        }
      else
        {
        i++;
        done = ( i >= sheets.length );
        }    
      }

    if ( found )
      {
      found = false;
      
      i = 0;
      done = ( i >= the_rules.length );
      while ( ! ( done || found ) )
        {
        found = ( the_rules [ i ].selectorText.toLowerCase ( ) == 
                  selector.toLowerCase ( ) );
        if ( found )
          {
          variable_font_rule = the_rules [ i ];
          } 
        else
          {
          i++;
          done = ( i >= the_rules.length );
          }    
        }
      }

    if ( variable_font_rule )
      {
      var cookie = read_cookie ( COOKIE_NAME );
      var font_size = DEFAULT_FONT_SIZE;

      if ( cookie )
        {
        font_size = parseInt ( cookie, 10 );
        }
      variable_font_rule.style.fontSize = ( font_size ) + "px";
      create_cookie ( COOKIE_NAME, font_size.toString ( ), 0 );
      }
    }
}

If the document includes at least one CSS style sheet and the two required arguments are provided, the initialize_font_size script:

  • Initializes the global variable variable_font_rule to point to the CSS rule that controls the font size for all elements that are declared as "class='selector'" in the cascading style sheet named 'css_sheet_name' (note that the invoker supplies the actual values for 'css_sheet_name' and 'selector').
  • If the global variable variable_font_rule is successfully initialized (i.e., is not undefined or null), reads a cookie named COOKIE_NAME to determine the new font size. If the cookie does not exist, the new font size is set to the value specified by the global variable DEFAULT_FONT_SIZE.
  • Sets the font sizes of all affected web page elements to the new font size by simply setting the style.fontSize of variable_font_rule to the new font size.
  • Writes the new font size to the cookie named COOKIE_NAME.

The string containing the name of the cascading style sheet file name must include the extension, and the string containing the selector (class name) found in the specified cascading style sheet must include the selector prefix (i.e., '.' for classes).

Mouse Click Resizing

I think that the easiest way to indicate to a user that text resizing is available is to present a visual clue on the web page. To that end, following NPR as a guide, the phrase 'text size' followed by differently sized letter 'A's is used. Additionally, a title that appears when the mouse hovers over the letter is included to make the action taken on a mouse click more obvious.

The HTML that triggers mouse click text sizing (shown to the right in the figure that appears at the top of this article) is encapsulated in a <div>.

HTML
<div class="textsize">
    text size 
    <a class="small" 
       href="javascript:void(0);" 
       onclick="reduce_font_size()" 
       title="Reduce font size">
      A
    </a> 
    <a class="big"
       href="javascript:void(0);" 
       onclick="restore_font_size()"
       title="Restore default font size">
      A
    </a> 
    <a class="bigger" 
       href="javascript:void(0);" 
       onclick="increase_font_size()"
       title="Increase font size">
      A
    </a>
</div>

This font sizing implementation requires three functions, reduce_font_size, restore_font_size, and increase_font_size, all found in the control_font_size script file. All three require that initialize_font_size has been successfully invoked, that is, the global variable variable_font_rule has been successfully initialized. Also, each of these functions requires cookie support found in the cookies script file.

JavaScript
// ************************************************* reduce_font_size

/// <summary>
///     reduces, by one point, the font size of elements that are 
///     declared as "class='variable_font'"


function reduce_font_size ( )
{
  
  if ( variable_font_rule )
    {
    var cookie = read_cookie ( COOKIE_NAME );
    var font_size = DEFAULT_FONT_SIZE;
  
    if ( cookie )
      {
      font_size = parseInt ( cookie, 10 );
      }
  
    if ( font_size > MINIMUM_FONT_SIZE )
      {
      font_size--;
      variable_font_rule.style.fontSize = ( font_size ) + "px";
      create_cookie ( COOKIE_NAME, font_size.toString ( ), 0 );
      }
    }
}

// ************************************************ restore_font_size

/// <summary>
///     restores the font size of elements that are declared as 
///     "class='variable_font'" to the default font size

function restore_font_size ( )
{

  if ( variable_font_rule )
    {
    var font_size = DEFAULT_FONT_SIZE;
  
    variable_font_rule.style.fontSize = ( font_size ) + "px";
    create_cookie ( COOKIE_NAME, font_size.toString ( ), 0 );
    }
}
  
// *********************************************** increase_font_size

/// <summary>
///     increases, by one point, the font size of elements that are 
///     declared as "class='variable_font'"

function increase_font_size ( )
{

  if ( variable_font_rule )
    {
    var cookie = read_cookie ( COOKIE_NAME );
    var font_size = DEFAULT_FONT_SIZE;
  
    if ( cookie )
      {
      font_size = parseInt ( cookie, 10 );
      }
  
    if ( font_size < MAXIMUM_FONT_SIZE )
      {
      font_size++;
      variable_font_rule.style.fontSize = ( font_size ) + "px";
      create_cookie ( COOKIE_NAME, font_size.toString ( ), 0 );
      }
    }
}

The global constants used in the control_font_size script are:

JavaScript
var COOKIE_NAME = "SAVED_VARIABLE_FONT_SIZE";
var DEFAULT_FONT_SIZE = 13;
var MAXIMUM_FONT_SIZE = 24;
var MINIMUM_FONT_SIZE = 8;

The cookies script provides support for the font sizing scripts. A cookie is set to preserve the user's desired font size from web page load to web page load.

JavaScript
// http://www.quirksmode.org/js/cookies.html

// **************************************************** create_cookie

/// <synopsis>
///     create_cookie ( name, value, days );
/// </synopsis>
///
/// <summary>
///     creates a cookie with the specified name, value, and 
///     expiration
/// </summary>
///
/// <param name="name">
///     a string containing the name of the cookie. if a cookie 
///     with the same name exists, it will be overwritten.
/// </param>
///
/// <param name="value">
///     a string containing the value to be assigned to the 
///     cookie
/// </param>
///
/// <param name="days">
///     the cookie expiration, specified in days
/// </param>
///
/// <example>
///     When calling createCookie() you have to give it three 
///     three pieces of information: the name and value of the 
///     cookie and the number of days it is to remain active. 
///     For example, to set a cookie named 'mycookie' to the value 
///     'mycookievalue' and have it active for 7 days, use
///  
///         create_cookie ( 'mycookie', 'mycookievalue', 7 );
/// 
///     If you want the cookie to exist as a session cookie, that is 
///     the cookie is trashed when the user closes the browser, 
///     set the number of days to 0. 
///
///     If you set the number of days to a negative number, the 
///     cookie is trashed immediately.
/// <example>

function create_cookie ( name, value, days ) 
{
  var expires = "";

  if ( days ) 
    {
    var date = new Date ( );

    date.setTime ( date.getTime ( ) + 
                 ( days * 24 * 60 * 60 * 1000 ) );
    expires = "; expires=" + date.toGMTString ( );
    }

  document.cookie = name + "=" + value + expires + "; path=/";
}

// ****************************************************** read_cookie

/// <synopsis>
///     var cookie = read_cookie ( name );
///     if ( cookie )
///       {
///       // do something with the cookie value
///       }
/// </synopsis>
///
/// <summary>
///     reads the value of a cookie
/// </summary>
///
/// <param name="name">
///     a string containing the name of the cookie to be read
/// </param>
///
/// <returns>
///     if the cookie exists, a string containing the value of 
///     the cookie; otherwise, null
/// </returns>

function read_cookie ( name ) 
{
  var cookie = null;
  
  if ( document.cookie.length > 0 )
    {
    var cookies = document.cookie.split ( ';' );
    var name_with_equal = name + "=";

    for ( var i = 0; ( i < cookies.length ); i++ ) 
      {
      var a_cookie = cookies [ i ];

      a_cookie = a_cookie.replace ( /^\s*/, "" );
      if ( a_cookie.indexOf ( name_with_equal ) === 0 )
        {
        cookie = a_cookie.substring ( name_with_equal.length, 
                                      a_cookie.length );
        break;
        }
      }
    }

  return ( cookie );
}

// ***************************************************** erase_cookie

/// <synopsis>
///     erase_cookie ( name );
/// </synopsis>
///
/// <summary>
///     remove the specified cookie
/// </summary>
///
/// <param name="name">
///     a string containing the name of the cookie to be removed
/// </param>

function erase_cookie ( name )
{
  
  create_cookie ( name, "", -1 );
}

The <script></script> blocks that I include to implement dynamic font sizing are:

HTML
<script type="text/javascript" 
  defer="defer" 
  src="Scripts/control_font_size.js"></script>
<script type="text/javascript" 
  defer="defer" 
  src="Scripts/cookies.js"></script>
<script type="text/javascript" 
      defer="defer" 
      src="Scripts/next_page.js"></script>

I place the <script></script> blocks before the </body> tag. I add defer="defer" to the <script> include blocks to ensure that the HTML loads completely before the scripts are loaded. Note that the "defer" attribute of the <script> tag is currently implemented only by Internet Explorer. I expect other browsers to implement this standard attribute in the future. Of course, all of the scripts can be combined into one script file. Then that single script file can be included.

Keyboard Font Sizing

The user may be provided font sizing keyboard shortcuts:

  • '+' - increases font size
  • '-' - decreases font size
  • ' ' - restores font size to default

The shortcuts are processed by the on_keyup event handler found in the control_font_size script file. Again, cookies are used to "remember" the last font size set by the user.

JavaScript
// ********************************************************* on_keyup

/// <summary>
///     event handler that responds to keyup events by determining 
///     what key was released and invoking the appropriate font size 
///     function
///
///       '+' - increase font size
///       '-' - decrease font size
///       ' ' - restore font size to default

function on_keyup ( e )
{
  var code = (window.event) ? event.keyCode : e.keyCode;

  switch ( code )
    {
    case 109 :
    case 189 : // '-'
      reduce_font_size ( );
      break;
    
    case 107 :
    case 187 : // '+'
      increase_font_size ( );
      break;
    
    case 32 :  // ' '
      restore_font_size ( );
      break;
    
    default :  // don't handle it in this module
    
      break;
    }
}

This event handler is registered by attaching it to the document.onkeyup event. In the control_font_size script file, this is accomplished by the statement:

JavaScript
document.onkeyup=on_keyup;

The expiration date of the cookie is set to zero so that the cookie exists only for the duration of the session. The cookies script was developed from JavaScript found at Peter-Paul Koch's cookies web page.

References

Cookie functions contain source code for the cookies script.

Browsers Tested

Internet Explorer Firefox Google Chrome Safari Opera Incompatible

Opera operates somewhat strangely, so I am unwilling to include it as a successfully tested browser.

History

  • 11/15/2010 - Revised article to address reader's comments, to correct typographic and logic errors, and to test the paradigm on common browsers
  • 12/6/2010 - Minor revisions to document; added browser versions of browsers used for testing

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)