{"id":292,"date":"2023-11-07T17:00:00","date_gmt":"2023-11-07T18:00:00","guid":{"rendered":"http:\/\/suimy.me\/?p=292"},"modified":"2024-05-01T17:01:43","modified_gmt":"2024-05-01T17:01:43","slug":"addressing-accessibility-concerns-with-using-fluid-type","status":"publish","type":"post","link":"http:\/\/suimy.me\/index.php\/2023\/11\/07\/addressing-accessibility-concerns-with-using-fluid-type\/","title":{"rendered":"Addressing Accessibility Concerns With Using Fluid Type"},"content":{"rendered":"

Addressing Accessibility Concerns With Using Fluid Type<\/title><\/p>\n<article>\n<header>\n<h1>Addressing Accessibility Concerns With Using Fluid Type<\/h1>\n<address>Maxwell Barvian<\/address>\n<p> 2023-11-07T18:00:00+00:00<br \/>\n 2024-05-01T16:05:07+00:00<br \/>\n <\/header>\n<p>You may already be familiar with the CSS <code>clamp()<\/code> function. You may even be using it to fluidly scale a font size based on the browser viewport. Adrian Bece demonstrated the concept in <a href=\"https:\/\/www.smashingmagazine.com\/2022\/01\/modern-fluid-typography-css-clamp\/\">another Smashing Magazine article<\/a> just last year. It\u2019s a clever <a href=\"https:\/\/css-tricks.com\/snippets\/css\/fluid-typography\/\">CSS \u201ctrick\u201d<\/a> that has been floating around for a while.<\/p>\n<p>But if you\u2019ve used the <code>clamp()<\/code>-based fluid type technique yourself, then you may have also run into articles that offer a warning about it. For example, <a href=\"https:\/\/www.smashingmagazine.com\/2022\/01\/modern-fluid-typography-css-clamp\/\">Adrian mentions this<\/a> in his article:<\/p>\n<blockquote><p>\u201cIt\u2019s important to reiterate that using <code>rem<\/code> values doesn\u2019t automagically make fluid typography accessible for all users; it only allows the font sizes to respond to user font preferences. Using the CSS <code>clamp<\/code> function in combination with the viewport units to achieve fluid sizing introduces <strong>another set of drawbacks<\/strong> that we need to consider.\u201d<\/p><\/blockquote>\n<p>Here\u2019s Una Kravets <a href=\"https:\/\/web.dev\/min-max-clamp\/#fluid-typography\">with a few words<\/a> about it on web.dev:<\/p>\n<blockquote><p>\u201cLimiting how large text can get with <code>max()<\/code> or <code>clamp()<\/code> can cause a WCAG failure under <a href=\"https:\/\/www.w3.org\/WAI\/WCAG21\/quickref\/?showtechniques=144#resize-text\">1.4.4 Resize text (AA)<\/a>, because a user may be unable to scale the text to 200% of its original size. Be certain to <a href=\"https:\/\/adrianroselli.com\/2019\/12\/responsive-type-and-zoom.html\">test the results with zoom<\/a>.\u201d<\/p><\/blockquote>\n<p>Trys Mudford also has something to say about it <a href=\"https:\/\/utopia.fyi\/blog\/clamp\/\">in the Utopia blog<\/a>:<\/p>\n<blockquote><p>\u201c<a href=\"https:\/\/adrianroselli.com\/2019\/12\/responsive-type-and-zoom.html\">Adrian Roselli<\/a> 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, <strong>ensure you test thoroughly<\/strong> before using it in production.\u201d<\/p><\/blockquote>\n<p>Mudford cites Adrian Roselli, who appears to be <a href=\"https:\/\/adrianroselli.com\/2019\/12\/responsive-type-and-zoom.html\">the core source<\/a> of the other warnings:<\/p>\n<blockquote><p>\u201cWhen you use <code>vw<\/code> units or limit how large text can get with <code>clamp()<\/code>, there is a chance a user may be unable to scale the text to 200% of its original size. If that happens, it is WCAG failure under <a href=\"https:\/\/www.w3.org\/WAI\/WCAG21\/quickref\/?showtechniques=144#resize-text\">1.4.4 Resize text (AA)<\/a> so be certain to test the results with zoom.\u201d<\/p><\/blockquote>\n<p>So, what\u2019s 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 guidelines say to understand the issue, then explore how we might be able to use <code>clamp()<\/code> in a way that adheres to WCAG Success Criterion (SC) 1.4.4.<\/p>\n<div data-audience=\"non-subscriber\" data-remove=\"true\" class=\"feature-panel-container\">\n<aside class=\"feature-panel\">\n<div class=\"feature-panel-left-col\">\n<div class=\"feature-panel-description\">\n<p>Meet <strong><a data-instant href=\"\/printed-books\/typescript-in-50-lessons\/\">\u201cTypeScript in 50 Lessons\u201d<\/a><\/strong>, our shiny new guide to TypeScript. With detailed <strong>code walkthroughs<\/strong>, hands-on examples and common gotchas. For developers who know enough <strong>JavaScript<\/strong> to be dangerous.<\/p>\n<p><a data-instant href=\"\/printed-books\/typescript-in-50-lessons\/\" class=\"btn btn--green btn--large\">Jump to table of contents\u00a0\u21ac<\/a><\/div>\n<\/div>\n<div class=\"feature-panel-right-col\"><a data-instant href=\"\/printed-books\/typescript-in-50-lessons\/\" class=\"feature-panel-image-link\"><\/p>\n<div class=\"feature-panel-image\">\n<img loading=\"lazy\" class=\"feature-panel-image-img lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Feature Panel\" width=\"481\" height=\"698\" data-src=\"https:\/\/archive.smashing.media\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/c2f2c6d6-4e85-449a-99f5-58bd053bc846\/typescript-shop-cover-opt.png\"><\/p>\n<\/div>\n<p><\/a>\n<\/div>\n<\/aside>\n<\/div>\n<h2 id=\"wcag-success-criterion-1-4-4\">WCAG Success Criterion 1.4.4<\/h2>\n<p>Let\u2019s first review what <a href=\"https:\/\/www.w3.org\/WAI\/WCAG21\/Understanding\/resize-text.html\">WCAG Success Criterion 1.4.4<\/a> says about resizing text:<\/p>\n<blockquote><p>\u201cExcept for <a href=\"https:\/\/www.w3.org\/WAI\/WCAG21\/Understanding\/resize-text.html#dfn-captions\">captions<\/a> and <a href=\"https:\/\/www.w3.org\/WAI\/WCAG21\/Understanding\/resize-text.html#dfn-image-of-text\">images of text<\/a>, <a href=\"https:\/\/www.w3.org\/WAI\/WCAG21\/Understanding\/resize-text.html#dfn-text\">text<\/a> can be resized without <a href=\"https:\/\/www.w3.org\/WAI\/WCAG21\/Understanding\/resize-text.html#dfn-assistive-technology\">assistive technology<\/a> up to 200 percent without loss of content or functionality.\u201d<\/p><\/blockquote>\n<p>Normally, if we\u2019re setting CSS <code>font-size<\/code> to a non-fluid value, e.g., <code>font-size: 2rem<\/code>, we never have to worry about resizing behavior. All modern browsers can zoom up to 500% without additional assistive technology.<\/p>\n<p>So, what\u2019s the deal with sizing text with viewport units like this:<\/p>\n<pre><code class=\"language-css\">h1 {\n font-size: 5vw;\n}\n<\/code><\/pre>\n<p>Here\u2019s a simple example demonstrating the problem. I suggest viewing it in either Chrome or Firefox because zooming in Safari can behave differently.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"MWLaqRX\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [vw-based font-size scaling [forked]](https:\/\/codepen.io\/smashingmag\/pen\/MWLaqRX) by <a href=\"https:\/\/codepen.io\/mbarvian\">Maxwell Barvian<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/MWLaqRX\">vw-based font-size scaling [forked]<\/a> by <a href=\"https:\/\/codepen.io\/mbarvian\">Maxwell Barvian<\/a>.<\/figcaption><\/figure>\n<p>If you click the zoom buttons in the demo\u2019s bottom toolbar, you\u2019ll notice that although the page zoom level changes, the text doesn\u2019t get smaller. Nothing really changes, in fact.<\/p>\n<p>The issue is that, unlike <code>rem<\/code> and <code>px<\/code> values, <strong>browsers do not scale viewport-based units when zooming the page<\/strong>. This makes sense when thinking about it. The viewport itself doesn\u2019t change when the user zooms in or out of a page. Where we see <code>font-size: 1rem<\/code> display like <code>font-size: 0.5rem<\/code> at a 50% zoom, <code>font-size: 5vw<\/code> stays the same size at all zoom levels.<\/p>\n<p>Herein lies the accessibility issue. Font sizes based on <code>vw<\/code> \u2014 or any <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Learn\/CSS\/Building_blocks\/Values_and_units#relative_length_units\">other viewport-based units<\/a> for that matter \u2014 could potentially fail to scale to two times their original size the way WCAG SC 1.4.4 wants them to. That\u2019s true <strong>even at 500%<\/strong>, 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.<\/p>\n<h2 id=\"back-to-clamp\">Back To <code>clamp()<\/code><\/h2>\n<p>Where does <code>clamp()<\/code> fit into all of this? After all, many of us don\u2019t rely <em>solely<\/em> on <code>vw<\/code> units to size type; we use <a href=\"https:\/\/royalfig.github.io\/fluid-typography-calculator\/\">any<\/a> of the <a href=\"https:\/\/clamp.font-size.app\/?config=eyJyb290IjoiMTYiLCJtaW5XaWR0aCI6IjUwMHB4IiwibWF4V2lkdGgiOiI5MDBweCIsIm1pbkZvbnRTaXplIjoiMXJlbSIsIm1heEZvbnRTaXplIjoiNDhweCJ9\">many tools<\/a> that <a href=\"https:\/\/fluidtypography.com\/\">are capable<\/a> of <a href=\"https:\/\/utopia.fyi\/type\/calculator\/\">generating<\/a> a clamped function with a <code>rem<\/code> or <code>px<\/code>-based component. Here\u2019s one example that scales text between <code>16px<\/code> and <code>48px<\/code> when the viewport is between <code>320px<\/code> and <code>1280px<\/code>. I\u2019m using <code>px<\/code> values for simplicity\u2019s sake, but <a href=\"https:\/\/ntgard.medium.com\/accessible-fluid-typography-875c4aac8056\">it\u2019s better to use <code>rem<\/code> in terms of accessibility<\/a>.<\/p>\n<pre><code class=\"language-css\">h1 {\n font-size: clamp(16px, 5.33px + 3.33vw, 48px)\n}\n<\/code><\/pre>\n<p>Try zooming into the next demo to see how the text behaves with this approach.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"poGjOXL\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [clamp()ed font-size [forked]](https:\/\/codepen.io\/smashingmag\/pen\/poGjOXL) by <a href=\"https:\/\/codepen.io\/mbarvian\">Maxwell Barvian<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/poGjOXL\">clamp()ed font-size [forked]<\/a> by <a href=\"https:\/\/codepen.io\/mbarvian\">Maxwell Barvian<\/a>.<\/figcaption><\/figure>\n<p>Is this font size accessible? In other words, if we zoom the page to the browser\u2019s 500% maximum, does the content display at least double its original size? If we <a href=\"https:\/\/codepen.io\/mbarvian\/full\/bGQPZop\">open the demo in full-page view<\/a> and resize the browser width to, say, <code>1500px<\/code>, notice what happens when we zoom in to 500%.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/1-zoom-level-100-and-500.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"210\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Zoom level: on the left, 100% (default), and on the right, 500% (maximum).\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/1-zoom-level-100-and-500.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Zoom level: on the left, 100% (default), and on the right, 500% (maximum). (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/1-zoom-level-100-and-500.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>The text only scales up to <code>55px<\/code>, or 1.67 times its original size, even though we zoomed the entire page to five times its original size. And because WCAG SC 1.4.4 requires that text can scale to at least two times its original size, this simple example would fail an accessibility audit, at least in most browsers at certain viewport widths.<\/p>\n<p>Surely this can\u2019t be a problem for <em>all<\/em> clamped font sizes with <code>vw<\/code> units, right? What about <a href=\"https:\/\/codepen.io\/mbarvian\/full\/jOQjRNa\">one that only increases from <code>16px<\/code> to <code>18px<\/code><\/a>:<\/p>\n<pre><code class=\"language-css\">h1 {\n font-size: clamp(16px, 15.33px + 0.208vw, 18px);\n}\n<\/code><\/pre>\n<p>The <code>vw<\/code> part of that inner <code>calc()<\/code> function (<code>clamp()<\/code> supports <code>calc()<\/code> without explicitly declaring it) is so small that it couldn\u2019t possibly cause the same accessibility failure, right?<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/2-zoom-level-default-maximum.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"206\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Zoom level: on the left, 100% (default), and on the right, 500% (maximum).\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/2-zoom-level-default-maximum.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Zoom level: on the left, 100% (default), and on the right, 500% (maximum). (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/2-zoom-level-default-maximum.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Sure enough, even though it doesn\u2019t get to quite 500% of its original size when the page is zoomed to 500%, the size of the text certainly passes the 200% zoom specified in WCAG SC 1.4.4.<\/p>\n<p>So, clamped viewport-based font sizes fail WCAG SC 1.4.4 in some cases but not in others. The only advice I\u2019ve seen for determining which situations pass or fail is to check each of them manually, as Adrian Roselli originally suggested. But that\u2019s time-consuming and imprecise because the functions don\u2019t scale intuitively.<\/p>\n<p>There must be some relationship between our inputs \u2014 i.e., the minimum font size, maximum font size, minimum breakpoint, and maximum breakpoint \u2014 that can help us determine when they pose accessibility issues.<\/p>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"thinking-mathematically\">Thinking Mathematically<\/h2>\n<p>If we think about this problem mathematically, we really want to ensure that <code>z\u2085(v) \u2265 2z\u2081(v)<\/code>. Let\u2019s break that down.<\/p>\n<p><code>z\u2081(v)<\/code> and <code>z\u2085(v)<\/code> are functions that take the viewport width, <code>v<\/code>, as their input and return a font size at a 100% zoom level and a 500% zoom level, respectively. In other words, what we want to know is at what range of viewport widths will <code>z\u2085(v)<\/code> be <em>less<\/em> than <code>2\u00d7z\u2081(v)<\/code>, which represents the minimum size outlined in WCAG SC 1.4.4?<\/p>\n<p>Using the first <code>clamp()<\/code> example we looked at that failed WCAG SC 1.4.4, we know that the <code>z\u2081<\/code> function is the <code>clamp()<\/code> expression:<\/p>\n<pre><code class=\"language-css\">z\u2081(v) = clamp(16, 5.33 + 0.0333v, 48)\n<\/code><\/pre>\n<p><strong>Notice<\/strong>: <em>The <code>vw<\/code> units are divided by <code>100<\/code> to translate from CSS where <code>100vw<\/code> equals the viewport width in pixels.<\/em><\/p>\n<p>As for the <code>z\u2085<\/code> function, it\u2019s tempting to think that <code>z\u2085 = 5z\u2081<\/code>. But remember what we learned from that first demo: <strong>viewport-based units don\u2019t scale up with the browser\u2019s zoom level.<\/strong> This means <code>z\u2085<\/code> is more correctly expressed like this:<\/p>\n<pre><code class=\"language-css\">z\u2085(v) = clamp(16*5, 5.33*5 + 0.0333v, 48*5)\n<\/code><\/pre>\n<p><strong>Notice<\/strong>: <em>This scales everything up by <code>5<\/code> (or <code>500%<\/code>), except for <code>v<\/code>. This simulates how the browser scales the page when zooming.<\/em><\/p>\n<p>Let\u2019s represent the <code>clamp()<\/code> function mathematically. We can convert it to a <a href=\"https:\/\/math.stackexchange.com\/a\/2372161\">piecewise function<\/a>, meaning <code>z\u2081(v)<\/code> and <code>z\u2085(v)<\/code> would ultimately look like the following figure:<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/3-zoom-z1v.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"150\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"100% zoom (z\u2081(v))\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/3-zoom-z1v.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n 100% zoom (<code>z\u2081(v)<\/code>). (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/3-zoom-z1v.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/4-zoom-z5v.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"112\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"500% zoom (z\u2085(v))\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/4-zoom-z5v.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n 500% zoom (<code>z\u2085(v)<\/code>). (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/4-zoom-z5v.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>We can graph these functions to help visualize the problem. Here\u2019s the base function, <code>z\u2081(v)<\/code>, with the viewport width, <code>v<\/code>, on the x-axis:<\/p>\n<figure class=\"\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/5-graphed-geogebra.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"553\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Graph chart showing the plotted points scaling up at the 320-pixel point.\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/5-graphed-geogebra.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Graphed with <a href=\"https:\/\/www.geogebra.org\/?lang=en\">GeoGebra<\/a>. (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/5-graphed-geogebra.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>This looks about right. The font size stays at <code>16px<\/code> until the viewport is <code>320px<\/code> wide, and it increases linearly from there before it hits <code>48px<\/code> at a viewport width of <code>1280px<\/code>. So far, so good.<\/p>\n<p>Here\u2019s a more interesting graph comparing <code>2z\u2081(v)<\/code> and <code>z\u2085(v)<\/code>:<\/p>\n<figure class=\"\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/6-graph-two-functions.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"554\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Showing both functions on the same graph\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/6-graph-two-functions.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n <code>2z\u2081(v)<\/code> (in teal) and <code>z\u2085(v)<\/code> (in green). (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/6-graph-two-functions.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Can you spot the accessibility failure on this graph? When <code>z\u2085(v)<\/code> (in green) is less than <code>2z\u2081(v)<\/code> (in teal), the viewport-based font size fails WCAG SC 1.4.4.<\/p>\n<p>Let\u2019s zoom into the bottom-left region for a closer look:<\/p>\n<figure class=\"\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/7-graph-two-functions-zoomed.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"619\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Both functions on the same graph zoomed for a closer look\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/7-graph-two-functions-zoomed.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/7-graph-two-functions-zoomed.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>This figure indicates that failure occurs when the browser width is approximately between <code>1050px<\/code> and <code>2100px<\/code>. You can verify this by <a href=\"https:\/\/codepen.io\/mbarvian\/full\/bGQPZop\">opening the original demo again<\/a> and zooming into it at different viewport widths. When the viewport is less than <code>1050px<\/code> or greater than <code>2100px<\/code>, the text should scale up to at least two times its original size at a 500% zoom. But when it\u2019s in between <code>1050px<\/code> and <code>2100px<\/code>, it doesn\u2019t.<\/p>\n<p><strong>Hint<\/strong>: <em>We have to manually measure the text \u2014 e.g., take a screenshot \u2014 because browsers don\u2019t show zoomed values in DevTools.<\/em><\/p>\n<h2 id=\"general-solutions\">General Solutions<\/h2>\n<p>For simplicity\u2019s sake, we\u2019ve only focused on one <code>clamp()<\/code> expression so far. Can we generalize these findings somehow to ensure any clamped expression passes WCAG SC 1.4.4?<\/p>\n<p>Let\u2019s take a closer look at what\u2019s happening in the failure above. Notice that the problem is caused because <code>2z\u2081(v)<\/code> \u2014 the SC 1.4.4 requirement \u2014 reaches its peak before <code>z\u2085(v)<\/code> starts increasing.<\/p>\n<p>When would that be the case? <em>Everything<\/em> in <code>2z\u2081(v)<\/code> is scaled by 200%, including the slope of the line (<code>v<\/code>). The function reaches its peak value at the same viewport width where <code>z\u2081(v)<\/code> reaches its peak value (the maximum <code>1280px<\/code> breakpoint). That peak value is two times the maximum font size we want which, in this case, is <code>2*48<\/code>, or <code>96px<\/code>.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/8-function-peak-value.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"288\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"A graph showing a peak value of the function\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/8-function-peak-value.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/8-function-peak-value.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>However, the slope of <code>z\u2085(v)<\/code> is the same as <code>z\u2081(v)<\/code>. In other words, the function doesn\u2019t start increasing from its lowest clamped point \u2014 five times the minimum font size we want \u2014 until the viewport width is five times the minimum breakpoint. In this case, that is <code>5*320<\/code>, or <code>1600px<\/code>.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/9-function-lowest-clamped-point.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"288\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"A graph showing function\u2019s lowest clamped point\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/9-function-lowest-clamped-point.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/9-function-lowest-clamped-point.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Thinking about this generally, we can say that if <code>2z\u2081(v)<\/code> peaks before <code>z\u2085(v)<\/code> starts increasing, or if the maximum breakpoint is less than five times the minimum breakpoint, then the peak value of <code>2z\u2081(v)<\/code> must be less than or equal to the peak value of <code>z\u2085(v)<\/code>, or two times the maximum value that is less than or equal to five times the minimum value.<\/p>\n<p>Or simpler still: <strong>The maximum value must be less than or equal to 2.5 times the minimum value<\/strong>.<\/p>\n<p>What about when the maximum breakpoint is more than five times the minimum breakpoint? Let\u2019s see what our graph looks like when we change the maximum breakpoint from <code>1280px<\/code> to <code>1664px<\/code> and the maximum font size to <code>40px<\/code>:<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/10-graph-increased-max-breakpoint.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"423\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"A graph showing the increased maximum breakpoint and the maximum font size\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/10-graph-increased-max-breakpoint.png\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/addressing-accessibility-concerns-fluid-type\/10-graph-increased-max-breakpoint.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Technically, we could get away with a slightly higher maximum font size. To figure out just <em>how<\/em> much higher, we\u2019d have to solve for <code>z\u2085(v) \u2265 2z\u2081(v)<\/code> at the point when <code>2z\u2081(v)<\/code> reaches its peak, which is when <code>v<\/code> equals the maximum breakpoint. (Hat tip to my brother, <a href=\"https:\/\/www.linkedin.com\/in\/zach-barvian\/\">Zach Barvian<\/a>, whose excellent math skills helped me with this.)<\/p>\n<p>To save you the math, you can play around with <a href=\"https:\/\/fluid.style\/type\">this calculator<\/a> to see which combinations pass WCAG SC 1.4.4.<\/p>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>Summing up what we\u2019ve covered:<\/p>\n<ul>\n<li>If the maximum font size is <em>less<\/em> than or equal to 2.5 times the minimum font size, then the text will always pass WCAG SC 1.4.4, at least on all modern browsers.<\/li>\n<li>If the maximum breakpoint is <em>greater<\/em> than five times the minimum breakpoint, it is possible to get away with a <em>slightly<\/em> higher maximum font size. That said, the increase is negligible, and that is a large breakpoint range to use in practice.<\/li>\n<\/ul>\n<p>Importantly, that first rule is true for non-fluid responsive type as well. If you open <a href=\"https:\/\/codepen.io\/mbarvian\/full\/eYQwaxB\">this pen<\/a>, for example, notice that it uses regular media queries to increase the <code>h1<\/code> element\u2019s size from an initial value of <code>1rem<\/code> to <code>3rem<\/code> (which violates our first rule), with an in-between stop for <code>2rem<\/code>.<\/p>\n<p>If you zoom in at 500% with a browser width of approximately <code>1000px<\/code>, you will see that the text doesn\u2019t reach 200% of its initial size. This makes sense because if you were to describe <code>2z\u2081(v)<\/code> and <code>z\u2085(v)<\/code> mathematically, they would be even simpler piecewise functions with the same maximum and minimum limitations. <strong>This guideline would hold for any function describing a font size with a known minimum and maximum<\/strong>.<\/p>\n<p>In the future, of course, we <a href=\"https:\/\/github.com\/w3c\/csswg-drafts\/issues\/6869\">may get more tools from browsers<\/a> 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.<\/p>\n<div class=\"signature\">\n <img src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Smashing Editorial\" width=\"35\" height=\"46\" loading=\"lazy\" class=\"lazyload\" data-src=\"https:\/\/www.smashingmagazine.com\/images\/logo\/logo--red.png\"><br \/>\n <span>(gg, yk)<\/span>\n<\/div>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>Addressing Accessibility Concerns With Using Fluid Type Addressing Accessibility Concerns With Using Fluid Type Maxwell Barvian 2023-11-07T18:00:00+00:00 2024-05-01T16:05:07+00:00 You may […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[12],"tags":[],"_links":{"self":[{"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/posts\/292"}],"collection":[{"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/comments?post=292"}],"version-history":[{"count":1,"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/posts\/292\/revisions"}],"predecessor-version":[{"id":293,"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/posts\/292\/revisions\/293"}],"wp:attachment":[{"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/media?parent=292"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/categories?post=292"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/suimy.me\/index.php\/wp-json\/wp\/v2\/tags?post=292"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}