Bevan did a great job on the dConstruct website. I tried to help him out along the way, which mostly involved me doing a swoop’n’poop code review every now and then.
I was particularly concerned about performance so I suggested base-64 encoding background images wherever possible and squeezing inline images through ImageOptim. I also spotted an opportunity to do a bit of conditional loading.
Apart from the home page, just about every other page on the site features a fairly hefty image in the header …if you view it in a wide enough browser window. If you’re visiting with a narrow viewport, an image like this would just interfere with the linearised layout and be an annoying thing to scroll past.
So instead of putting the image in the markup, I put a data-img
attribute on the body
element:
<body data-img="/img/conference.png">
Then in a JavaScript file that’s executed after the DOM has loaded, I check to see if the we’re dealing with a wide-screen viewport or not. Now, the way I’m doing this is to check to see if the header is linearised or if it’s being floated at all—if it’s being floated, that means the layout styles within my media queries are being executed, ergo this is a wide-screen view, and so I inject the image into the header.
I could’ve just put the image in the markup and used display: none
in the CSS to hide it on narrow screens but:
- that won’t work for small-screen devices that don’t support media queries, and
- the image would still be downloaded by everyone even if it isn’t displayed (a big performance no-no).
I’m doing something similar with videos.
If you look at a speaker page you’ll see that in the descriptions I’ve written, I link to a video of the speaker at a previous conference. So that content is available to everyone—it’s just a click away. On large viewports, I decided to pull in that content and display it in the page, kind of like I’m doing with the image in the header.
This time, instead of adding a data-
attribute to the body, I’ve put in a div
(with a class
of “embed” and a data-src
attribute) at the point in the document where I want to the video to potentially show up:
<div class="embed" data-src="//www.youtube.com/embed/-2ZTmuX3cog"></div>
There are multiple video providers—YouTube, Vimeo, Blip—but their embed codes all work in much the same way: an iframe
with a src
attribute. That src
attribute is what I’ve put in the data-src
attribute of the embed
div
.
<div class="embed" data-src="//player.vimeo.com/video/33692624"></div>
Once again, I use JavaScript after the DOM has loaded to see if the wide-screen media queries are being applied. This time I’m testing to see if the parent of the embed
div
is being floated at all. If it is, we must be viewing a widescreen layout rather than the linearised content. In that case, I generate the iframe
and insert it into the div
:
(function(win){
var doc=win.document;
if (doc.getElementsByClassName && win.getComputedStyle) {
var embed = doc.getElementsByClassName('embed')[0];
if (embed) {
var floating = win.getComputedStyle(embed.parentNode,null).getPropertyValue('float');
if (floating != 'none') {
var src = embed.getAttribute('data-src');
embed.innerHTML = '<iframe src="'+src+'" width="320" height="180" frameborder="0"></iframe>';
}
}
}
})(this);
In my CSS, I’m then using Thierry Koblentz’s excellent technique for creating intrinsic ratios for video to make sure the video scales nicely within its flexible container. The initial video proportion of 320x180 is maintained as a percentage: 180/320 = 0.5625 = 56.25%:
.embed {
position: relative;
padding-bottom: 56.25%;
height: 0;
}
.embed iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
The conditional loading is working fine for the header images and the embedded videos, but I still feel a bit weird about testing for the presence of floating.
I could use matchMedia instead but then I’d probably have to use a polyfill (another performance hit), and I’d still end up maintaining my breakpoints in two places: once in CSS, and again in JavaScript. Likewise, if I just used documentElement.clientWidth
, I’d have to declare my breakpoints twice.
Paul Hayes wrote about this issue a while back:
We need a way of testing media query rules in JavaScript, and a way of generating events when a new rule matches.
He came up with the ingenious solution of using transitionEnd
events that are fired by media queries. The resulting matchMedia
polyfill he made is very clever, but probably overkill for what I’m trying to do—I don’t really need to check for resize events for what I’m doing.
What I really need is some kind of otherwise-useless CSS declaration just so that I can test for it in JavaScript. Suppose there were a CSS foo
declaration that I could use inside a media query:
@media screen and (min-width: 45em) {
body {
foo: bar;
}
}
…then in JavaScript I could test its value:
var foovalue = window.getComputedStyle(document.body,null).getPropertyValue('foo');
if (foovalue == 'bar') {
// do something
}
Of course that won’t work because foo
wouldn’t be recognised by the browser so it wouldn’t be available to interrogate in JavaScript.
Any ideas? Maybe something like zoom:1
? If you can think of a suitable CSS property that could be used in this way, leave a comment.
Of course, now that I’m offering you a textarea to fill in with your comments, you’re probably just going to use it to tell me what’s wrong with the JavaScript I’ve written …those “comments” might mysteriously vanish.