Media Queries Are Not The Answer: Element Query Polyfill

Advertisement

Responsive Web design has transformed how websites are designed and built. It has inspired us to think beyond device classifications and to use media queries to adapt a layout to the browser’s viewport size. This, however, deviates from the hierarchical structure of CSS and characterizes elements relative to the viewport, instead of to their container.

Extensive use of media queries might be the answer for today, but it is not a viable long-term solution. Media queries do not allow for reusable modules that adapt based on their containers’ size.

What Is Responsive Web Design?

Responsive Web design is not limited to a set of technologies; rather, it is a different approach to designing and building websites. I, like many, took Ethan’s words1 about responsive Web design too literally and overlooked the essence of what was being said:

“Fluid grids, flexible images, and media queries are the three technical ingredients for responsive web design, but it also requires a different way of thinking.”

We have accomplished great things while embracing the stated “technical ingredients” for responsive Web design, but we have much room for growth when it comes to a “different way of thinking.” Thinking differently should affect not only how we design and build our websites, but also how we design and build the tools and technologies that our websites are founded on.

Modular Design

When I learned about how media queries could be used in responsive Web design, I was excited by the possibilities. However, it was not long before I learned of the limitations. Media queries are great for adapting layouts to various screen sizes, but terrible for creating modular designs2. Modular CSS is already hard enough, and media queries provide very little to no help. Truly modular layouts need to respond to the sizes of containers, not just to the viewport’s size. Media queries, however, are based on the viewport, rather than an element’s container. There is some hope for standard CSS on the horizon, in the form of a W3C working draft3, by allowing the cascade inheritance to be broken and resetting an element to its defaults. But what about media queries?

The @media Hack

Web developers are masters at taking something created for one purpose and using it to accomplish other things. The Web’s history is littered with examples of this, and media queries are no exception. Kudos to Ian Storm Taylor for writing down his thoughts in the article “Media Queries Are a Hack4.” Hacks are necessary on the Web to provide desired functionality until proper support is achieved, as well as to provide support to older browsers. The W3C states5, “By using media queries, presentations can be tailored to a specific range of output devices without changing the content itself.” The key word here is “can,” but just because you can do something, doesn’t mean you should… But do we have any other choice?

The Element Query

Introducing the element query. An element query is similar to a media query in that, if a condition is met, some CSS will be applied. Element query conditions (such as min-width, max-width, min-height and max-height) are based on elements, instead of the browser. Unfortunately, CSS doesn’t yet support element queries, but that shouldn’t stop us from dreaming, hacking and pushing for new standards.

Conceptual Example

Consider the following example, in which the navigation menu should become visible when it reaches a minimum width of 500 pixels (representing one of many potential syntaxes):

nav (min-width: 500px) {
    display: block;
}

Compare this to a media query in which the navigation menu’s visibility depends on the viewport’s width and needs to account for the padding and other declarations of parent elements:

@media all and (min-width: 520px) {
    nav {
        display: block;
    }
}

Now imagine having to build a modular component that needs to be placed in containers of various sizes on a single page. One current approach is to provide different theme classes (like .module--large) to trigger CSS in media queries. This, however, adds a lot of complications and requires a module to know how its parent will react to various viewport widths.

Issues: Invalid and Looping Conditions

There are several cases in which the CSS of an element query would invalidate the element query itself or create recursion. Hopefully, the browser would be able to detect these conditions and respond appropriately.

Consider the following examples.

Once an element reaches 500 pixels wide, it’s resized to 200 pixels, at which point the rule would no longer apply:

.element (min-width: 500px) {
    width: 200px;
}

Once an element’s width reaches 31.250 ems, its font size would be decreased, which changes the definition of the em unit:

.element (min-width: 31.250em) {
    font-size: 0.75em;
}

Once a container’s width reaches 450 pixels, the size of its child changes to 400 pixels, which would shrink the size of the container:

