Addressing Accessibility Concerns With Using Fluid Type — Smashing Magazine

By admin
Addressing Accessibility Concerns With Using Fluid Type


11 min
TIME

read

Share on Twitter, LinkedIn

The CSS clamp() function is often paired with viewport units for “fluid” font sizing that scales the text up and down at different viewport sizes. As common as this technique is, several voices warn that it opens up situations where text can fail WCAG Success Criterion

1.4.4
CARDINAL

, which specifies that text should scale up to

at least 200%
PERCENT

when the user’s browser reaches its

500%
PERCENT

maximum zoom level.

Max Barvian
PERSON

takes a deep look at the issue and offers ideas to help address it. The

CSSfunction
PRODUCT

is often paired with viewport units for “fluid” font sizing that scales the text up and down at different viewport sizes. As common as this technique is, several voices warn that it opens up situations where text can fail WCAG Success Criterion

1.4.4
CARDINAL

, which specifies that text should scale up to

at least 200%
PERCENT

when the user’s browser reaches its

500%
PERCENT

maximum zoom level.

Max Barvian
PERSON

takes a deep look at the issue and offers ideas to help address it.

You may already be familiar with the

CSS
ORG

clamp() function. You may even be using it to fluidly scale a font size based on the browser viewport.

Adrian Bece
PERSON

demonstrated the concept in another

Smashing Magazine
ORG

article

just last year
DATE

. It’s a clever CSS “trick” that has been floating around for a while.

But if you’ve used the clamp() -based fluid type technique yourself, then you may have also run into articles that offer a warning about it. For example,

Adrian
PERSON

mentions this in his article:

“It’s important to reiterate that using rem values doesn’t automagically make fluid typography accessible for all users; it only allows the font sizes to respond to user font preferences. Using the

CSS
ORG

clamp function in combination with the viewport units to achieve fluid sizing introduces another set of drawbacks that we need to consider.”

Here’s

Una Kravets
PERSON

with a few words about it on web.dev:

“Limiting how large text can get with

max
PERSON

() or clamp() can cause a WCAG failure under

1.4.4
CARDINAL

Resize text (AA), because a user may be unable to scale the text to

200%
PERCENT

of its original size. Be certain to test the results with zoom.”


Trys Mudford
PERSON

also has something to say about it in the Utopia blog:



Adrian Roselli
PERSON

quite rightly warns that clamp can have a knock-on effect on the maximum font-size when the user explicitly sets a browser text zoom preference. As with any feature affecting typography, ensure you test thoroughly before using it in production.”


Mudford
PERSON

cites

Adrian Roselli
PERSON

, who appears to be the core source of the other warnings:

“When you use vw units or limit how large text can get with clamp() , there is a chance a user may be unable to scale the text to

200%
PERCENT

of its original size. If that happens, it is

WCAG
ORG

failure under

1.4.4
CARDINAL

Resize text (AA) so be certain to test the results with zoom.”

So, what’s going on here? And how can we address any accessibility issues so we can keep fluidly scaling our text? That is exactly what I want to discuss in this article. Together, we will review what the

WCAG
ORG

guidelines say to understand the issue, then explore how we might be able to use clamp() in a way that adheres to

WCAG Success Criterion
ORG

(

SC
ORG

)

1.4.4
CARDINAL

.

WCAG Success Criterion

1.4.4
CARDINAL

Let’s

first
ORDINAL

review what

WCAG Success Criterion
ORG

1.4.4 says about resizing text:

“Except for captions and images of text, text can be resized without assistive technology

up to 200 percent
PERCENT

without loss of content or functionality.”

Normally, if we’re setting CSS font-size to a non-fluid value, e.g., font-size:

2rem
CARDINAL

, we never have to worry about resizing behavior. All modern browsers can zoom

up to 500%
PERCENT

without additional assistive technology.

So, what’s the deal with sizing text with viewport units like this:

h1 { font-size:

5vw
CARDINAL

; }

Here’s a simple example demonstrating the problem. I suggest viewing it in either

Chrome
ORG

or Firefox because zooming in

Safari
ORG

can behave differently.

If you click the zoom buttons in the demo’s bottom toolbar, you’ll notice that although the page zoom level changes, the text doesn’t get smaller. Nothing really changes, in fact.

The issue is that, unlike rem and px values, browsers do not scale viewport-based units when zooming the page. This makes sense when thinking about it. The viewport itself doesn’t change when the user zooms in or out of a page. Where we see font-size:

1rem
CARDINAL

display like font-size:

0.5rem
CARDINAL

at a

50%
PERCENT

zoom, font-size:

5vw
CARDINAL

stays the same size at all zoom levels.

Herein lies the accessibility issue. Font sizes based on vw — or any other viewport-based units for that matter — could potentially fail to scale to

