Advanced Text Resizing

For text inside hero images to be considered accessible, they must conform to the following guidelines:

  1. They must not be "hard-coded" into the image in order to conform to WCAG 1.4.5 - Images of Text.
  2. They must adhere to contrast requirements of WCAG 1.4.3 - Contrast (Minimum)
  3. They must accommodate the adjustable text-spacing guidelines of WCAG 1.4.12 - Text Spacing.
  4. They must be resizable via a browser's text zooming feature to conform to WCAG 1.4.4 - Text Resize.

The first item is easily resolved: just use "live" HTML text. Checking contrast is covered in the Text Contrast Strategies section of Enable. The final two requirements, though, can bring up some hard, mind-numbing issues that I have seen over and over again, so I thought I'd show how I've fixed these.

Text Zooming Issues

The styling advice given here is recommended for both new and existing work.
This solution described below is available as an NPM module. (Module installation instructions)

Consider this screenshot of a typical desktop-sized hero image:

Cüneyt Arkın

is a Turkish film actor, director, producer and martial artist. He is widely considered one of the most prominent Turkish actors of all time. Arkın's films have ranged from well-received dramas to mockbusters throughout his career spanning four decades.

Learn more
Portrait shot of Cüneyt Arkın in front of a starry background
Screenshot of a black and white hero image. Turkish actor Cüneyt Arkın is on the right with text describing who he is on the left.
Figure 1. A typical desktop hero image.

It is easy to render this text via HTML. The design even accommodates text spacing requirements: when I apply Steve Faulkner's text spacing bookmarklet, the text fills the hero image.

Screenshot of the above hero image with text-spacing stylesheet applied.  The text on the left of the hero image is still contained by the image container and is still legible
Figure 2. Hero image with text-spacing stylesheet applied.

However, things break down when I try to resize the text. Here is what the hero image looked like when I applied 150% text zoom on the page:

Screenshot of the above hero image with the browser's text-zoom set to 150%.  Note that the text bleeds outside of the hero image, and Cüneyt Arkın's first name is cut off by the text's container element.
Figure 3. Hero image with text zoom set to 150%. Not all the text is legible.

This is typical of a lot of hero images on the web. It's so common, I created a JavaScript library to work around this issue. When the text is resized using the browser's text zooming feature, the layout changes to accommodate the larger text:

Screenshot of the above hero image with the browser's text-zoom set to 150% with JavaScript solution applied.  The layout has been altered so now the text is above the hero image instead of inside of it.
Figure 3. Hero image with text zoom set to 150% and JavaScript solution applied.

How does this work? When the user resizes text on the screen using the browser's text zooming functionality, the JavaScript library adds the text-zoom class on the body tag. Additional styles were created to adjust the layout of the hero.

Code Walkthrough of the Above Example

Below is the HTML of the above example. Use the dropdown to highlight each of the individual steps that makes the example accessible.

☜ Scroll to read full source ☞


Installation Instructions

You can load this JavaScript library into your application in serveral ways:

If you haven't done so already, choosing which you should use is obviously a major architectural decision. Here are a few articles that will help you decide:

Using NPM/Webpack to load ES6 Modules:

  1. Install the enable-a11y NPM project.
  2. Edit your webpack.config.json file to resolve the ~ modifier by adding the following:
    ☜ Scroll to read full source ☞
    module.exports = { ... resolve: { extensions: ['.js', '.jsx', '.scss', '.css', '*.html'], modules: [ path.resolve('./src/js'), path.resolve('./node_modules') ], alias: { '~enable-a11y': path.resolve(__dirname, 'node_modules/enable-a11y') }, ... }, ... }
  3. You can use the module like this:
    ☜ Scroll to read full source ☞
    // import the JS module import textZoomEvent from '~enable-a11y/js/modules/textZoomEvent'; // import the CSS for the module import '~enable-a11y/css/textZoomEvent'; // How to initialize the textZoomEvent library textZoomEvent.init();
  4. Alternatively, if you are using LESS you can include the styles in your project's CSS using:
    ☜ Scroll to read full source ☞
    @import '~enable-a11y/css/textZoomEvent';
    (If you are using it in your CSS, you will have to add the .css suffix)

Using NPM/Webpack to Load Modules Using CommonJS Syntax

  1. Install the enable-a11y NPM project.
  2. You can import the module using require like this:
    ☜ Scroll to read full source ☞
    var textZoomEvent = require('enable-a11y/textZoomEvent').default; ... textZoomEvent.init();
  3. You will have to include the CSS as well in your project's CSS using:
    ☜ Scroll to read full source ☞
    @import '~enable-a11y/css/textZoomEvent';

Using ES6 modules natively.

This is the method that this page you are reading now loads the scripts.

  1. Grab the source by either using NPM, grabbing a ZIP file or cloning the enable source code from github.
  2. If you want to load the module as a native ES6 module, copy js/modules/textZoomEvent.js , and css/textZoomEvent.css from the repo and put them in the appropriate directories in your project (all JS files must be in the same directory).
  3. Load the CSS in the head of you document:
    ☜ Scroll to read full source ☞
    <html> <head> ... <link rel="stylesheet" href="path-to/css/textZoomEvent.css" > ... </head> <body> ... </body> </html>
  4. Load your scripts using the follwing code (NOTE: you must use <script type="module">):
    ☜ Scroll to read full source ☞
    <script type="module"> import textZoomEvent from "path-to/textZoomEvent.js" textZoomEvent.init(); </script>

Using ES4

Just do the same as the ES6 method, except you should get the JavaScript files from the js/modules/es4 directory instead of the js/modules/:
☜ Scroll to read full source ☞
<script src="path-to/es4/textZoomEvent.js"></script>