How To Style Resized Text and Quickly Fix WCAG 1.4.4 Issues

May 26th, 2019 by zoltan · 2 Comments
Photo from the movie '3 Dev Adam': Turkish Captain America is trying to save Julie from the Evil Turkish Spiderman.
Text Zoom - Simple example
If you zoom the text in this demo over 113%, you will see this text reposition itself to ensure it doesn't obscure important parts of this photo.

In order to see the above demo in action, resize/zoom just the text on this page over 113%. Do not zoom all the content on this page, just the text. If you have never done this before, jump to the section of this article that shows how to resize text in the browser of your choice. You can also see a clean room example of this demo and compare it with a page that doesn't have the fix applied.

As a user, I find text resizing quite helpful. Ever since I started wearing glasses 10 years ago, the first thing I do when I get a new mobile device is open up the browser preferences and change the default size of text (Note that I am not talking about resizing everything via page zoom. I mean resizing just the text, since I find horizontal scrolling through a zoomed page very annoying). I am sure I am not the only one: there are a lot of tech savvy people are over 35, which is the age when a lot of people normally lose sharpness in their vision. WCAG 2.1 has a guideline to help people with all sorts of vision loss, but given the terse read W3C documentation, I’m sure a lot of you will appreciate this simplified explanation of the “Resize Text” guideline: “you should allow for up to a 200% resize of text without dropping any content or functions”.

As a developer, you must ensure your site can resize text. This means avoiding using pixels in CSS for font-size and using em or rem instead, since Chrome and IE will not resize font-sizes that are defined in pixels. If you want still want to use pixels for font-sizing, but want your favourite CSS pre-processor to convert these values to rems for you, CSS tricks has a great page to help you out.

As a developer, you must also ensure that people can still use your site when the text is resized. Here’s the scenario: you have an existing website that has been audited and accessibility issues have been raised. The auditor has found that when the text in a component on the site has been resized or zoomed 200%, the text is not legible (due to contrast issues, the text is cut off, text is running into other text, or similar reasons). After 10 minutes of looking into the code, you realize that the problem is not easily fixed with CSS or a simple markup change, due to the way the component is styled, and that there is no media query that is directed towards resized text. You will have to spend hours refactoring the code … unless you can find a way to capture an event that fires when you resize the text so you can put special classes on the top of the component when the problems happen. No such native event exists today! If only there was a lightweight JavaScript library that can do this today!

How do you solve this problem? Use my text-zoom-resize JavaScript package, available both at the text-zoom-resize GitHub repository or using npm to import it into your current project

How To Use The text-zoom-resize JavaScript Module

Step 1: Include The Code Into Your Project

You can include the project into your page using a plain ol’ script tag:

<script src="path/to/textZoomEvent.js"></script>

The textZoomEvent object also exports itself as a module, so you can use it with npm and import it into your project easily.

Step 2: Initialize

Before using an event handler to capture the event, you must initialize the library using textZoomEvent.init():

// You must give this value as the argument for the following 
// function when the doc is not zoomed:
// 
// parseFloat(getComputedStyle(document.documentElement).fontSize
//
textZoomEvent.init(16);

As mentioned in the comment, you must give the default, unzoomed value of the document element as an argument in order for this script to work. This is so the script can understand if the page loaded with the text already resized (most, if not all, browsers will persist the text zoom level for a website, even when reloading a page, until the user resets it manually).

Step 3: Find The Page’s Current resizeFactor

You can find the current zoom factor using textZoomEvent.resizeFactor(). It is advised to check this as soon as the script is initialized in order to find if the page’s text is current resized.

Step 4: Capture The textzoom event

Now create a textzoom event handler so you can find out when the user resizes the text:

You can also use the textzoom event to fire when the user zooms the text with their browser:

document.addEventListener('textzoom', textZoomEvent);

Note that you can find the resizeFactor using the event object inside the textzoom event handler:

function textZoomEvent(e) {
  console.log('The current text resize factor is', e.detail.resizeFactor());
}

Step 5: Test