two
CARDINAL

times their original size the way

WCAG SC
ORG

1.4.4 wants them to. That’s true even at

500%
PERCENT

, which is the maximum zoom level for most browsers. If a user needs to zoom in at that scale, then we need to respect that for legibility.

Back To clamp()

Where does clamp() fit into all of this? After all, many of us don’t rely solely on vw units to size type; we use any of the many tools that are capable of generating a clamped function with a rem or px -based component. Here’s

one
CARDINAL

example that scales text between 16px and 48px when the viewport is between

320px
ORG

and 1280px . I’m using px values for simplicity’s sake, but it’s better to use rem in terms of accessibility.

h1 { font-size: clamp(16px,

5.33px
ORG

+ 3.33vw, 48px) }

Try zooming into the next demo to see how the text behaves with this approach.

Is this font size accessible? In other words, if we zoom the page to the browser’s

500%
PERCENT

maximum, does the content display at least double its original size? If we open the demo in full-page view and resize the browser width to, say, 1500px , notice what happens when we zoom in to

500%
PERCENT

.

Zoom level: on the left,

100%
PERCENT

(default), and on the right,

500%
PERCENT

(maximum). (Large preview)

The text only scales up to 55px , or

1.67
CARDINAL

times its original size, even though we zoomed the entire page to

five
CARDINAL

times its original size. And because

WCAG SC
ORG

1.4.4 requires that text can scale to

at least two
CARDINAL

times its original size, this simple example would fail an accessibility audit, at least in most browsers at certain viewport widths.

Surely this can’t be a problem for all clamped font sizes with vw units, right? What about one that only increases from 16px to 18px :

h1 { font-size: clamp(16px,

15.33px
CARDINAL

+

0.208vw
CARDINAL

, 18px); }

The vw part of that inner calc() function ( clamp() supports calc() without explicitly declaring it) is so small that it couldn’t possibly cause the same accessibility failure, right?

Zoom level: on the left,

100%
PERCENT

(default), and on the right,

500%
PERCENT

(maximum). (Large preview)

Sure enough, even though it doesn’t get to quite

500%
PERCENT

of its original size when the page is zoomed to

500%
PERCENT

, the size of the text certainly passes the

200%
PERCENT

zoom specified in

WCAG SC
ORG

1.4.4.

So, clamped viewport-based font sizes fail

WCAG
ORG

SC 1.4.4 in some cases but not in others. The only advice I’ve seen for determining which situations pass or fail is to check each of them manually, as

Adrian Roselli
PERSON

originally suggested. But that’s time-consuming and imprecise because the functions don’t scale intuitively.

There must be some relationship between our inputs — i.e., the minimum font size, maximum font size, minimum breakpoint, and maximum breakpoint — that can help us determine when they pose accessibility issues.

Thinking Mathematically

If we think about this problem mathematically, we really want to ensure that z₅(v) ≥

2z₁(v
CARDINAL

) . Let’s break that down.


z₁(v
PRODUCT

) and z₅(v) are functions that take the viewport width, v , as their input and return a font size at a

100%
PERCENT

zoom level and a

500%
PERCENT

zoom level, respectively. In other words, what we want to know is at what range of viewport widths will z₅(v) be

less than
CARDINAL

2×z₁(v) , which represents the minimum size outlined in

WCAG SC
ORG

1.4.4?

Using the

first
ORDINAL

clamp() example we looked at that failed

WCAG SC
ORG


1.4.4
DATE

, we know that the

z₁
ORG

function is the clamp() expression:


z₁(v
PRODUCT

) = clamp(16,

5.33
CARDINAL

+

0.0333v
CARDINAL

,

48
DATE

)

Notice: The vw units are divided by

100
CARDINAL

to translate from CSS where

100vw
LOC

equals the viewport width in pixels.

As for the z₅ function, it’s tempting to think that z₅ =

5z₁
CARDINAL

. But remember what we learned from that

first
ORDINAL

demo: viewport-based units don’t scale up with the browser’s zoom level. This means z₅ is more correctly expressed like this:

z₅(v) = clamp(16*

5
CARDINAL

,

5.33
CARDINAL

*

5
CARDINAL

+

0.0333v
ORG

,

48
CARDINAL

*

5
CARDINAL

)

Notice: This scales everything up by

5
CARDINAL

(or

500%
PERCENT

), except for v . This simulates how the browser scales the page when zooming.

Let’s represent the clamp() function mathematically. We can convert it to a piecewise function, meaning

z₁(v
LAW

) and z₅(v) would ultimately look like the following figure:

We can graph these functions to help visualize the problem. Here’s the base function,

z₁(v
LAW

) , with the viewport width, v , on the x-axis:

This looks about right. The font size stays at 16px until the viewport is

320px
NORP

