Back to All

Firing Responsive jQuery Functions based on CSS Media Queries Rather than Window Width

Feb072013

There are some great options for managing Javascript when using CSS media queries in a responsive website. MediaCheck, jRespond, and Breakpoints.js all allow you to fire javascript functions based on customizable breakpoints in browser width. However, recently I was working on a small site with only a single function to be called at a smaller browser size, in conjunction with a media query, and thought I'd forgo one of these scripts and manage my change using a jQuery window width measurement.

The Problem: jQuery $(window).width() and CSS3 Media Queries do not always match.

Initially I was using the below code:

$(window).resize(function(){
	if ($(window).width() <= 800){	
		// do something here
	}	
});

When viewing the site in Firefox, I noticed a small difference in the width at which my media query and javascript were firing. Roger Johansson recently wrote up a great article documenting the inconsistent treatment of vertical scrollbars in media query widths. This inconsistency causes a small difference between browsers in the actual window width when a media query fires, which in turn causes media query and jQuery width measurements to not match in some popular browsers: Firefox, IE, and Opera. Here is a code example showing the difference between the jQuery window width and the media query width measurement.

The solution: use jQuery to test for a changed CSS property, rather than the browser width

Rather than the measuring the screen width on resize of the window, I check for a css rule that is changed by the media query. This way, regardless of the how the browser treats the scrollbar, the media query will fire at the same time.

Suppose the "sampleClass" class has a float:left rule before the media query, and a float:none rule after, on window resize I check for the change in that rule.

The jQuery

$(window).resize(function(){	
	if ($(".sampleClass").css("float") == "none" ){
		// your code here
	}
});

The CSS

.sampleClass {float:left;}
@media only screen and (max-width: 800px){
	.sampleClass {float:none;}
}

Comments:

Vinod Patil • Dec 12, 2011

It’s great, thank you ! :)

Nathan • Feb 28, 2013

Thank you! This sounds exactly what I have been looking for. By the way, I love the way your site here responds by making the navigation menu animate when the width is smaller. I might just use that for my site. Thanks for the inspiration and keep up the good work!

Anthony Cullen • Apr 08, 2013

Worked a treat targeting z-index of a relatively-positioned element. Thanks!

Lukasz • Apr 09, 2013

Smart and clean move. I’m going to use it with Bootstrap by checking .container’s width. Thanks for sharing.

supermegapollo • May 22, 2013

Awesome!! Thx dude ;)

Julian • May 27, 2013

Perfect !
jquery has ever the answer ;)

Alan A • Jun 07, 2013

What a great idea! Using it right now.

Ryan • Jun 24, 2013

That’s neat a way to go about things, I’ve got some media queries/scripts to galvanize!  Thanks for the tip!

Fergus • Jun 25, 2013

This is bad because it intrinsically links behaviour (JS) to content (HTML). Say you (or a colleague) may in the future need to remove the JS hook element (the floated left class). Doing so would render this JS function obsolete (unused code), and would furthermore interfere with the intentional behaviour of the responsive design. We should always be mindful to keep a ‘separation of concerns’ when it comes to these sorts of problems.

Chris Arasin • Jun 26, 2013

Hi Fergus, good point. My counter argument for this method is that in many cases, we may want that intrinsic link between the javascript and the markup. For example, if there’s a piece of content that at larger screen sizes functions as a slideshow but then at smaller sizes breaks out of the slideshow into a scrollable format, you would want the javascript to change exactly when the css modifies the layout.

But to your point, yes a totally arbitrary selection of css rule to check against may lead to a problem down the road.

Fergus • Jun 26, 2013

That intrinsic link can (and I think should) be communicated through employing semantically similar JS hooks and CSS classes/IDs. For instance, I might have some buttons with class=“random_button”. If I want to attach JS behaviour to those buttons I would add an additional class of ‘js_random_button’. Decoupling of behaviour and presentation, as you say, prevents problems later on, but it also serves as a helpful visual indicator of intent. Given that class, it will be immediately obvious to others that the element/s is/are also used in a JS script. There are many advantages to this type of css selector allocation.

David • Jun 27, 2013

What a clever, elegant solution. Thanks!

Martin • Aug 06, 2013

Yes.. but happens when you initially load the page on a mobile device, so there’s no actual browser resize happening? Then this jQuery never fires.

Chris Arasin • Aug 06, 2013

You can do a check outside of the window.resize function as well.

√únsal Korkmaz • Aug 09, 2013

Seriously i love those type of solutions ^^ Thank you

Dagobert Renouf • Aug 09, 2013

Superb idea, I love how it makes it basically impossible to fail, and as it’s supposed to be linked to the css anyway… this is perfect, thank you so much for posting this!

Bill Criswell • Aug 12, 2013

Awesome idea. I think you guys would find Jeremy Keith’s approach very interesting as well. I hacked up a little example for you.

http://jsbin.com/ehawax/1

Mark • Sep 05, 2013

Thanks! This was a big help.

Justin • Sep 06, 2013

Why not just give ‘html’ a width of 100% on your stylesheet and use jQuery to pull the width. Another bonus of doing that is it will account for the width of the scroll bar. Just a thought…

Working example: http://buffolark.com/sandbox/jq-ss-loader/

Chris Arasin • Sep 14, 2013

Thanks Justin, I like that method too.

Shaun W. • Nov 25, 2013

Thanks!

Using bootstrap.

Set a display: hidden; div with a .responsiveTell class then set content: ‘xs’; in each media query

Then tested for .css(‘content’) === ‘xs/sm/md/lg’ in jquery

Frank Folsche • Dec 24, 2013

Hey, nice script but there where a few things not working for me:
like Chris Arasin mentioned you also need to check outside of the resize function otherwise the function does not get called on mobile divices. (tip: you can check this easily in chrome canary)
also the resize function checks for both vertical and horizontal changes, and you only need to detect the horizontal change, this was a problem for me because I was changing the height of the window and the function kept on firing.
I’m now using this:
$(document).ready(function () {
  $(window).resize(function () {
      if ($(window).height() == height) return;
      mobile();
  });
  mobile();
});
function mobile() {
  if ($(“body”).css(“left”) == “3px”) {//mobile test == <500
      smallMobile();
  };
}

Pawel • Jan 03, 2014

Doesn’t work for me unfortunately, using html5 boilerplate with jQuery 1.10.2 ... without the line “if ($(”.sampleClass”).css(“float”) == “none” ){” my code fires up no problems, though. is there any special requirement for this function to work? this is my full code:
$(document).ready(function(){
      if ($(“p.test”).css(“font-size” == “3em” ){
          $(“body”).click(function() {
          $(this).css(‘background’,‘red’);
          });
        });
      });

James • Jan 08, 2014

Anyone got any thoughts on what a good CSS property to be applied to the body that wouldn’t go anything? That way that property wont need to be overridden if the site is restyled, and the body (unlike other elements) will always be on the page.

Umair Hafeez • Jan 27, 2014

Great :-) works like a charm…

Add a Comment

Commenting is not available in this channel entry.
background background
background background background
background background background background