Letting users disable responsive layout

It’s great that media queries allow us to adapt the layout of our sites to the users’ viewport size, a.k.a. Responsive Web Design. However, some argue that doing so comes with a (slight) risk of confusing some people that don’t expect viewport width to make the layout change as drastically as media queries allow.

While I don’t think this affects a large number of people, it’s quite possible that people who do not know what responsive web design is (i.e. the vast majority of people) can be confused by a site looking radically different on their computer that on their tablet or smartphone. Bruce Lawson mentions an example of this in Turning off responsive web design, and I’ve heard other similar stories.

A colleague mentioned another case when a responsive layout is not always ideal—client support. Support issues from clients often mention layout issues or change requests. If you get a support email referring to the desktop layout while away from your desktop computer you may not be able to see the same thing on your tablet or smartphone, so you’ll have to postpone responding. Sure, it’s an edge case, but one in which being able to turn off the responsive layout would be useful.

Despite having the feeling that it wouldn’t benefit a large number of people, implementing a switch to toggle a website’s responsiveness on and off isn’t really a lot of work. So in a couple of projects I have done that, and thought I’d share how. The approach is pretty similar to what Adrian Roselli describes in Letting Mobile Users See Desktop View of RWD Site. It’s not very complicated, and neither is it revolutionary, but as with most things there are different ways of getting there.

Naming the switch

The trickiest part is probably what to call the switch. Phrases like “View desktop layout”, “Go to desktop version” and “View full site” seem like saying that what you’re currently viewing is missing something. So instead I called it “View fixed width layout” (and “View flexible width layout” to toggle back). I don’t really know if it helps end users understand the difference, but I think it’s a more accurate description than using “desktop” and “mobile”. Someone’s browser window being narrower than 960 pixels, or 1200 pixels, or wherever you choose to draw the line, does not necessarily mean they’re using a “mobile” device.

HTML and CSS

I made a Disable responsive layout demo page to show how what I implemented works. If you load the page and then make the browser window narrower than 960 pixels, a text and a switch link will show up. I feel that there’s no need to show the switch unless any media queries are applied—if the responsive design doesn’t affect your browser, there’s nothing to switch off.

I chose to put the switch link in the HTML source code instead of inserting it with JavaScript. That’s because I’ve let the back-end (could be any server-side language of course, but in the demo I’ve used PHP) handle the cookie that gets set if you choose to disable the responsive layout.

On the actual demo page there is more content inside the #toggle element, but the necessary HTML is this:

<div id="toggle">
	<a href="?fixedwidth=1">Switch to fixed width layout</a>
</div>

In the CSS that all browsers use (i.e. not inside any media query) are these rules:

#toggle {
	display:none;
}
.fixed #toggle {
	display:block;
}

This simply hides the entire toggle element unless the HTML element has the class name “fixed”. If it has this class name it means that the user has opted out of the responsive layout, so the switch needs to be visible so they can enable it again.

The following snippet is inside a CSS file that contains the media queries:

@media only screen and (max-width:960px) {

	#toggle {
		display:block;
	}

}

This displays the switch when the media query is triggered, in this case when the viewport is narrower than 960px. If the user has disabled the responsive layout, this CSS file isn’t loaded at all (I’ll show how later).

If your media query CSS is not in a separate file, either by preference or because you have concatenated all CSS files, it will require a bit more work to prevent those rules from being applied. You could prefix all rules inside media queries with html:not(.fixed) or make your concatenation process create a separate file without any media queries for this purpose.

JavaScript

If the media query CSS is disabled, you’ll also want to make sure to disable any JavaScript that doesn’t make sense in a non-responsive layout or needs rules defined in the CSS file that doesn’t get loaded. In case you have those scripts in a separate file, you can use the same technique as for the CSS (described below in the PHP section) and simply not load the file. If you don’t use a separate file, check for the fixed class name on the html element before initiating the responsive scripts:

<script>
if ( !document.documentElement.className.match(/(\\s|^)fixed(\\s|$)/) ) {
	// Responsive scripts go here, likely with additional checks
	// for viewport width, media query support etc.
}
</script>

PHP

In this demo I use PHP to handle the cookie and the markup changes that are necessary to disable the responsive layout. You could use JavaScript for this if you feel that it’s ok that it won’t work for users with JavaScript disabled. It’s not critical functionality, after all. If you do choose to use JavaScript, remember to also let the script insert the switch or people with JavaScript disabled will see a link that does nothing and leads nowhere.

Here’s a basic HTML structure with the necessary PHP in place:

<?php
	$fixedwidth = '';
	// Check if the query string contains our key and assign its value to $fixedwidth
	if ( isset($_GET['fixedwidth']) && ($_GET['fixedwidth'] != "") ) {
		$fixedwidth = $_GET['fixedwidth'];
	}
	// Check if a cookie has already been set
	if ( isset($_COOKIE['fixedwidth']) ) {
		if ( $fixedwidth == '0' ) {
			// If the value is '0', delete the cookie
			setcookie('fixedwidth', '', time() - 60, '/');
		} else {
			// Value is not '0', so no need to get the cookie value
			$fixedwidth = '1';
		}
	} else if ( $fixedwidth == '1') {
		// The user wants fixed width, so set a cookie
		$expires = 60 * 60 * 24 * 60 + time();
		setcookie('fixedwidth', '1', $expires, '/');
	}
?>
<!DOCTYPE html>
<html lang="en" <?php if ($fixedwidth == '1') { echo 'class="fixed"'; } ?>>
<head>
	<meta charset="utf-8" />
	<title>Document title</title>
<?php
// Only insert the meta[name="viewport"] element if responsive is not disabled
if ( $fixedwidth != '1' ): ?>
	<meta name="viewport" content="width=device-width, initial-scale=1" />
<?php endif; ?>
	<link rel="stylesheet" href="main.css" />
<?php
// Only load the CSS file containing media queries if responsive is not disabled
if ( $fixedwidth != '1' ): ?>
	<link rel="stylesheet" href="mq.css" />
<?php endif; ?>
</head>
<body>
	<h1>Document title</h1>
	<div id="toggle">
<?php
// Responsive is disabled, so insert a switch to flexible width
if ( $fixedwidth == '1' ): ?>
		<a href="<?php echo $_SERVER["SCRIPT_NAME"] ?>?fixedwidth=0">Switch to flexible width layout</a>
<?php
// Responsive is not disabled, so insert a switch to fixed width
else: ?>
		<a href="<?php echo $_SERVER["SCRIPT_NAME"] ?>?fixedwidth=1">Switch to fixed width layout</a>
<?php endif; ?>
	</div>
	<script>
	if ( !document.documentElement.className.match(/(\\s|^)fixed(\\s|$)/) ) {
		// Responsive scripts go here
	}
	</script>
</body>
</html>

I’m sure the PHP can be improved upon, but I hope you get the idea.

Should this be a user agent setting?

You could argue that browsers could (or should) let users switch between responsive or not. I’m not so sure it would always work though. Browsers would likely need to disable their media query support for it to work and rely on sites to display the “full width” or “desktop” layout by default. That’s how I personally like to develop sites, but some developers use a reverse, “mobile first” approach which requires media query support to display the “desktop layout”.

Another issue is if you’re Using media queries to hide CSS3 from older browsers. A browser switch that completely disables media queries would likely disable any rules inside viewport-independent media queries as well, which could cause plenty of layout issues depending on what you’re hiding in there.

In other words I think this problem is something we web developers need to handle. If it needs to be handled at all, that is.

Posted on March 25, 2013 in CSS