.container { float: left; }
.child { width: 500px; }
.container (min-width: 450px) > .child {
    width: 400px;
}

There are many other such examples, but you get the point: Element queries are not as simple as we had hoped.

Element Query Polyfill

Element queries seem pretty awesome, but they also have some real issues. To help sort these out, I’ve written a proof-of-concept polyfill. The polyfill has enabled me to understand how a browser might react to various conditions. As I got further along, I realized that the polyfill could hold real value in the Web community’s debate on element queries, and that some developers could even start using element queries today.

The elementQuery polyfill script is available on GitHub6 for you to use, fork and contribute to.

Selector Syntax

The syntax used in the previous examples caused limitations, so I updated the polyfill to support an attribute selector syntax. The ~= attribute selector7 checks whether the value is contained in a space-delimited list (supported in modern browsers above Internet Explorer 6).

The following examples show CSS rules using the syntax required for the elementQuery polyfill.

This rule queries itself for a single condition:

header[min-width~="500px"] {
    background-color: #eee;
}

This rule queries itself for multiple conditions:

header[min-width~="500px"][max-width~="800px"] {
    background-color: #eee;
}

This rule queries a parent for a condition:

header[min-width~="31.250em"] nav {
    clear: both;
}

How It Works

Unfortunately, the elementQuery polyfill requires JavaScript and the Sizzle8 selector engine (which is embedded in jQuery). When the document object model (DOM) is ready, elementQuery scans the document.styleSheets collection for any CSS rules that use elementQuery. When it finds a match, it extracts the following information:

  • Selector
    Such as header, ul > li.class
  • Query type
    min-width, max-width, min-height, max-height
  • Query value
    Such as 500px, 31.250em

elementQuery then uses this information to add or remove attributes from elements that match the given selector and query condition.

Expanded Support

Most browsers, but not Internet Explorer, don’t provide access to the contents of cross-domain style sheets, which causes issues when CSS files are served from a content delivery network. Additionally, parsing style sheets takes time (not much, though). So, I created two branches for elementQuery: master9 and prod10. The master branch includes the code for extracting the necessary elementQuery information (selector, query type, query value), and it also provides a selectors() function to export the information. The prod branch requires the information to be declared in JavaScript, which avoids the cross-domain file issue and the time required to parse the style sheets.

Here is an example of how to export elementQuery information using the master branch:

console.log(JSON.stringify(elementQuery.selectors()));

And here is an example of how to import elementQuery information using the prod branch:

elementQuery({"header":{"min-width":["500px","31.250em"],"max-width":["800px"]}});

Working Examples

I’ve put together a few working examples on CodePen (using the master branch) that you can experiment with or fork. I would love to see what other examples people create (which will probably be much cooler than mine). Just be sure to tag them with #elementquery11 so that others can benefit.

Be Creative

I didn’t write this just to get you to jump on the element query bandwagon, but rather to encourage people to think about how we can solve the problems that are limiting our medium. Let’s keep the discussion going and make the Web a better place. So, go wild and make cool stuff!

Further Reading

(Source of image on front page: Looking Beyond Common Media Query Breakpoints19)

(al)

↑ Back to topShare on Twitter

