Commit 6147ea9e authored by Laura Kalbag's avatar Laura Kalbag
Browse files

Add blog post on Dynamic Type. Has not yet been added to blog list page. Dates need updating too.

parent fb0b2add
......@@ -65,11 +65,27 @@
<p>Dynamic Type is pretty cool. You can go to Settings > General > Accessibility > Larger Text on your phone, and either grow or shrink your preferred reading size. Apple will then apply this reading size to every Dynamic Type-supported element across iOS. It’s a little bit like the default or minimum font size setting in a web browser.</p>
<figure>
<img src="images/larger-text.jpg" alt="Side-by-side screenshots of standard sized text, enabling Dynamic Type to set text to be larger">
<figcaption>
<p>(Left: standard Settings. Right: Larger Dynamic Type.) Dynamic Type is known as “Larger Text” in the Accessibility menu. You can instantly see the text resize in the Settings. You can also enable “Larger Accessibility Sizes” to make the text even bigger.</p>
</figcaption>
</figure>
<p>What’s even cooler is that Dynamic Type also works in Safari on iOS.</p>
<p>As I’ve mentioned before, Better’s interface is mostly web views. They’re local to the device, but they’re HTML and CSS like you’d find on any web page. So Dynamic Text support needed to be added to the CSS. As we have a few specific CSS rules for the app, I could have just added the Dynamic Type support there. But Dynamic Type also works in Safari, I thought it was worth making it work on the <a href="https://better.fyi">Better site</a> as well.</p>
<figure>
<img src="images/better-dynamic-type.jpg" alt="Side-by-side screenshots of Better with standard text size and Dynamic Type larger text size">
<figcaption>
<p>Left: the <a href='https://better.fyi/trackers/doubleclick.net/'>Google DoubleClick tracker page on Better.fyi</a> without Dynamic Type enabled. Right: the same page but with a larger text size selected</p>
</figcaption>
</figure>
<p>As I’ve mentioned before, Better’s interface is mostly web views. They’re local to the device, but they’re HTML and CSS like you’d find on any web page. So Dynamic Text support needed to be added to the CSS.</p>
<p>Sidenote: I’m not a huge fan of <a href="http://alistapart.com/article/every-time-you-call-a-proprietary-feature-css3-a-kitten-dies">using proprietary CSS unless it’s for implementing prefixed future standards</a>. But Dynamic Type is an important feature, and integral to Better’s overall accessibility.</a>
<p>As we have a few specific CSS rules for the app, I could have just added the Dynamic Type support there. But Dynamic Type also works in Safari, I thought it was worth making it work on the <a href="https://better.fyi">Better site</a> as well. Apple themselves don’t seem to have support for Dynamic Type on their site, so I assume they intended this feature to mostly be used in web views inside native apps.</p>
<h2>Adding basic Dynamic Type support</h2>
<p>Reading up on what <a href="https://webkit.org/blog/3709/using-the-system-font-in-web-content/">little “official” information there is</a> about <a href="http://www.interactiveaccessibility.com/blog/text-resizing-web-pages-ios-using-dynamic-type">implementing Dynamic Text on the web</a>, it looked to be fairly straight-forward to implement:</p>
......@@ -86,74 +102,181 @@ font: -apple-system-short-caption1
font: -apple-system-short-footnote
font: -apple-system-tall-body</code></pre>
<p>But there are some caveats. Firstly, you need to understand what <code>-apple-system-etc</code> does. It effectively sets the following:</p>
<p>But there are some caveats. Firstly, you need to understand what <code>-apple-system-etc</code> does. It is a <a href='https://css-tricks.com/almanac/properties/f/font/#article-header-id-5'>font keyword</a> that sets:</p>
<pre><code>font-family: (system font);
font-size: (Dynamic Type size)
font-size: (Dynamic Type size);
font-style: normal;
font-weight: (bold for -headlines, normal for -body,-caption,-footnote)
font-weight: (bold for -headlines, normal for -body,-caption,-footnote);
font-variant: normal;</code></pre>
<p>You can see the Dynamic Type defaults in action if you <a href="http://ia11y.github.io/Coding-Patterns/iOS/text-resizing/resizable-vs-non-resizable-font-ios.html_">visit this sample page on iOS Safari</a>. (See screenshot below)</p>
<figure>
<img src="" alt="Sample list of Dynamic Type type choices in iOS">
<img src="images/demo.jpg" alt="Sample list of Dynamic Type type choices in iOS">
<figcaption>
<p>Notice that headlines are small and body text is big.</p>
<p>Left: standard text size. Right: with Larger Text (Dynamic Type) enabled. Notice that, by default, headlines are small and body text is big.</p>
</figcaption>
</figure>
<p>How you then add Dynamic Type depends on how you want to implement it on your page. For Better I decided:</p>
<p>How you then add Dynamic Type depends on how you want to implement it on your site. For Better I wrote a list of what I wanted to implement:</p>
<ul>
<li>Use the default Dynamic Type size for every text element</li>
<li>Don’t apply Dynamic Type to the root. <a href="/labs/blog/better-css-overhaul/">We use em units</a>, so setting Dynamic Type on the root the layout would resize every unit in the layout, and break a lot of elements with fiddly layouts</li>
<li>Keep our own font families, so we still have the Better look-and-feel</li>
<li>Allow Dynamic Type to override the chosen font-styles, font-weights and font-variants, for consistency with other apps that support Dynamic Type</li>
</li>
<li><a href='#on-root'>Dynamic Type should be applied to HTML root so all other font sizes scale relatively</a></li>
<li><a href='#unless-on-ios'>The use of Dynamic Type should not affect the page unless on iOS</a></li>
<li><a href='#unless-enabled'>The use of Dynamic Type should not affect the page unless Dynamic Type is enabled</a></li>
</ul>
<h2 id='on-root'>Setting Dynamic Type on the root</h2>
<p>If you use proprietary prefixes a lot, then you probably use them like this:</p>
<p>The <a href='http://www.interactiveaccessibility.com/blog/text-resizing-web-pages-ios-using-dynamic-type'>example provided on the Interactive Accessibility site</a> is to wrap a <code>&lt;span&gt;</code> around all the text you want to make resizable like below:</p>
<figure><pre><code>display: -webkit-box; /* make flexbox work for old webkit implementations */
display: -webkit-flex; /* make flexbox work for newer webkit implementations */
display: -ms-flexbox; /* make flexbox work for Internet Explorer */
display: flex; /* make flexbox work for all browsers that support the standard implementation of flexbox */</code></pre>
<pre><code>&lt;p&gt;&lt;span class="body-text-size"&gt;This is some text in my page.&lt;/span&gt;&lt;/p&gt;</pre></code>
<figcaption><p>You use the standard, non-prefixed, property last, because that will override the previous rules if it is also supported.</p></figcaption>
</figure>
<p>This would be a complete nightmare to maintain, and near-impossible on a dynamically generated site like ours. If your CSS <a href='../better-css-overhaul'>relies on setting a root font size, then using <code>em</code>s for all subseqent sizes</a>, adding Dynamic Type is much easier.</p>
<p>But that doesn’t work with Dynamic Type because the proprietary bit is the value, not the property.</p>
<p>First, you need to set the Dynamic Type font rule on the root. We decided that we wanted the font sizes and layout to scale up together, so I used <code>-apple-system-body;</code> as the root value:</p>
<pre><code>p {
font: -apple-system-body;
font-family: Avenir, Helvetica, sans-serif;
font-size: 1em;
font-weight: normal;
<pre><code>html
{
font: -apple-system-body;
}</code></pre>
<p>As the -apple-system-body rule uses the <a href="https://www.impressivewebs.com/css-font-shorthand-property-cheat-sheet/">font property shorthand</a> this would result in the Dynamic Type being overridden by the following font-family, font-weight, and font-size rules. For Better, I wanted to keep the original font-family and font-weight, but not override the font-size as that would defeat the point of adding support for Dynamic Type.</p>
<p>Then all subsequent font sizes specified in <code>em</code>s with resize appropriately to the size chosen in the Accessibility settings.</p>
<pre><code>html
{
font: -apple-system-body;
}
h2
{
font-size: 1.75em;
}
</code></pre>
<p>In the example above, the <code>h2</code> font size is <a href='https://developer.mozilla.org/en-US/docs/Web/CSS/computed_value'>computed</a> as 27.96500015258789px when the default font size is used, and 87.18499755859375px when the Dynamic Type size is set to the very largest using Larger Text.</p>
<h2 id='unless-on-ios'>Preventing the font rule from breaking the rest of the CSS</h2>
<p>Adding the Dynamic Type in this way is pretty handy, however <code>font: -apple-system-body;</code> is not proprietary CSS, this is <a href='https://css-tricks.com/almanac/properties/f/font/#article-header-id-5'>the correct syntax for using System Fonts</a>. This means that all the other browsers will also see the <code>font:</code> property, use it to override any <a href='https://www.smashingmagazine.com/2010/04/css-specificity-and-inheritance/'>less specific font rules</a>, but not understand the <code>-apple-system-body</code> value, and ignore it. Thus resetting the fonts back to its browser default. So I had to make sure other browsers wouldn’t see the <code>font: -apple-system-body;</code> CSS.</p>
<h3>@supports to the rescue</h3>
<p>The trick is to do the following:</p>
<pre><code>p {
font-size: 1em; /* sets font size for all browsers */
font: -apple-system-body; /* set Dynamic Type, overriding font size for iOS */
font-family: Avenir, Helvetica, sans-serif; /* set font family for all browsers, overriding Dynamic Type */
font-weight: normal; /* set font weight for all browsers, overriding Dynamic Type */
<p>Thanks to the wonders of modern browsers, Safari can detect support for <code>font: -apple-system-body;</code> using <a href='http://docs.webplatform.org/css/atrules/supports/'><code>@supports</code></a>. So I just needed to wrap any CSS related to Dynamic Type in an @supports at-rule, and I’m no longer breaking the CSS in other browsers:</p>
<pre><code>/* ↓ root size for all other browsers */
html
{
font-size: 14px;
}
/* ↓ root size for iOS browsers (those that support font: -apple-system-body;) */
@supports (font: -apple-system-body)
{
html
{
font: -apple-system-body;
}
}</code></pre>
<p>If you were working on browser workarounds in the days of IE6 and IE for Mac, you will understand the level of delight I get from <code>@supports</code>.</p>
<h2 id='unless-enabled'>When Dynamic Type is not enabled</h2>
<p>This works well for Better’s CSS as we mostly set the font-sizes on the base elements (h1, h2 etc) and let the cascade do the rest. However, it does get a little trickier if you set font-sizes on classes and other more-specific selectors. You’ll need to repeat the same rule again:</p>
<p>Now that I had my Dynamic Type rule taking priority over the root size on iOS, I had another tricky issue: how do I set the root size when Dynamic Type is not enabled?</p>
<pre><code>body.spotlight .feature
<p>Technically-speaking, Dynamic Type is always enabled, it’s just a case of whether you have chosen to change the text size or not. This means that the root font size will always be Apple’s chosen default for <code>-apple-system-body</code>, even if you haven’t touched the Accessibility settings. If you’re the kind of person who always works from the browser’s default size, then this may not bother you. But I am a control freak, and I like font sizing to be fairly consistent cross-browser.</p>
<p>Inspecting the various computed font sizes, I found that Apple’s default font size is 17px, whereas my chosen root font size is 14px on the narrowest viewport. It’s a fairly sizeable difference. So I used the cascade to scale down the font size on the <code>body</code> element, so all the subsequent font sizes would be the same computed size as other browsers:</p>
<pre><code>@supports (font: -apple-system-body)
{
font-size: 1.1em; /* special font size for this feature */
font: -apple-system-body; /* set Dynamic Type again */
font-family: Avenir, Helvetica, sans-serif; /* override the Dynamic Type font family again */
word-wrap: break-word;
html
{
font: -apple-system-body;
}
body
{
font-size: 0.94em;
}
}</code></pre>
<p>Needless to say, if your CSS is simple and relies on the cascade, adding Dynamic Type is much easier.</p>
<p>This worked well, but I later on I was confused as to why my text wasn’t scaling up at different viewport sizes. (If you’ve read <a href='../better-css-overhaul'>my post on how we scale using <code>ems</code></a>, you’ll know that I scale up the root font size at two wider viewport breakpoints.) This was because the specificity of the <code>body</code> rule was overriding that of the subsequent <code>html</code> rules. The media queries were not as specific in terms of the cascade. I had to re-state the <code>body</code> rule for each time I scaled up the font size according to viewport width. I also had to recalculate the adjustment for the default font size according to the desired font size. My final CSS for Dynamic Type and root sizes is now essentially:</p>
<pre><code>html
{
font-size: 14px;
line-height: 1.5;
}
@media only screen and (min-width: 28.78em)
{
html
{
font-size: 16px;
}
}
@media only screen and (min-width: 33.4em)
{
html
{
font-size: 18px;
}
}
@supports (font: -apple-system-body)
{
html
{
font: -apple-system-body;
}
/* default size of -apple-system-body here is 17px
using that as a default, scale text down to equivalent of 14px (14/17).
*/
body
{
font-size: 0.94em;
}
@media only screen and (min-width: 28.78em)
{
html
{
font: -apple-system-body;
}
/* default size of -apple-system-body here is 17px
using that as a default, scale text down to equivalent of 16px (16/17).
*/
body
{
font-size: 0.82em;
}
}
}
@media only screen and (min-width: 33.4em)
{
html
{
font: -apple-system-body;
}
/* default size of -apple-system-body here is 17px
using that as a default, scale text down to equivalent of 18px (18/17)
*/
body
{
font-size: 1.06em;
}
}
}</code></pre>
<p>If you’re having trouble with long words or URLs overflowing your layouts when the Dynamic Type is set to very large, it’s worth reading <a href="https://css-tricks.com/snippets/css/prevent-long-urls-from-breaking-out-of-container/">Chris Coyier on CSS for Handling Long Words and URLs</a>.</p>
<p>Now I <em>think</em> this is probably the most straight-forward way to implement Dynamic Type. Especially if you don’t need to scale up the root font size at different viewport sizes, and if you don’t mind using the browser’s default font size on the root. Has anyone else implemented Dynamic Type on the web? I’d love to hear how you did it!</p>
</div>
<div id="discourse-comments"></div>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment