Cross-browser responsive design without media queries

johna by | June 7, 2013 | Responsive Web Design Jquery/Javascript Web Development

...Or an alternative to media queries for responsive design


I really like the concept of responsive design, and I have read a lot of the positive stuff about it, and also read a lot of the negative too.

Despite the negatives, I do think that responsive design is the way of the future (and now), but it seems that it is far from easy to get right.

I'm taking my first steps in responsive design now, but one of the first issues I encountered is browser compatibility for CSS3 media queries. The Google Analytics statistics for most of the sites I maintain still show enough users with Internet Explorer 8 that I still need to consider these browsers during development.

I have looked at some of the well-known fixes but the idea of requesting my CSS files by AJAX and parsing them doesn't sound too efficient, even though it will only happen with IE8 and below.

An alternative is to use JavaScript or jQuery to handle the change of display size for all browsers, and I put something together quickly to do this. As the experimental work I have done so far has only involved using "max-width", my jQuery example presented here works only that way.

It works simply by applying classes to a specified tag (default is BODY tag). So if you have breakpoints set at 500 pixels and 300 pixels, it will apply no classes at 600 pixels, the 500 pixel class (which you specify) once the display width is less than or equal to 500 pixels, and both the 500 and 300 pixels classes when the display width is less than or equal to 300 pixels. It adjusts classes on document ready and when the browser is resized.

Here's the code and a sample (jQuery required):

<script type="text/javascript">
(function ($) {
jQuery.responsive = function (options) {
var settings = $.extend({
breakpoints: [],
container: "body"
}, options);
$(window).resize(function () {
respond();
});
respond();
function respond() {
for (var i = 0; i < settings.breakpoints.length; i++) {
if ($(window).width() <= settings.breakpoints[i][0]) {
$(settings.container).addClass(settings.breakpoints[i][1]);
}
else {
$(settings.container).removeClass(settings.breakpoints[i][1]);
}
}
};
}
})(jQuery);

//Sample usage - adds two breakpoints and applies class to BODY tag
$(function () {
$.responsive({
//array with max-width in pixels, and class to apply
breakpoints: [[980, "mw980"], [480, "mw480"]]
//optional specify container to apply classes to, default is body
//,container: "#wrapper"
});
});
</script>

I mocked up a couple of samples, one using media queries and my alternative using jQuery:

Example using media queries

Example using jQuery

They should appear and operate identically in all browsers, except IE8 and below where the media queries example will not work as designed.

Update: I have since redesigned my blog using this technique. I also added support for min-width. You can look at the source of this page to see updated code.

Update: I found that one of the disadvantages of using this technique is that the adding of classes does not happen until document ready. This means that there can be a delay in applying the classes which is visible to the user. To solve this problem I suggest adding a second script using native JavaScript to add the classes immediately after the BODY open tag (or whichever tag has the clases applied). Example (also applied to this website):

var container = "body"; //must be ID
var breakpoints = [
["max-width", 650, "max650"],
["min-width", 986, "min986"]
];
for (var i = 0; i < breakpoints.length; i++) {
if (breakpoints[i][0] == "max-width") {
if (window.innerWidth <= breakpoints[i][1]) {
document.getElementById(container).className = breakpoints[i][2];
}
}
else if (breakpoints[i][0] == "min-width") {
if (window.innerWidth >= breakpoints[i][1]) {
document.getElementById(container).className = breakpoints[i][2];
}
}
}


I've actually created some ASP.NET server controls to handle this in some of the projects I am working on. Let me know if you're interested in seeing that.

Update:

I have created a pure JavaScript version of the cross-browser responsive media query alternative code. This version should be placed immediately after the opening tag for the element that classes are to be applied. The id of that element and the breakpoints need to be adjusted to your requirements. Here's an example:

<script type="text/javascript">
function hasClass(el, cls) {
return el.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
function addClass(el, cls) {
if (!this.hasClass(el, cls)) el.className += " " + cls;
}
function removeClass(el, cls) {
if (hasClass(el, cls)) {
var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
el.className = el.className.replace(reg, ' ');
}
}

var addEvent = function (elem, type, eventHandle) {
if (elem == null || elem == undefined) return;
if (elem.addEventListener) {
elem.addEventListener(type, eventHandle, false);
} else if (elem.attachEvent) {
elem.attachEvent("on" + type, eventHandle);
} else {
elem["on" + type] = eventHandle;
}
};

function responsive() {
var w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;

for (var i = 0; i < breakpoints.length; i++) {
if (breakpoints[i][0] == "max-width") {
if (w <= breakpoints[i][1]) {
addClass(document.getElementById(id), breakpoints[i][2]);
}
else {
removeClass(document.getElementById(id), breakpoints[i][2]);
}
}
else if (breakpoints[i][0] == "min-width") {
if (w >= breakpoints[i][1]) {
addClass(document.getElementById(id), breakpoints[i][2]);
}
else {
removeClass(document.getElementById(id), breakpoints[i][2]);
}
}
}
}

var resizeTimeoutId;

function resized() {
window.clearTimeout(resizeTimeoutId);
resizeTimeoutId = window.setTimeout('responsive();', 10);
}

var id = "body";
var breakpoints = [["max-width", 630, "max630"], ["min-width", 1890, "min1890"]];

addEvent(window, "resize", resized);

responsive();
</script>

Related Posts

Web Development

How to set up a debugging using the Turnkey Linux LAMP stack and VS Code

by johna | December 19, 2023
The second part in my guide to setting up a website and database using the Turnkey Linux LAMP stack.

Website Hosting Web Development

How to set up a website and database using the Turnkey Linux LAMP stack

by johna | November 18, 2023
If you need to host your own website for the purposes of web development, Turnkey Linux LAMP Stack is an easy to install all-in-one solution that you can set up on a spare computer or a VM (Virtual Machine).

Web Development

Intermittent "Unable to read data from the transport connection: net_io_connectionclosed" errors

by johna | May 6, 2020
If you are having intermittent problems sending email in .NET using System.Net.Mail consider switching libraries.

Comments

There are no comments yet. Be the first to leave a comment!

Leave a Comment

About

...random postings about web development and programming, Internet, computers and electronics topics.

I recommend ASPnix for web hosting and Crazy Domains for domain registration.

Subscribe

Get the latest posts delivered to your inbox.