September 2, 2015

A Developer’s Dilemma: Responsive Design and the Vertical Scrollbar

by Mary Clare Riordan

By Jen Scott, Applications Engineer

dilemma

Responsive design is lauded as a solution to our multi-device world: one code base that looks great on devices big and small. But in reality, it’s not so simple as it sounds.

For this harmonious, one-code-to-be-viewed-by-all scenario to work, we must rely heavily upon CSS media queries and Javascript resize events which determine how content is rendered. If not handled correctly, you can end up in the “Mismatch Zone”—a  zone where the triggering of media queries and resize events don’t match, causing the user to see a jumbled page.

Mismatch Zone  

Media queries, in this case intended to check the size of the screen, and JS resize events need to work in concert. However, sometimes a page’s content is longer than the height of the screen, which means a vertical scrollbar is added to the screen. This scrollbar affects the calculated width of the screen, which impacts when your media queries and resize events are triggered. When they’re triggered at different times due to the vertical scrollbar, a Mismatch Zone of 15-20 pixels appears on the page.

Is a 20px difference that big of a deal? If you’re implementing a truly fluid design, then probably not. However, what is commonly seen is a hybrid of fixed-width and fluid design principles where elements are fluid up to fixed breakpoints. (A fluid design means when the users is resizing their browser, the page grows and shrinks, but all of the elements are in the same spots and the layout remains the same. A breakpoint based design means the page will look one way until the screen hits a certain spot – or breakpoint – and then the layout will change to better fit that size window.)The hybrid we typically see is a fluid shrinking or growing of elements as we resize to a breakpoint, then the design will change and become fluid again until the next breakpoint. It’s this scenario – when the browser hits a breakpoint and a more dramatic shift of elements is triggered – where the Mismatch Zone can cause issues.

How Browsers Calculate Viewable Area

According to W3C, the definition of width is:

The ‘width’ media feature describes the width of the targeted display area of the output device. For continuous media, this is the width of the viewport (as described by CSS2, section 9.1.1 including the size of a rendered scroll bar (if any).

However, not all browsers use this definition. Of the four main browsers, Safari is the only one that doesn’t include the scrollbar when defining width. This means Safari media queries will be 15-20px off from the other browsers.

CSS and jQuery Trigger at Different Widths

There is another layer to this issue: jQuery. Remember I said CSS media queries and JavaScript resize events have to be triggered at the same time. One of the most prevalent JavaScript frameworks developers use is jQuery. It is a powerful library that helps developers use JavaScript more easily. This framework has built in methods that are used to calculate screen dimensions and handle browser resizing. One method that is commonly used to find the width of the browser screen is $(window).width().

If you rely upon jQuery’s $(window).width() for screen-width detection, you may have an issue in the Mismatch Zone. This is because jQuery .width() includes the scrollbar in its calculations.

So, if your CSS media query is firing at 800px excluding the scrollbar, and your jQuery resize event is firing at 800px including the scrollbar, you have a Mismatch Zone problem. There will be a 15-20 pixel area where your CSS has already changed and your Javascript resize event has not.

Let’s consider the following scenario to demonstrate.

We have a responsive breakpoint at 760px. When the browser is resized to less than 760px, we want the horizontal menu to turn into a vertical off-canvas menu. At our breakpoint, we need two things to happen.

The first is that jQuery needs to kick in to change a horizontal navigation menu into a tall mobile menu accessed by an icon. Touch events are applied, subcategories are hidden from view, and a new height is calculated to turn the horizontal, 40px tall menu into to a vertical, 100% height menu.

The second is that the CSS media queries need to trigger to change the position and look of the menu. The small, clickable links become larger, touch-friendly links and the position is updated to move it off the visible screen area.

The jQuery resize event changes the height of our navigation, but a CSS media query is supposed to move it off screen. When these two things do not happen at the same time, our page is covered by the now 100% height menu and we can no longer see any content

As we resize the page in Chrome, if we are using jQuery’s $(window).width() to calculate our screen width, when we reach 759px, the horizontal navigation’s height is suddenly covering the majority of screen, but the media query that moves the menu off-screen has not triggered. This causes the navigation to block the use of the page. If we reduce the screen about 15px more, the CSS kicks in; the menu is moved off-canvas; and we can use the page again.

mismatch zone 1

Minimize your Mismatch Risk

While it’s not a 100% browser-proof option, window.innerWidth is the simplest and easiest option to minimize the Mismatch Zone. Just swap out window.innerWidth for whatever method you are currently using to in your site’s width calculations.

mismatch zone 2
This graphic shows how the vertical scrollbar is calculated in media queries and JavaScript/jQuery methods. Because three out of four major browsers are “scrollbar blind” in their calculations, it makes sense to look for a JavaScript option that is also “scrollbar blind.”  The window.innerWidth calculation is the only one.

Using window.innerWidth on your resize events will allow for the best cross-browser experience with only the Safari browsers falling victim to the Mismatch Zone.

Other solutions do exist. Some developers have written scripts that will temporarily remove the vertical scrollbar, calculate the width using $(window).width(), then put the scrollbar back.  Others have a created long and complicated scripts designed to pull browser data and select optimized methods based upon that.  While those may be technically more accurate, the benefit is small for the effort.

Want to learn more? Contact us!

References:

http://www.sitepoint.com/responsive-web-design-too-fragile/

http://www.sitepoint.com/rwd-scrollbars-is-chrome-better/

https://www.fourfront.us/blog/jquery-window-width-and-media-queries

https://www.fourfront.us/demo/jquery-width-and-media-queries.html