Cross-browser responsive design without media queries

By · June 7, 2013 · 0 comments

...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>

Get the latest posts delivered to your inbox.

Comments

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

Leave a Comment

All comments are moderated and rel="nofollow" is in use. Avatars are sourced from gravatar.com – a globally recognised avatar.

Type the numbers from the picture above

About me
John Avis ...mostly about web development and programming, with a little bit of anything else related to the Internet, computers and technology.

profile for John at Stack Overflow, Q&A for professional and enthusiast programmers
Subscribe

Get the latest posts delivered to your inbox. *