- September 15, 2016
Autolayout
I’ve had a love-hate relationship with grid systems over the years. Every system I try to standardize on becomes bloated, forgotten, or yesterday’s news. I find myself constantly switching to the next best thing. What follows isn’t a proclamation that this new system is the best, or that you should drop everything and switch. Instead, allow me to walk you through my grid system evolution so that we may all learn from it.
Back in the “early days,” I rolled my own system using floats and fixed widths. It worked great, for the time, and my class names were crazy explicit. Things like news-listing
created a layout and floated news-items
the way news items should be floated. Inevitably, the project would grow and we’d end up adding “stories.” Now, Stories were totally different from News (I thought) and re-using the news-listing
didn’t make much sense. Being the semantic developer I was, I added a stories-listing
and copied and pasted the layout code over from the news-listing
class. Ugh.
Then 960.gs came out and I jumped at the chance to not have to maintain layout code any more. With a grid framework in place, my user code was only concerned with the design of the on-page components—not, necessarily, where those components tiled. Best of all, when Happy Cog handed off our source code to a client team, they could dive into the 960.gs documentation and didn’t have to spend time learning what news-listing
meant by grepping my code.
The switch to a documented grid system wasn’t without trade-offs, though. With my custom code I was free to create layouts of any width. Want to float a column three-and-a-half grids? It’s easy when you’re defining percentages yourself in your site’s CSS. Moving to 960.gs,we lost that and ended up with this weird mix of some standard and some custom grids.
Then Sass came out and I dove into all its plugins like Compass and Neat/Bourbon. For a time this was even better than 960.gs. It provided me with all the layout abstraction I was used to with 960.gs but moved the implementation of the grid out of the vendor directory and into the site’s code. This change meant that I could manage all my layout in my SCSS and didn’t have to worry about some standard and some custom layouts. I again had control over each layout.
Even with Neat I found myself missing the flexibility of a completely custom system like I had originally started with. For example, Neat sets its grid entirely with percentages. Because of this, your layout needs to be aware of the containing grid to use the correct gutters. E.g. A layout at the top of your page (on a 12 column grid) could set its columns to 4/12 and you’d end up with 1/3 splits. However, if you nest that same layout into half the page you’d have to adjust your 4/12 code into a 2/6 to retain the correct gutter. (It’s 2/6 because you’re dealing with half a page, 6 columns, and you’d like 1/3 of that.) Ugh.
So, I abandoned Neat and went back to a custom implementation that allowed me to define my grids with exact percentages. We’re still designing with a grid, but from a development perspective we have a bit more freedom to break out of the grid when needed. Say our grid is 12 columns wide and we want 1/3 splits—we can set columns to be 33.3333%. If, however, you’d like to split 12 columns by 5 you can set the width to 20%. This adds some responsibility to the developer to ensure the percentages they’re using align to the grid, but that’s a worthwhile tradeoff, in my opinion.
For a time, again, things were good. But I noticed there was a lot of boilerplate in my layouts. Having done some iOS development from time to time I started to enjoy using the string based Autolayout syntax. In iOS it’s as easy as,
|-[find]-[findNext]-[findField(>=20)]-|
That asks for two buttons with the standard 8px spacing and a text field that is at least 20px wide.
What if we could do the same in CSS?
|-[column]-[column]-|
That asks for two evenly spaced columns with a standard gutter between.
And, what if we could do something much more complex:
|-[column(25%)]-100px-[column(50%)]-[column(25%)]-|
That asks for three columns with a wider middle column and a wider than standard gutter.
So, I went ahead and built it. Paul and I then implemented it and have been using it on an in-development project for the past few weeks. It took the shape of a Sass mixin used like this:
@include autolayout('|-[column]-[column]-|');
So far it has worked well. We’re happy because we have a custom grid again with the reduced boilerplate of a grid abstraction library. Now if only it had some documentation…
Note: we didn’t consider responsive states in this because we’ve been using and really enjoying @include media()
. With it we can do,
@include media('<700px') { @include autolayout('|-[column]-|'); }
@include media('>=700px') { @include autolayout('|-[column(25%)]-[column(75%)]-|'); }