One Web to Rule Them All: The Elastic Grid
This series is meant to be an in-depth look at Responsive Design. It covers the history, the how-to, and best practices on responsive design, taken from the view of someone who hates fluid layouts and has found a (seemingly) better solution. This session will be expounded upon in detail at PodCampNashville, then again in more detail at BlogWorldExpo later this year.
In case you’re wondering, here’s the road map for this week’s series:
- Introduction
- What Are Media Queries
- The Elastic Grid
- Best Practices for Responsive Design
- Podcamp Session: Wrap Up!
When last we spoke I had mentioned that I ended up releasing my core theme onto GitHub, and I’ve already gotten some fantastic feedback! I’d love to see what you guys are doing with it, because it’s a labor of love and it’s sort of strange just turning it out into the wild… so I want to see good results!
If you’ve looked at the theme, you may have an idea of what we’re going to talk about today, but if not, then let’s just dive right in.
I may have mentioned once or twice that I absolutely hate fluid layouts. With a firey passion that burns greater than a thousand suns, actually. When I saw all of the responsive layouts that were made with fluid backbones, I cringed. There had to be a way to retain the design integrity of a fixed layout and have the nice fluidity of a responsive layout.
Enter the “Elastic Grid”
Picture your typical layout:
You’ve got logos (black), navigation (grey), a slider (light grey), and footer widgets/columnized content (dark grey). Now, we need something that will hold a fixed amount of fluid… say, an aquarium:
So we’ve filled our aquarium with water, and are laying these items in it to “float” on the water… some are sitting on top of others, but for the most part you can see how the elements are stacked. We can assume, by the way, that each of these elements are a specific size. The upper logo, for example, is 2/16 of the full aquarium. We’re still going to think in pixels, but we know how many pixels now. The widgets are exactly 1/3 of the full width (this includes margin on both sides [except on the edges]).
Now, if we change the size of the container, the elements will change, but only slightly:
The elements may look a little shorter in width, but it still retains the same shape. This is our goal for tablet layouts; keep as much content on the screen without having to scroll.
But what happens when we drastically shrink our aquarium?
This is where a lot of fluid layouts start to really bug me, and where a true responsive design really shines. We’ve lost the original concept because the elements are just too skinny. What should happen is that the elements should stack on top of each other when the content area starts to become too skinny to be readable.
Notice our logo now spans the whole content region? That’s because the logo was small enough before that it really doesn’t change sizes – we may orient it differently, but it doesn’t shrink. The navigation now floats under the logo (and may take up either multiple lines or one line per menu item). The slider has shrunk in ratio to keep the images looking sharp, and the widgets now span the entire content width. But, the difference between this and some fluid layouts is that this layout will never show up unless you’re on a small screen.
Remember this?
[code]
/* #Media Queries
================================================== */
/* Smaller than standard 960 (devices and browsers) */
@media only screen and (max-width: 959px) {}
/* Tablet Portrait size to standard 960 (devices and browsers) */
@media only screen and (min-width: 768px) and (max-width: 959px) {}
/* All Mobile Sizes (devices and browser) */
@media only screen and (max-width: 767px) {}
/* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
@media only screen and (min-width: 480px) and (max-width: 767px) {}
/* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */
@media only screen and (max-width: 479px) {}
[/code]
Now you can make more sense of what we’re doing. This allows us to have a fixed layout that appears normal for both desktops and tablets, while giving us a stacked layout for phones (both tablet and landscape). We get the best view for all devices, while keeping the integrity of the design.
Code Dump, Ahoy!
OK, now that you see the media queries, let’s look at some actual CSS:
[code]
/* #Base 960 Grid
================================================== */
.container { position: relative; width: 940px; margin: 0 auto; padding: 0 10px; }
.container .column,
.container .columns { float: left; display: inline; margin-left: 10px; margin-right: 10px; }
.row { margin-bottom: 20px; }
/* Nested Column Classes */
.column.alpha, .columns.alpha { margin-left: 0; }
.column.omega, .columns.omega { margin-right: 0; }
/* Base Grid */
.container .one.column,
.container .one.columns { width: 40px; }
.container .two.columns { width: 100px; }
.container .three.columns { width: 160px; }
.container .four.columns { width: 220px; }
.container .five.columns { width: 280px; }
.container .six.columns { width: 340px; }
.container .seven.columns { width: 400px; }
.container .eight.columns { width: 460px; }
.container .nine.columns { width: 520px; }
.container .ten.columns { width: 580px; }
.container .eleven.columns { width: 640px; }
.container .twelve.columns { width: 700px; }
.container .thirteen.columns { width: 760px; }
.container .fourteen.columns { width: 820px; }
.container .fifteen.columns { width: 880px; }
.container .sixteen.columns { width: 940px; }
.container .one-third.column { width: 300px; }
.container .two-thirds.column { width: 620px; }
/* Offsets */
.container .offset-by-one { padding-left: 60px; }
.container .offset-by-two { padding-left: 120px; }
.container .offset-by-three { padding-left: 180px; }
.container .offset-by-four { padding-left: 240px; }
.container .offset-by-five { padding-left: 300px; }
.container .offset-by-six { padding-left: 360px; }
.container .offset-by-seven { padding-left: 420px; }
.container .offset-by-eight { padding-left: 480px; }
.container .offset-by-nine { padding-left: 540px; }
.container .offset-by-ten { padding-left: 600px; }
.container .offset-by-eleven { padding-left: 660px; }
.container .offset-by-twelve { padding-left: 720px; }
.container .offset-by-thirteen { padding-left: 780px; }
.container .offset-by-fourteen { padding-left: 840px; }
.container .offset-by-fifteen { padding-left: 900px; }
[/code]
Look familiar? If you’re familiar with the 960 Grid system it should – the CSS is very similar. What we’re doing is starting off with a grid. A grid that we’ll change as soon as our size does.
On tablets, for example:
[code]
/* #Tablet (Portrait)
================================================== */
/* Note: Design for a width of 768px */
@media only screen and (min-width: 768px) and (max-width: 959px) {
.container { width: 748px; }
.container .column,
.container .columns { margin-left: 10px; margin-right: 10px; }
.column.alpha, .columns.alpha { margin-left: 0; margin-right: 10px; }
.column.omega, .columns.omega { margin-right: 0; margin-left: 10px; }
.alpha.omega { margin-left: 0; margin-right: 0; }
.container .one.column,
.container .one.columns { width: 28px; }
.container .two.columns { width: 76px; }
.container .three.columns { width: 124px; }
.container .four.columns { width: 172px; }
.container .five.columns { width: 220px; }
.container .six.columns { width: 268px; }
.container .seven.columns { width: 316px; }
.container .eight.columns { width: 364px; }
.container .nine.columns { width: 412px; }
.container .ten.columns { width: 460px; }
.container .eleven.columns { width: 508px; }
.container .twelve.columns { width: 556px; }
.container .thirteen.columns { width: 604px; }
.container .fourteen.columns { width: 652px; }
.container .fifteen.columns { width: 700px; }
.container .sixteen.columns { width: 748px; }
.container .one-third.column { width: 236px; }
.container .two-thirds.column { width: 492px; }
/* Offsets */
.container .offset-by-one { padding-left: 48px; }
.container .offset-by-two { padding-left: 96px; }
.container .offset-by-three { padding-left: 144px; }
.container .offset-by-four { padding-left: 192px; }
.container .offset-by-five { padding-left: 240px; }
.container .offset-by-six { padding-left: 288px; }
.container .offset-by-seven { padding-left: 336px; }
.container .offset-by-eight { padding-left: 384px; }
.container .offset-by-nine { padding-left: 432px; }
.container .offset-by-ten { padding-left: 480px; }
.container .offset-by-eleven { padding-left: 528px; }
.container .offset-by-twelve { padding-left: 576px; }
.container .offset-by-thirteen { padding-left: 624px; }
.container .offset-by-fourteen { padding-left: 672px; }
.container .offset-by-fifteen { padding-left: 720px; }
}
[/code]
Notice how we keep the same classes, but just change their width. It’s not quite a LESS approach, but it’s getting there.
And finally the drastic change for mobile:
[code]
/* #Mobile (Portrait)
================================================== */
/* Note: Design for a width of 320px */
@media only screen and (max-width: 767px) {
.container { width: 280px; }
.container .columns,
.container .column { margin: 0; }
.container .one.column,
.container .one.columns,
.container .two.columns,
.container .three.columns,
.container .four.columns,
.container .five.columns,
.container .six.columns,
.container .seven.columns,
.container .eight.columns,
.container .nine.columns,
.container .ten.columns,
.container .eleven.columns,
.container .twelve.columns,
.container .thirteen.columns,
.container .fourteen.columns,
.container .fifteen.columns,
.container .sixteen.columns,
.container .one-third.column,
.container .two-thirds.column { width: 300px; }
/* Offsets */
.container .offset-by-one,
.container .offset-by-two,
.container .offset-by-three,
.container .offset-by-four,
.container .offset-by-five,
.container .offset-by-six,
.container .offset-by-seven,
.container .offset-by-eight,
.container .offset-by-nine,
.container .offset-by-ten,
.container .offset-by-eleven,
.container .offset-by-twelve,
.container .offset-by-thirteen,
.container .offset-by-fourteen,
.container .offset-by-fifteen { padding-left: 0; }
}
/* #Mobile (Landscape)
================================================== */
/* Note: Design for a width of 480px */
@media only screen and (min-width: 480px) and (max-width: 767px) {
.container { width: 400px; }
.container .columns,
.container .column { margin: 0; }
.container .one.column,
.container .one.columns,
.container .two.columns,
.container .three.columns,
.container .four.columns,
.container .five.columns,
.container .six.columns,
.container .seven.columns,
.container .eight.columns,
.container .nine.columns,
.container .ten.columns,
.container .eleven.columns,
.container .twelve.columns,
.container .thirteen.columns,
.container .fourteen.columns,
.container .fifteen.columns,
.container .sixteen.columns,
.container .one-third.column,
.container .two-thirds.column { width: 420px; }
}
[/code]
See how all the columns are just given the same width? That was the whole idea – we stack on top of each other the elements that would float side-by-side in a larger container.
This code is taken directly from the Skeleton framework, in my opinion one of the best elastic grid frameworks out there, and by far the easiest to design for (especially if you’re used to the 960 grid!)
Tomorrow we (finally) finish the series by looking at some examples, and Saturday if you’re in Nashville you can pop by PodCampNashville for a wrapup!