September 2, 2015
A Developer’s Dilemma: Responsive Design and the Vertical Scrollbar
By Jen Scott, Applications Engineer
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.
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
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.
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.
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.
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!