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.
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:
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.
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:
em
or rem
. Yes, this is a big no-no, but the reality is that websites like this still exist for a number of reasonsThere 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:
font-size
font-size
for each selector based on the initial sizeThis 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.
Here’s a demo in Codepen. 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.
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.
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.
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:
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.
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.
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.
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowThe useReducer React Hook is a good alternative to tools like Redux, Recoil, or MobX.
Node.js v22.5.0 introduced a native SQLite module, which is is similar to what other JavaScript runtimes like Deno and Bun already have.
Understanding and supporting pinch, text, and browser zoom significantly enhances the user experience. Let’s explore a few ways to do so.
Playwright is a popular framework for automating and testing web applications across multiple browsers in JavaScript, Python, Java, and C#. […]