Now to test! Most browsers support text zoom, but many developers (and users) don’t know how to use this feature. Here is what you need to know:

  • Safari:
    1. Desktop (OSX): To increase the font size, press Option-Command-Plus sign (+). To decrease the font size, press Option-Command-Minus sign (-)
    2. Mobile (iOS): When first writing this article, it looked like there was no way to actually resize text in iOS Safari natively. The only way to resize text is at the operating system level (by opening the iOS Settings app and under Accessibility choosing Larger Text and using the slider). By default, however, most web pages don’t respect the size that is set. However, after doing a lot of research for this article, I found that if you put the following CSS into your page, you can get Safari to resize the text according to the system settings:
      body {
          /*
           * This tells Safari to use the OS's base font and
           * the size set in the iOS Accessibility settings.
           */
          font: -apple-system-body;
      
          /*
           * Put whatever font you want to use here.  The font
           * size will still be grabbed by the iOS Accessibility
           * settings.
           */
          font-family: "Times New Roman", serif;
      }
      

      I encourage everyone to put these styles in their base styles. It will make visually impaired iOS users happy. The only caveat here is that the font resize will not happen until after the user refreshes the browser. Thanks to the user “clshortf…@gmail.com” in this Chromium bug report for sharing this info.

  • Chrome:
    1. Desktop:
      • At the top right, click More and then Settings.
      • Under “Appearance,” next to “Font size,” click the Down arrow . Then select the font size you want (you have a choice of very small, small, medium, large and very large). You can have a little bit more granular control by clicking “Customize fonts” and moving the “Font Size” range widget.

      Note that Chrome will not resize text that is sized in px units.

    2. Mobile (Android):
      • Go to Settings, and then Accessibility. You can change the font-size by using the “Text Scaling” slider.

      Please note that Chrome for Android has some serious differences than all other browsers. Text is only resized inside HTML element has more than 217 characters in it, and only if they have a dynamic height. This is not useful as an accessibility feature, since it is not guaranteed to resize all the content on the page. Because of this, text-zoom-resize does not support Chrome for Android.

      A bug has been filed a year and a half ago with Google on this issue, and I have submitted my own comments to it. Hopefully this will be resolved soon.

  • Firefox:
    • Desktop:
      1. On the menu at the top of your browser, click View, then go to Zoom (if you are using Windows or Linux, you may have to press the “Alt” key in order to make this menu visible).
      2. Select Zoom Text Only (This makes the controls only change the size of text; not images).
      3. Click on the hamburger menu in the upper top-right corner of the browser’s chrome.
      4. Click on the plus and minus icons in the “Zoom” option.
    • Mobile (Android):
      1. You first need to set up Firefox to use the operating system text zoom settings. To do this, click on the More menu, denoted by three vertical dots ⋮, and then Settings. Then go to the Accessibility Menu. Make sure the “Use System font size” slider is on. Also make sure the “Always enable zoom” slider is on as well.
      2. Now, that you have set up Firefox right, you can now zoom the font. Launch Android’s “Settings” app and choose “Display”. Then click on “Font size”. Use the slider to change the text zoom font size value. Click OK and then go back to Firefox (Note: You may need to reload the web page in order for the text zoom to take effect).

      (A more visual representation of the second step above can be found at How to Change the Size of Text, Icons, and More in Android at the How To Geek website).

  • Internet Explorer: Go to the menu bar, click “View” and choose the “Text Size” menu item. Note that like Chrome, Internet Explorer will not resize text that is sized in px units.
  • Microsoft Edge:
    • For Edge <= 18 (which is based on the EdgeHTML rendering engine): the only information I found about text zooming is outlined in this article, but I couldn’t get it to work (I think Microsoft may have removed this feature).
    • For Edge > 18 (which is based on the Blink rendering engine): go to Settings, and choose the “Appearance” tab. You can change the “Font size” select box value, or have more fine grained control by clicking “Custom fonts” and moving the “Font size” slider.

(This list was lifted from Zoom & Resizing Text from Yale University’s Usability & Web Accessibility site).

How It Works

To make a long story short, the library inserts a visually hidden <iframe> tag at the beginning of the page (this iframe is also hidden from screen readers using aria-hidden="true"). The width of this iframe is 1em. Because its width is measured in em measurements, when a user resizes text, the iframe’s pixel width will change and will fire a resize event. We then find out what the iframe’s offsetWidth is, divide that from the value we passed in step 1, and we get the resizeFactor. A simple solution that solves a difficult problem.

Acknowledgments

  • The idea of using an <iframe> resize event is not new. I borrowed this idea from this blog post by Hedgerow retrieved from The Wayback Machine
  • The photo used in the demo is from the epic Turkish film 3 Dev Adam, a 1973 Turkish cult superhero film in which Captain America and El Santo have to defeat evil crime lord Spider-Man. None of the characters in the film were used with permission of the copyright holders. If you haven’t seen this film and want a good laugh, you can either see a subtitled copy of 3 Dev Adam in its entirety on YouTube or watch a hilarious review of 3 Dev Adam by the Cinema Snob. The film does contain adult situations, so viewer discretion is advised.


Tags: Uncategorized

2 responses so far ↓
  • 1 Léonore Mangold // Mar 15, 2022 at 11:30 am

    Hello !

    I’m using your text-zoom-resize library on a project and I was wondering why you added @babel/preset-env as a dependency rather than just a devDependency.

    Thanks for your answer.

    Léonore

  • 2 zoltan // Mar 15, 2022 at 2:05 pm

    Hi @Léonore!

    As you probably have guessed, this is a typo and should be a devDependency. This will be fixed in the next release very soon. Thanks for the heads up! :-)

Give Feedback

Don't be shy! Give feedback and join the discussion.

Please Note: If you are asking for help using the information on this page or if you are reporting a bug with the code featured here, please include a URL that shows the problem you are experiencing along with the browser/version number/operating system combination where the issue manifests itself. Without this information, I may not be able to respond.

An orange star denotes a required field.