{"id":259590,"date":"2017-09-01T06:22:45","date_gmt":"2017-09-01T13:22:45","guid":{"rendered":"http:\/\/css-tricks.com\/?p=259590"},"modified":"2017-09-25T08:45:52","modified_gmt":"2017-09-25T15:45:52","slug":"best-way-programmatically-zoom-web-application","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/best-way-programmatically-zoom-web-application\/","title":{"rendered":"Best Way to Programmatically Zoom a Web Application"},"content":{"rendered":"

Website accessibility has always been important, but nowadays, when we have clear standards and regulations from governments in most countries, it’s become even more crucial to support those standards and make our projects as accessible as they can be.<\/p>\n

The W3C recommendation provides 3 level of conformance: A<\/code>, AA<\/code> and AAA<\/code>. To be at the AA<\/code> level, among other requirements, we have to provide a way to increase the site’s font size:<\/p>\n

1.4.4<\/a> Resize text:<\/strong> Except for captions<\/a> and images of text<\/a>, text<\/a> can be resized without assistive technology<\/a> up to 200 percent without loss of content or functionality. (Level AA)<\/p><\/blockquote>\n

Let’s look at solutions for this and try to find the best one we can.<\/p>\n

Update(09\/25\/17):<\/strong> It turns out that WCAG doesn’t require a text resizing custom solution in addition to what user-agents provide. We just have to make sure a website looks OK as a result of resizing. Yet if we still want to scale elements for any reason, below is a thorough analysis of different methods for doing that.<\/p>\n

<\/p>\n

Incomplete Solution\u200a: \u200aCSS zoom<\/code><\/h3>\n

The first word which comes up when we talk about size changing is zoom<\/em>. CSS has a zoom<\/code> property and it does exactly what we want\u200a\u2014\u200aincreases size. <\/p>\n

Let’s take a look at a common design pattern (that we’ll use for the rest of this article): a horizontal bar of navigation that turns into a menu icon at a certain breakpoint:<\/p>\n

\"\"
This is what we want to happen. No wrapping and the entire menu turns into a menu icon at a specified breakpoint.<\/figcaption><\/figure>\n

The GIF below shows what we get with zoom<\/code> approach applied to the menu element. I created a switcher which allows selecting different sizes and applies an appropriate zoom level: <\/p>\n

\"\"
Check out the Pen here<\/a> if you want to play with it.<\/figcaption><\/figure>\n

The menu goes outside visible area because we cannot programmatically increase viewport width with zoom nor we can wrap the menu because of the requirement. The menu icon doesn’t appear either, because the screen size hasn’t actually changed, it’s the same as before we clicked the switcher.<\/p>\n

All these problems, plus, zoom<\/code> is not supported by Firefox at all anyway.<\/p>\n

Wrong Solution: Scale Transforms<\/h3>\n

We can get largely the same effect with transform: scale<\/code> as we got with zoom<\/code>. Except, transform<\/code> is more widely supported by browsers<\/a>. Still, we get the exact same problems as we got with zoom<\/code>: the menu doesn’t fit into the visible area, and worse, it goes beyond the vertical visible area as well because page layout is calculated based on an initial 1-factor scale.<\/p>\n

See the Pen Font-switcher–wrong-scale<\/a> by Mikhail Romanov (@romanovma<\/a>) on CodePen<\/a>.<\/p>\n

Another Incomplete Solution\u200a: \u200arem<\/code> and html<\/code> font-size<\/code><\/h3>\n

Instead of zooming or scaling, we could use rem<\/code> as the sizing unit for all elements on the page. We can then change their size by altering html<\/code> element’s font-size<\/code> property, because by its definition 1rem<\/code> equals to html<\/code>‘s font-size<\/code> value.<\/p>\n

This is a fairly good solution, but not quite perfect. As you can see in the following demo, it has the same issues as previous examples: at one point it doesn’t fit horizontally because required space is increased but the viewport width stays intact.<\/p>\n

See the Pen Font-switcher–wrong-rem<\/a> by Mikhail Romanov (@romanovma<\/a>) on CodePen<\/a>.<\/p>\n

The trouble, in a sense, is that the media queries don’t adjust to the change in size. When we go up in size, the media queries should adjust accordingly so that the effect at the same place would happen before the size change, relative to the content.<\/p>\n

Working Solution: \u200aEmulate Browser Zoom with Sass mixin<\/code><\/h3>\n

To find inspiration, let’s see how the native<\/em> browser zoom feature handles the problem:<\/p>\n

\"\"<\/figure>\n

Wow! Chrome understands that zooming actually does change the viewport. The larger the zoom, the narrower the viewport. Meaning that our media queries will actually take effect like we expect and need them to.<\/p>\n

One way to achieve this (without relying on native zoom, because there is no way for us to access that for our on on-page controls as required by AA) is to somehow update the media query values every time we switch the font size. <\/p>\n

For example, say we have a media query breakpoint at 1024px<\/code> and we perform a 200%<\/code> zoom. We should update that breakpoint to 2048px<\/code> to compensate for the new size.<\/p>\n

Shouldn’t this be easy? Can’t we just set the media queries with rem<\/code> units so that when we increase the font-size<\/code> the media queries automatically adjust? Sadly no, that approach doesn’t work. Try to update media query from px<\/code> to rem<\/code> in this Pen<\/a> and see that nothing changes. The \u200alayout doesn’t switch breakpoints after increasing the size. That is because, according to standard<\/a>s, both rem<\/code> and em<\/code> units in media queries are calculated based on the initial value of html<\/code> element font-size<\/code> which is normally 16px<\/code> (and can vary). <\/p>\n

Relative units in media queries are based on the initial value, which means that units are never based on results of declarations. For example, in HTML, the em<\/code> unit is relative to the initial value of ‘font-size<\/code>.<\/p><\/blockquote>\n

We can use power of Sass mixin<\/code>s to get around this though! Here is how we’ll do it:<\/p>\n