Torkil Johnsen

My personal piece of cyberspace

Let CSS tell JS which breakpoint we’re at

Posted in CSS on May 24th, 2012

I have been working with responsive webdesign lately, and I have come across more than one example of people who define their breakpoints in both CSS and Javascript, or were having issues deciding where to define them. A quick fix/hack for you…

Defining breakpoints should be done once.

I’m solving it like this:

At the bottom of your HTML, add for instance a UL. We’ll change this UL in the CSS, and have JS pick up the changes:

<ul id="breakpoints">
    <li id="tiny"></li>
    <li id="small"></li>
    <li id="medium"></li>
    <li id="large"></li>
    <li id="huge"></li>
</ul>

Then, in your CSS, you do something like this:

#breakpoints    { display: none }
#breakpoints li { height: 0 }
 
@media screen and (min-width: 50em) {
    #breakpoints #medium { height: 1px }
}

Javascript knows we’re at the medium breakpoint or beyond, because the item’s height is set to 1. Still, no items are showing on screen because the UL has display: none.

Using jQuery here, to fetch the height:

if ($('#medium').height() == 1) {
    // do your medium breakpoint thing
}

If you’re using a CSS preprocessor, like Sass, you should also define your breakpoints as variables — once — in the CSS, and not litter your CSS with multiple min-width: 50em’s.

Defining things ONCE was kind of the point I was trying to make here ;)

Having Sass work things out for us:

Here, I just loop over each breakpoint, adding height:0 or height:1 to each LI item on each iteration, depending on the breakpoint.

#breakpoints {
    display: none;
    & > li { height: 0 }
}
 
$breakpoints: 15em 25em 45em 64em 80em;
$breakpoint_names: tiny small medium large huge;
 
@for $i from 1 through 5 {
    @media screen and (min-width: nth($breakpoints, $i)) {
        @for $j from 1 through $i {
            #breakpoints ##{nth($breakpoint_names, $j)} { height:
                @if $j == $i { 1px } 
                @else if $j == $i-1 { 0 }
            }
        }
    }
}

Yes, this code could probably be a lot nicer, but you get the point.

The above will output something like this:

#breakpoints {
    display: none;
}
 
#breakpoints > li {
    height: 0
}
 
@media screen and (min-width: 15em) {
    #breakpoints #tiny  { height: 1px }
}
 
@media screen and (min-width: 25em) {
    #breakpoints #tiny   { height: 0 }
    #breakpoints #small  { height: 1px }
}
 
@media screen and (min-width: 45em) {
    #breakpoints #small  { height: 0 }
    #breakpoints #medium { height: 1px }
}
 
@media screen and (min-width: 64em) {
    #breakpoints #medium { height: 0 }
    #breakpoints #large  { height: 1px } 
}
 
@media screen and (min-width: 80em) {
    #breakpoints #large  { height: 0 }
    #breakpoints #huge   { height: 1px } 
}

Power of loops in Sass :)

  • http://torkiljohnsen.com Torkil Johnsen

    Another interesting method of solving the same issue, from adaptive-images.com:

    @media only screen and (max-device-width: 479px) {
       html { background-image:url(ai-cookie.php?maxwidth=479); } }

    Now, the ai-cookie.php-file will set a cookie for you, which can then be used by both Javascript and PHP for instance. Clever!See: https://github.com/MattWilcox/Adaptive-Images/blob/master/instructions.htmAnd: https://github.com/MattWilcox/Adaptive-Images/blob/master/ai-cookie.php


Creative Commons License
This work by Torkil Johnsen is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.