Tyson Matanich is the lead developer on the Microsoft.com home page. His writings reflect his own opinions and don’t necessarily represent Microsoft’s. He focusses on frontend Web development but will do what’s necessary to get the job done. You can follow him on Twitter or read his blog.

  1. 1

    It seems the repo has gone missing (404).

    0
  2. 3

    Responsive design is dying for a solution to this. Yours it a wonderful step in the right direction.

    There are still a few hurdles that we need to solve. For instance, if classNames are dynamically added, which otherwise would have triggered these element-specific styles on DOM load or resize, then there’s no listener that can trigger a refresh.

    Additionally, if we set the “width” or other attribute of an element dynamically, then these element-specific media queries won’t trigger a rerender.

    I love that we can begin considering flexible designs at the element-level, but a fully-developed solution must accomodate these use-cases and others like it.

    Waiting with bated breath :)

    3
  3. 4

    Explain: what does “access to the contents of cross-domain style sheets” mean?

    0
  4. 6

    I wrote something similar 3 Months ago but your syntax is definitely better – https://github.com/wemakeweb/element-queries

    0
  5. 8

    This method is nice but it cost perfromance, especially on mobile devices. Manipulating DOMElements is resource consuming.

    0
    • 9

      It would be a good idea to write mobile first css and, once you’re done, use something like enquirejs to load the script once the screen width is close to your smallest min-width element-query.

      1
  6. 10

    Excellent element queries will be incredibly beneficial for the plugin market. Responsive plugins aren’t enough. I find users often put plugins in the strangest of places….

    0
    • 11

      Jon Hobbs-Smith

      June 25, 2013 4:53 am

      Indeed, if you don’t even know what layout your component is going to end up in… This could be very useful in tandem with Web Components.

      0
  7. 12

    Jon Hobbs-Smith

    June 25, 2013 4:48 am

    Responsive Design is crying out for this. I really hope browser manufacturers and the W3C can band their heads together and come up with a solution. The simple thing would be to not allow any recursion, or not allow inner elements to affect the size of the container, like iframes do.

    0
  8. 13

    Vitaly Friedman

    June 25, 2013 5:15 am

    You can also follow a fantastic discussion about the so-called “element media queries” in a recent Scott Jehl’s article on the Filament’s group blog: Working around a lack of element queries.

    0
  9. 14

    jQuery required? I really wish that this solution was native. As I would like to use this technique on navigation elements.

    0
    • 15

      It heavily relies on Sizzle to quickly query for elements matching the CSS selectors. Doing a standalone script would require me to rewrite most of Sizzle. Hopefully browsers will eventually start supporting element queries so we wouldn’t have to rely on JavaScript.

      0
      • 16

        Nobody forces you to use Sizzle. There are a few faster selector engines around – I’d just take one of those, add the core script of headJS or anything else that does help us to some nice on-DOM-ready call, add the rest of the actual polyfill on top – and taadaa! Bill’s your uncle.

        cu, w0lf.

        ps: Yep, I actually did that already a few times in other cases. Native JS is just so much more fun .. ;)

        pps: Dear Smashing Magazine: Yeah, I’m STILL no spam bot. Instead you folks obviously STILL haven’t got your “anti-spam” issues fixed.

        0
  10. 18

    I have been reading about CSS FLEXIBLE BOX OR “FLEXBOX” It will be interesting if that concept picks up more traction and see if it plays out.

    0
  11. 19

    Thanks, Tyson for sharing your tips & knowledge about the element query as well as showing us some working examples and pointing out some of its issues.

    0
  12. 20

    Adrian Zumbrunnen

    June 25, 2013 6:53 am

    You can actually use a wrapper which i functions as a module.

    for instance:

    if you use box-sizing border-box im combination with the surrounding element (‘module’) which dictates the width, you get a pretty modular result.

    you start sketching your modules first, then the contents within will adapt just smoothly.

    0
  13. 21

    Also, if you want cleaner rules you can use a CSS preprocessor to nest your selectors:

    header[min-width~="31.250em"] {
    	h1 {
    		font-size: 1.75em;
    	}
    	nav {
    		clear: both;
    	}
    }
    0
    • 22

      Alexandru Lighezan

      November 6, 2013 4:55 pm

      I was wondering wether inside the css element query you could add a class. That class could have properties defined somewhere else in the css. Your js script could then add that class to the element based on its size. Should be much faster than reading all the rules and applying them to the element.

      0
  14. 23

    Daniel Montgomery

    June 25, 2013 8:21 am

    This is a great overview of the topic and good examples.

    I feel the main bottleneck will be surrounding the recursion examples provided. To me, this speaks more for the current model where elements can be sized from containers or contents. I don’t know how the browser decides what to do when there are conflicts, but building from the inside out and the outside in is going to present tons of challenges.

    It feels to me like websites used to build for wrappers fitting to their contents where now almost all content is meant to fit inside their wrapper.

    Could a new element type or procedure be used to force contents to fit inside rather than bloat the wrapper? It’s also an issue of using a structural and style system (CSS) on top of a system (HTML) that is supposed to be abstracted from the structure. They are supposed to be independent, but that’s not realistic at this point.

    If we can’t even get a flexible box model supported I don’t know how long before something useful like this will exist. Here’s hoping soon!

    0
  15. 24

    Another css element query alternative that supports more events than windows’s ‘resize’ event.
    https://github.com/marcj/css-element-queries

    0
  16. 25

    If we’re pushing for standards I’d ask we go a step further and examine how we’re defining these “break points” and re think the ambiguous terminology that is min and max width… yes we’re used to it, but as much as @media is a hack so is this.

    I would propose that we use less-than, greater-than, equal-to, between, range … etc.

    0
  17. 26

    The more we use Media Queries, the more problems we start to see arrising. This kind of solution would definatly help us to solve a few of those problems. Maybe a CSS4 implimentation (if they can get off their ass).

    0
  18. 28

    This is a great solution to one of the RWD problems. However, it is still OSFA in nature.

    By gratuitously pursuing OSFA RWD, we are placing limits that never allow us to take full advantage of the medium. The smartphone, the tablet, the desktop/laptop all need to be seen as unique mediums with unique advantages, benefits and limitations.

    Developers of phone, tablet and desktop apps don’t simply rescale their apps for each device. Why do we do it with web pages?

    RWD should be constrained to the medium. e.g. on the smartphone medium, delivering normal graphics on an iPhone 3GS, and retina graphics on an iPhone 5. Or on the desktop/laptop medium, two column body layout on a desktop greater than 1680, and one column on less than that.

    But when we try transforming a smartphone, 320px wide layout, into a 1920 desktop, we make sacrifices on both mediums.

    If we must pursue OSFA RWD, then this proposal of element queries is better than media queries.

    0
  19. 29

    So if the CSS spec. and browsers someday support the “element query” would this then eliminate the need to use something like ‘sizzle’?

    0
  20. 30

    Wouldn’t a solution to the looping problem be fixed by using container queries rather than element queries? You’d still largely have the same functionality.

    I imagine it would work something like this:

    “`
    @parent (min-width: 500px) {
    .foo {
    width: 200px;
    }
    }
    “`

    In fact, now that I look at this I think it may be more useful. Allowing you to reuse a `@parent` query for multiple modules.

    Issue:

    looping may still occur if the parent elements width depends on it’s content. Although that is an issue with the element query too, so this is at least closer. In fact it could probably solved by only applying to elements that are positioned in a way that doesn’t depend on content.

    1
  21. 31

    Just awesome.

    We’ve been looking for something like this to help us out with quick prototyping. Sure enough, there is a performance hit and I would never use it on a production site, but when it comes to prototyping (where you need _a lot_ more flexibility) this is a true godsend. The concept of element queries has been floating around the web for a while now, good to see it pick up some steam. RWD needs it.

    0
  22. 32

    Thanks for the article. It’s really great to see other developers experimenting with technology that is already in place. Keep up the hard work!

    0
  23. 33

    I hated the idea of element queries when I first saw them, they felt redundant and forced but over the last couple of weeks I’ve really come to believe that they are the long term solution. THank you for putting this polyfill out there, I look forward to playing with i.t

    0
  24. 34

    Great concept and technique. I like anything that’s simpler and more streamlined. If you’re calling media queries a hack though – with which I don’t totally disagree – then this technique also seems like a another hack to me. At least for the time being, considering the current state of affairs on the web with this. Be interesting to see this developed more. I’ll keep an eye out. Thanks.

    0
  25. 35

    Lucifero Von Nachtosphere

    July 1, 2013 7:09 am

    Great article Tyson Matanich, my compliments.
    Maybe (maybe) it’s more for the “classic” templating approach, but nonetheless this is kinda the «holy grail» of templates, really!
    I had some fun with this: http://codepen.io/nobilelucifero/pen/hgGLf and think I’ll use this technique ASAP.

    You made my day, Sir

    0
  26. 36

    Marcellino Bommezijn

    July 2, 2013 11:48 am

    Nice approach indeed. The sample links on Codepen respond very slow (at least for me – FF and Chrome) on browser re-size and doesn’t immediate show the visual result, it stalls. This might be due to the use of JS which needs to evaluate the page first and do the magic.
    And these are small samples, so i wonder what happens when it concerns a large collection of rules that need to be evaluated.
    Would it be possible to mix the use of media queries and polyfill? This way you can take advantage of both.

    0
    • 37

      It’s only a Polyfill, so, yeah, it’s slow. But as soon as this is implemented it will probably be as fast as media queries.

      0
  27. 38

    Jonathan Weavers

    July 9, 2013 12:49 am

    Hey Tyson-

    Your last post [Media Queries Are Not The Answer: Element Query Polyfill] was freaking awesome. I have gone ahead and added your stuff to my Feedly account. Please keep me updated if you post anywhere else.

    Keep rocking –

    Jon

    0
  28. 39

    Some of what you’re talking about is being achieved with the LESS CSS plugin. It provides a very well thought out method for treating CSS programmatically.

    Check it out at: http://lesscss.org/

    0
  29. 40

    I wrote a framework [SickleS] which inspired by your [elementQuery].
    Check it out : http://singggum3b.github.io/SickleS/

    0
  30. 41

    Can you help me how to link the scripts in the html page?

    0
  31. 42

    i don’t like the script solution, but this is how media queries should work and i believe this will be the future

    i hope someone will start soon to write an rfc regarding this

    0
  32. 43

    Loving this, but I feel like I was just getting my fancy SASS-based, old-IE accommodating media-queries set up right.. The web moves so fast :-)

    0
  33. 44

    When will we designers get back to designing in terms of proportions?

    As long as this so called “responsive” technology ignores that visual communications and visual aesthetics are strongly based upon the interrelationship between the height and the width of a visual element — and not based on either width-only or height-only formulas — then all of these technical refinements seem doomed to aesthetic miscommunications.

    I’m all for a “different way of thinking”, but only if this different way actually strengthens our visual communications with one another, and this can’t be achieved as long as proportions are ignored.

    For examples of what I mean, go to:
    http://www.thesevenfoldstudio.com/blog/

    1
  34. 45

    “Once an element reaches 500 pixels wide, it’s resized to 200 pixels, at which point the rule would no longer apply:”

    “.element (min-width: 500px) {
    width: 200px;
    }”

    This seems silly. Isn’t the obvious solution that the width is referring to the parent (available width)? That seems more analogous to how media queries work, where it’s measuring the viewport. Why would I be measuring the properties of the element upon which I’m setting properties? That seems like a recursion nightmare.

    If you want modularity, measure the properties of the available container for your element i.e. the parent element.

    2
    • 46

      I think this might be the more sensible solution. A previous commenter, James Kyle, suggested something similar, a @parent query that works like a @media query. The advantage of this is that it’d work equally well as @media and indeed could be a replacement for all size-based media queries. However, I’d still love to see it as a pseudo-class.

      0
  35. 47

    Hi there,

    I really want to use this for a website I’m designing. However, I am fairly new with professional web development(still in college) and I’m not sure what I need to do in the html to get this working. The elementyQuery file is in my website’s directory but do I have to link to them in the head of my html page? What do I have to put in the head of html page, if anything? For that matter, besides having the file in my directory, what setup overall do I have to apply?

    0
  36. 48

    I totally agree with this! CSS should totally work like this. Maybe CSS4

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top