Rearrange content when it’s too wide with jquery
Sep 17, 2012 | In jQuery, Tutorials |Media queries have proven to be extremely useful in responsive layouts. However, they do have a drawback: they can’t analyze the content on the page before deciding when to kick in. For example, if you have a fluid layout, CSS doesn’t know exactly what width the container has when the browser has a width of, for example, 742px. Javascript does. In this post, I’ll show how javascript can be used to make layouts even smarter and more adaptable.
HTML
The example we’ll be creating today is just the top of a web page – it will contain the title of the site and the navigation menu. That means the HTML is fairly straightforward.
<header> <h1>The title of the site</h1> <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">Portfolio</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> </nav> </header>
Header just contains everything, the “h1″ is the title of the site, and the “nav” contains the navigation menu. Feel free to add whatever you want to the HTML – the beauty of this script is that it will work no matter what you have in there.
CSS
In the CSS, we’ll first style the elements to look a certain way, and then we’ll add classes that will be applied to the elements when there isn’t enough space.
We’ll start off with some basic styling.
body { font-family: Arial; font-size: 15px; line-height: 25px; color: #595959; background: #f8f8f8; }
Now, the header. We’ll give this a percentage width of 60% to demonstrate the capabilites of the javascript we’ll write in a moment. You can set this to whatever you want, but I would suggest sticking with 60%.
header { width: 60%; min-width: 260px; height: 50px; margin: 0 auto; margin-top: 30px; background: #fff; -webkit-box-shadow: 0px 0px 5px #888888; box-shadow: 0px 0px 5px #888888; -webkit-border-radius: 5px; border-radius: 5px; padding: 15px; }
The “header” has a width of 60%, and it doesn’t get any smaller than 260px, because anything less than that is just unreasonably small. The height is 50px, and we’re setting it because the elements inside are floated. It’s centered using “margin: 0 auto”, and is 30px from the top of the page, and after that are just some styles to make it look nice.
Next up, we’re going to style the “h1″ title inside the header.
h1 { font-size: 32px; line-height: 50px; float: left; }
The font-size is 32px because that’s a reasonable size for the title of a website, and its line height is 50px so that it’s centered in the header. Since the header has a height of 50px, anything inside with a line-height of 50px will be vertically centered, and that’s what’s happening with the title and the navigation.
Now, we just need the “nav” to float to the right.
nav { float: right; }
However, the content inside the nav still looks ugly. Let’s fix this.
nav ul li { display: inline; padding-left: 10px; line-height: 50px; }
Each “li” is displayed inline so that they can all be on one line, they’re all 10 pixels from each other, and the line-height is 50px so that they’re vertically centered.
Unfortunately, the links inside still look pretty bad.
nav ul li a { color: #515151; text-decoration: none; }
There. That nasty blue color is gone, and so is the underline. Much better.
At this point, everything is completely styled – but one thing is missing: the styles for the smaller, alternate versions of the header, the title, and the navigation.
Let’s make an alternate version of the header
.smallHeader { height: 100px; }
The height is now twice as tall as it was before, so that all the content inside still fits perfectly. Since the title and the navigation both have a line-height of 50px, and they’re on separate lines now, two rows of 50px is 100px.
Now, let’s make the title and the navigation both 100%, so they make the best use of the space availabe.
.smallTitle { width: 100%; text-align: center; } .smallNav { width: 100%; text-align: center; }
They’re both as wide as possible, and have their text-align set to center so that the text inside is… centered.
jQuery
Make sure you have a copy of jQuery before starting this part.
Here’s how the javascript will work: at the beginning, we’ll declare 3 variables – the width of the title, the width of the navigation, and the width of both of them added together.
$(document).ready(function(){ var origTitleWidth = $('h1').width(); var origNavWidth = $('nav').width(); var origSpaceTaken = origTitleWidth+origNavWidth; });
These 3 variables are declared before any changes happen to the three elements, so we have their original widths, and not the altered ones.
Next, we declare the “rearrange” function.
function rearrange(){ }
Now, we need to find out the width of the header to know whether or not to apply the modified styles to the title and the navigation.
function rearrange(){ var headerWidth = $('header').width(); }
Once we have the header width, we need to set up two “if” statements.
function rearrange(){ if(origSpaceTaken>headerWidth){ } if(origSpaceTaken<headerWidth){ } }
This handles both possibilites: either the space taken is larger than the space available, or it is smaller.
If the space taken up by the elements inside is too large for the space available, we need those elements to receive their alternate styling.
function rearrange(){ if(origSpaceTaken>headerWidth){ $('header').addClass('smallHeader'); $('h1').addClass('smallTitle'); $('nav').addClass('smallNav'); } if(origSpaceTaken<headerWidth){ } }
There. Now, if the header is too small, the elements inside are optimized for it. The other possibility is that they fit, so we don’t want the “small” classes.
function rearrange(){ if(origSpaceTaken>headerWidth){ $('header').addClass('smallHeader'); $('h1').addClass('smallTitle'); $('nav').addClass('smallNav'); } if(origSpaceTaken<headerWidth){ $('header').removeClass('smallHeader'); $('h1').removeClass('smallTitle'); $('nav').removeClass('smallNav'); } }
That makes sure that they have the proper styling when necessary.
Also, the function needs to be called to work.
rearrange();
Lastly, we need to set up a window resize function so that the script can change the elements without reloading the page.
$(window).resize(function(){ rearrange(); });
Now, as soon as the window is resized, the script can check to see if the elements inside fit or not, and can apply the right styles when necessary.
Here’s the completed code:
$(document).ready(function(){ var origTitleWidth = $('h1').width(); var origNavWidth = $('nav').width(); var origSpaceTaken = origTitleWidth+origNavWidth; function rearrange(){ var headerWidth = $('header').width(); if(origSpaceTaken>headerWidth){ $('header').addClass('smallHeader'); $('h1').addClass('smallTitle'); $('nav').addClass('smallNav'); } if(origSpaceTaken<headerWidth){ $('header').removeClass('smallHeader'); $('h1').removeClass('smallTitle'); $('nav').removeClass('smallNav'); } } rearrange(); $(window).resize(function(){ rearrange(); }); });
I can see this as being especially useful for themes and templates, where you don’t know what the buyer will have as their site title or their navigation. This way, the styles will be applied at the perfect moment. That’s the end of this tutorial – if you have any questions or comments, feel free to post them below and I’ll do my best to help you out.