wide, and it increases linearly from there before it hits 48px at a viewport width of 1280px . So far, so good.

Here’s a more interesting graph comparing

2z₁(v
CARDINAL

) and z₅(v) :

Can you spot the accessibility failure on this graph? When z₅(v) (in green) is

less than 2z₁(v
CARDINAL

) (in

teal
PERSON

), the viewport-based font size fails

WCAG
ORG

SC 1.4.4.

Let’s zoom into the bottom-left region for a closer look:

This figure indicates that failure occurs when the browser width is approximately between 1050px and 2100px . You can verify this by opening the original demo again and zooming into it at different viewport widths. When the viewport is less than 1050px or greater than 2100px , the text should scale up to

at least two
CARDINAL

times its original size at a

500%
PERCENT

zoom. But when it’s in between 1050px and 2100px , it doesn’t.

Hint: We have to manually measure the text — e.g., take a screenshot — because browsers don’t show zoomed values in

DevTools
ORG

.

General Solutions

For simplicity’s sake, we’ve only focused on

one
CARDINAL

clamp() expression so far. Can we generalize these findings somehow to ensure any clamped expression passes

WCAG
ORG

SC 1.4.4?

Let’s take a closer look at what’s happening in the failure above. Notice that the problem is caused because

2z₁(v
CARDINAL

) — the SC

1.4.4
CARDINAL

requirement — reaches its peak before z₅(v) starts increasing.

When would that be the case? Everything in

2z₁(v
CARDINAL

) is scaled by

200%
PERCENT

, including the slope of the line ( v ). The function reaches its peak value at the same viewport width where

z₁(v
LAW

) reaches its peak value (the maximum 1280px breakpoint). That peak value is

two
CARDINAL

times the maximum font size we want which, in this case, is

2
CARDINAL

*

48
DATE

, or 96px .

However, the slope of z₅(v) is the same as

z₁(v
PRODUCT

) . In other words, the function doesn’t start increasing from its lowest clamped point —

five
CARDINAL

times the minimum font size we want — until the viewport width is

five
CARDINAL

times the minimum breakpoint. In this case, that is

5
CARDINAL

*

320
CARDINAL

, or 1600px .

Thinking about this generally, we can say that if

2z₁(v
CARDINAL

) peaks before z₅(v) starts increasing, or if the maximum breakpoint is

less than five
CARDINAL

times the minimum breakpoint, then the peak value of

2z₁(v
CARDINAL

) must be less than or equal to the peak value of z₅(v) , or

two
CARDINAL

times the maximum value that is less than or equal to

five
CARDINAL

times the minimum value.

Or simpler still: The maximum value must be less than or equal to

2.5
CARDINAL

times the minimum value.

What about when the maximum breakpoint is

more than five
CARDINAL

times the minimum breakpoint? Let’s see what our graph looks like when we change the maximum breakpoint from 1280px to

1664px
ORG

and the maximum font size to 40px :

Technically, we could get away with a slightly higher maximum font size. To figure out just how much higher, we’d have to solve for z₅(v) ≥

2z₁(v
CARDINAL

) at the point when

2z₁(v
CARDINAL

) reaches its peak, which is when v equals the maximum breakpoint. (Hat tip to my brother,

Zach Barvian
PERSON

, whose excellent math skills helped me with this.)

To save you the math, you can play around with this calculator to see which combinations pass

WCAG
ORG

SC 1.4.4.

Conclusion

Summing up what we’ve covered:

If the maximum font size is less than or equal to

2.5
CARDINAL

times the minimum font size, then the text will always pass

WCAG
ORG

SC

1.4.4
DATE

, at least on all modern browsers.

If the maximum breakpoint is

greater than five
CARDINAL

times the minimum breakpoint, it is possible to get away with a slightly higher maximum font size. That said, the increase is negligible, and that is a large breakpoint range to use in practice.

Importantly, that

first
ORDINAL

rule is true for non-fluid responsive type as well. If you open this pen, for example, notice that it uses regular media queries to increase the h1 element’s size from an initial value of

1rem
CARDINAL

to 3rem (which violates our

first
ORDINAL

rule), with an in-between stop for

2rem
CARDINAL

.

If you zoom in at

500%
PERCENT

with a browser width of

approximately 1000px
CARDINAL

, you will see that the text doesn’t reach

200%
PERCENT

of its initial size. This makes sense because if you were to describe

2z₁(v
CARDINAL

) and z₅(v) mathematically, they would be even simpler piecewise functions with the same maximum and minimum limitations. This guideline would hold for any function describing a font size with a known minimum and maximum.

In the future, of course, we may get more tools from browsers to address these issues and accommodate even larger maximum font sizes. In the meantime, though, I hope you find this article helpful when building responsive frontends.

(gg, yk)