Flexible & Semantic Grids with Compass
When I started working on a personal site for myself, I had two main goals in mind. First, I wanted a simple, hassle-free content management system. Second, I wanted a fluid & flexible design based on a grid. The first goal was easily solved by using toto. toto allows me to publish blog articles as .txt files via git. It's awesome and it's easy and it's not WordPress.
The second one was to take much more work, and I'm still working out its kinks. I knew that I didn't want to produce HTML that was cluttered with unsemantic class names like col-1, container, last, et cetera. I like my HTML elements to be called exactly what they are: things like "sidebar," "post," and of course "pretty_button."
<!-- ugly! -->
<div class="container">
<div class="post col-8">
<p>Blah blah...</p>
</div>
<div id="sidebar" class="col-4 last">
<p>Blah blah blah...</p>
</div>
</div>
I knew that using a tool like Compass would make creating a semantic grid-based layout much easier. Compass uses SASS, so I would just need to create some mixins to create grid columns:
mixin col($cols)
float: left
width: $cols * 70px
margin-right: 40px
So far, so good. I created some mixins called container, col, and last. All the basics of a grid-based layout. The challenge came with making this easy grid-based layout flexible and responsive. The revelation came when I realized that when SASS sees an @media declaration nested inside of something else, it makes the correct assumption that what I actually want it to do is to create an @media declaration and nest the object (that the @media is inside of in SASS) inside of that declaration. It's kind of an inversion. So:
@mixin col($cols)
width: $cols * 70px
@media (max-width: 640px)
width: 320px
#my_div
+col(8)
Actually compiles to:
#my_div { width: 560px; }
@media (max-width: 640px) {
#my_div { width: 320px; }
}
This brilliant little trick by SASS means that although I can set the width of any element to whatever number of columns is necessary, I can also choose how I want any element using this mixin to look when below a certain width (as triggered by a media query).
Combining this trick with a fluid design attained by setting the main content container's width using max-width and sizing columns in percentages rather than pixels, I get a fluid and responsive grid-based layout that can be paired with perfectly semantic HTML. Below is the full _grid.sass partial that takes care of the majority of the grid layout. There are some small overrides scattered throughout other partials and normal SASS files.
$container_width: 960
$gutter_width: 40
$container: $container_width * 1px
$gutter: ($gutter_width / $container_width) * 100%
$gutter_px: $gutter_width * 1px
$column: ($container_width - 11 * $gutter_width) / 12
@mixin container
max-width: $container
margin: 0 auto
overflow: hidden
@mixin col($cols:12)
width: ($cols * $column + ($cols - 1) * $gutter_width) / $container_width * 100%
margin-right: $gutter
float: left
@if $cols == 12
margin-right: 0
@media (max-width: 640px)
width: 100%
margin-right: 0
margin-left: 0
float: none
@mixin push($cols)
margin-left: ($cols * $column + ($cols - 1) * $gutter_width) / $container_width * 100%
@mixin last
margin-right: 0
Some widths are set as raw numbers first so that they can be used in either pixel or percentage form by multiplication.
So that's my grid system. There is definitely extra code generated in CSS with all of the @media declarations, but it makes building a system like this much easier and is worth the trade-off in my opinion.
You can view this entire blog's codebase on Github at https://github.com/jclem/jclem.net.
