Update: The first piece of code had an unexpected side effect that is addressed in the update at the bottom of this post.
CSS media queries and jQuery window width calculations each handle scrollbars differently. This can cause unexpected (and ugly) results when they are used together. I was recently building a responsive menu system that relied on CSS media queries to create a vertical menu for small screens, such as mobile devices. I then used a jQuery width measurement to determine whether or not to create a button for toggling the visibility of the vertical menus. However, I was in for a nasty surprise. Unfortunately, when a CSS media query measures the width of the window it includes the width of the scrollbar. On the other hand, when jQuery measures the width of the window it does not include the width of the scrollbar. When there was no vertical scrollbar, both my CSS media query and jQuery function would fire at the same window size. However, when the page content was long enough to require a scrollbar, the jQuery function would fire first. Eventually, I realized that I could disable scrolling momentarily while I placed the window width into a variable for use later in the script. Here is what it looks like:
jQuery('body').css('overflow', 'hidden'); jQuery('html').css('overflow-y', 'hidden'); var window_width = jQuery(window).width(); jQuery('body').css('overflow', 'auto'); jQuery('html').css('overflow-y', 'auto');
Update: After working with this section of code for a time, I realized that setting “overflow” to hidden caused the page to jump to the top whenever the page was reloaded or the window was resized. So I set off across the internet in search of a script that would measure the width of the scroll bar, rather than measuring the width of the window without the scroll bar. That is how I came across this script by Jonathan Sharp. However, I didn’t need to know the scrollbar width on short pages that didn’t scroll, so I modified it to only return a value when a scrollbar is present on the page.
/* Calculates scrollbar width in pixels */ function scrollbar_width() { if( jQuery('body').height() > jQuery(window).height()) { /* Modified from: http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php */ var calculation_content = jQuery('<div style="width:50px;height:50px;overflow:hidden;position:absolute;top:-200px;left:-200px;"><div style="height:100px;"></div>'); jQuery('body').append( calculation_content ); var width_one = jQuery('div', calculation_content).innerWidth(); calculation_content.css('overflow-y', 'scroll'); var width_two = jQuery('div', calculation_content).innerWidth(); jQuery(calculation_content).remove(); return ( width_one - width_two ); } return 0; }
This can then be added to the window width to get the full width of the window including the scrollbar:
var window_width = jQuery('body').width() + scrollbar_width();
Great tip – saved me some pain – thanks 🙂
Quite a few frameworks such as HTML5 Boilerplate recommend to set “html” to “overflow-y: scroll” so there’s always a scrollbar. Changing line #3 to “if( ($(‘body’).height() > $(window).height()) || ($(‘html’).css(‘overflow-y’) == ‘scroll’)) {” will accommodate for that.
Thanks for pointing that out, Tim. Just as a personal preference, I don’t like showing a scrollbar if it doesn’t do anything. I know there are both pros and cons for the each side of scrollbar issue, so thanks for posting your modifications so both situations can be handled!
Personally, I don’t like the jumps that occur when you surf from a page with scrollbar to one without and vice versa. I actually had one or two customers complaining about the broken layout, so we got that overflow-y:scroll integrated into our base.css.
BTW, I’m currently working on a rewrite of breakpoints.js that’ll include your script. Thanks for that.
I’m glad you found the script helpful! Let me know when you finish your rewrite of breakpoints. I’d love to take a look!