CSS3 media queries with dynamic viewport width

I’ve only recently started using CSS3 media queries in order to target mobile devices, but I found it so easy I wondered why I hadn’t got around to it before. Essentially it boils down to something like this inside your CSS file:

@media only screen and (max-width: 480px) {
	body {
		background:#fff;
		margin: 0;
	}
}

Here, the two declarations for body are only applied if the device’s width is 480px or less. But beware before you start relating that to screen resolutions since CSS pixels are an abstract concept which have little relation to the pixel density of the device. This is actually rather handy since we don’t need to panic about super high res phones- generally they’ll have the same/similar CSS pixel count to a lower resolution device- meaning it’s pretty much one size fits all in our declarations. 480px should cover phones in both portrait and landscape. See Quirksmode’s rather interesting article ‘A pixel is not a pixel is not a pixel‘ for more.

While that’s all well and good, it turns out some simple boilerplate HTML is needed in the head of the document to make the layout fit nicely on mobile devices:

<meta name="viewport" content="width=device-width" />

This tells the mobile browser that the viewport should be the same width as that of the device. This avoids it loading up the page with a much bigger viewport- essentially zoomed out. If you’ve designed a simple mobile layout this can deceiving as it just looks like your text is small. But with the magic meta viewport delcaration in the head, all is well!

At least at first glance.

The thing is, the CSS media query above (purposely) excludes tablet sized devices. I wanted to serve up the standard desktop site on tablets since it works better than the overly simplistic mobile version. But here’s the thing: as I set the viewport to the width of the device, part of my desktop site got cut off on tablets. This is understandable since my site IS wider than the device. But, the device is perfectly capable of displaying it nicely if it just zooms out a little. My design is 1024px and allowing for some slight breathing space, a viewport of around 1080px works well. So of course I tried:

<meta name="viewport" content="width=1080" />

Perfect! On tablets at least, but then on a mobile phone my site no longer fitted the device… so it turned out that I needed the viewport to change dependent upon the width of the device. And Quirksmode was able to come to the rescue again by pointing out that changing the viewport with some JavaScript does work on most mobile browsers (bar FireFox).

So I just needed to pop an ID on my meta viewport tag (to make it super easy to find with JS) and this little script in the head of my document:

if (screen.width > 480) {
	var viewport = document.getElementById('viewport');
	viewport.setAttribute('content','width=1080');
}

Which solves the issue. As Firefox has such a tiny share of the tablet browser space, I doubt I’ll lose any sleep over such users having to pan around/zoom out a little (that’s about as graceful as any fallback gets).

However, I was also using Drupal for the project so I needed a way to get this custom code into the header (preferably in the most legit way possible). And the most legit way I found is (drumroll please)… implementing template_preprocess_page in your template.php file as follows:

function template_preprocess_page(&$variables) {
	$element = array(
		'#tag' => 'meta',
		'#attributes' => array(
			'id' => 'viewport',
			'name' => 'viewport',
			'content' => 'width=device-width, initial-scale=1.0'
		)
	);
	drupal_add_html_head($element, "viewport");
	
	drupal_add_js("if (screen.width > 480) {
			var viewport = document.getElementById('viewport');
			viewport.setAttribute('content','width=1080');
		}", 'inline');
}

Replace the template_ prefix with (your theme name)_ to keep up with current Drupal parlance of course. I also plopped for putting initial-scale=1.0 in the meta tag to ensure that the page is initially zoomed correctly.

Reasons why you might not need this:

  • You want to serve your mobile site to phone and tablet users- just increase the max-width in your CSS3 media query accordingly and use a viewport set to the device width
  • You want to serve up one site for mobile users and another for desktop/tablet users. Set the viewport width of your mobile site to device-width and the viewport of the mobile/desktop version to the width of your site. Tablets will obey, desktop browsers don’t care- simple.
This entry was posted in Drupal, JavaScript. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>