Creating a Portable Text Resizing Widget

This write-up was originally posted on LogRocket.


Improving general web accessibility is a vast and ever-changing process, but it is important to ensure that websites and applications are accessible to all users.

In this tutorial, we will focus on a simple yet crucial aspect of the user experience: text size. For some users, “normal-sized” text can be too small to read comfortably or at all, and, depending on the font size and family, even users with good vision may have difficulty reading text comfortably.

There are a number of ways to accommodate users, one of which is by implementing a text resizing widget. In its simplest form, this widget is a pair of buttons or links that increase or decrease the text size.

Let’s learn how to implement a text resizing widget.

Accessibility standards for adjustable text

The requirement for adjustable text size comes from WCAG 2.0 Guideline 1.4.4:

Resize text: Except for captions and images of text, text can be resized without assistive technology up to 200 percent without loss of content or functionality. (Level AA)

There is not a whole lot to go off of there, but WCAG 2.0 provides additional information in Understanding SC 1.4.4. The main takeaways are the following:

  • The intent is to help people with low vision read text on a web page
  • Text must be resizable up to at least 200%
  • Content must not be clipped, truncated, or obscured when text is resized

It’s important to note that a text resizing widget is not a requirement. It is one of the suggested techniques for ensuring users can read your website, but there are other acceptable solutions to adjusting your text, such as simply ensuring your website responds to browser text size settings.

My interpretation of the requirements boils down to this: all critical text must be resizable to at least 200% of the default font size (16px). This is admittedly a somewhat loose interpretation, but my thinking is anything larger than 32px is larger than 200% of the default font size, so it’s presumably already legible enough to begin with.

In addition, if you have large headings and you resize them to 200% of their original size, it’s likely to cause clipping or other layout issues, which would fail the guideline.

Feasibility of retrofitting the text widget

Now, let’s talk about the feasibility of implementing a text widget. Specifically, I’m going to discuss this in the context of retrofitting a widget on an existing site — one that was not necessarily designed or built with text resizing in mind.

A website like this can present a number of challenges, but I will focus on two:

  • Some font sizes may be in pixels instead of relative units like em or rem. Yes, this is a big no-no, but the reality is that websites like this still exist for a number of reasons
  • If there is very large text on the site, increasing its size will likely break the layout

There are a few different ways our widget could work. We could make it change the font-size of <html> or <body>. That would be easy, but it wouldn’t affect font sizes set in pixels, and it would target all text on the site, including text that is already large.

After a number of iterations, this is the approach I’ve settled on:

  • Use CSS selectors to specify what should be resized
  • For each selector, get the initial font-size
  • When text size is adjusted, update font-size for each selector based on the initial size
  • Store the text size setting in browser memory so it persists across pages and sessions

This approach has a number of advantages. First, it’s extremely flexible and can be used on virtually any site without updating markup or styling. Font sizes can be in any unit initially because the script will read the initial size and use it as a baseline for calculating new font sizes. This approach can also be used to create a system where a class enables resizing of specific text.

Creating a text resizing widget

Here’s where we’ll end up:

Let’s walk through the script.

First, create an array of CSS selectors for all of the text elements that should be resizable. You can use existing selectors that are already in your markup, or you can create a class just for this.

JavaScript
let selectorsToScale = [
  'p',
  'button',
  '#some .very .specific.selector',
  '.a-class-that-makes-text-resizable'
];

For each selector, get the font-size and store the selector and font size as a key-value pair in an array.

JavaScript
for (const selector of selectorsToScale) {
  let fontSize = $(selector).css('font-size');

  if (fontSize) {
    fontSize = fontSize.slice(0, fontSize.length - 2);
  } else {
    fontSize = '';
  }

  initialSizes[selector] = fontSize;
}

When a user adjusts the text size with the widget, the setting is saved in the browser. This setting is simply a number from 100 to 200 and represents the scale factor for text size as a percentage.

Here we check to see if there is a saved setting so that text size adjustments persist across pages and browsing sessions.

JavaScript
if (fontSizeSetting) {
  setFontSizes(fontSizeSetting);
} else {
  fontSizeSetting = 100.0;
}

When a resize button is clicked, update the setting variable, store it in the browser, then update font sizes:

JavaScript
function changeFontSizes(direction) {
  if (direction === 'down') {
    fontSizeSetting -= 10;
  } else {
    fontSizeSetting += 10;
  }
  localStorage.setItem('codepenFontSizeSetting', fontSizeSetting);
  setFontSizes(fontSizeSetting);
}

Finally, let’s focus on the part that actually resizes the text. For each selector we specified at the beginning, we calculate the new font-size — in pixels — based on the initial value and the new text size setting, then apply that font-size to the selector.

JavaScript
function setFontSizes(setting) {
  const resizeFactor = setting / 100.0;

  indicator.html(parseInt(setting));

  for (const selector of selectorsToScale) {
    let initialSize = initialSizes[selector];

    initialSize = parseFloat(initialSize);

    let newSize = initialSize * resizeFactor;

    $(selector).css('font-size', newSize + 'px');
  }
}

Last but not least, I have a few thoughts on the appearance of the widget. The G178 technique is sparse on details, but it’s important to make the widget easy to use for those who need it. The text should be fairly large with high contrast, and the buttons should be easy to click.

The widget itself should also be easy to find on the page, and its purpose should be clear, so avoid using trendy but vague icons. To keep it out of the way but still easily accessible, I chose to make my text resizing widget slide out from the side or bottom of the screen, but that is optional. A static widget is perfectly acceptable, too.

Conclusion

When building for the web, there are a thousand ways to get something done. Resizing text is no different. The approach outlined here is a relatively low-friction way to enable text resizing on existing sites, but ultimately, the right approach for you will depend on the platform, codebase, audience, and budget of your project.