Simulating Element Queries
Until real element queries show up in a specification or a browser, these are the simulated techniques that I’m aware of. Am I missing others? Let me know.
Evaluating the pros and cons of each technique may help you decide which ones works best in your situation.
Technique #1: Window Resize Events
addEventListener('resize', function () {
var
elements = document.querySelector(element_selectors),
width = window.innerWidth;
// do stuff
});
Pros
- Will fire on all window size changes.
- May be used to select individual elements.
- Will work in legacy browsers with nominal polyfilling.
Cons
- Does not detect when elements change size without the window resizing.
- May fire way too often, to the point of necessitating a throttle.
- May require expensive element checks and/or element sizing checks.
Technique #2: Media Query Events
// fires when the query goes from true to false or vice versa
matchMedia('(max-width: 640px)').addListener(function (q) {
var elements = document.querySelectorAll(element_selectors);
// do stuff
});
Pros
- May be used to modify individual elements.
- Will only fire when specific breakpoints occur.
- Will work in legacy browsers with some polyfilling.
Cons
- Does not detect when element changes size without window resize.
- Limited to specific breakpoints.
Technique #3: Polling
requestAnimationFrame(function () {
var
elements = document.querySelector(element_selectors),
width = window.innerWidth;
// do stuff
});
Pros
- May be used to detect when individual elements change size.
- Will work in legacy browsers with nominal polyfilling.
Cons
- Will fire way too often, probably 60 times a second, no matter what.
- May require expensive element checks and/or element sizing checks.
Technique #4: Iframe Media Query Events
NodeList.prototype.forEach = Array.prototype.forEach;
document.querySelectorAll(element_selectors).forEach(function (element) {
// inject a hidden iframe for each element
var iframe = element.appendChild(document.createElement('iframe'));
iframe.style.cssText = 'border:0;height:100%;position:absolute;width:100%;z-index:-1';
iframe.contentWindow.matchMedia(query).addListener(function (media) {
// do stuff
});
});
Pros
- Fires on all element size changes.
- Works in legacy browsers with some polyfilling.
Cons
- Requires a
position
ofrelative
,absolute
, orsticky
on the element. - May add
<iframe>
elements all over the page. - May upset
:nth-child
selectors. - May fire too often.