Structuring CSS is not a trivial task, especially in large projects. Even smaller systems may become complex and hard to maintain when introduced to RWD. In this post I’ll describe how I approach implementing larger sets of CSS rules.
I’ve worked with web technologies professionally for about five years. Until this fall I also studied, which culminated with my thesis where I created a JavaScript framework that aimed at giving JS-developers tools to make applications using the Semantic Web. For myself I aim to work with the web professionally, and hope to do so for many, many years to come.
An aspect of my career is my work with CSS, which has proven to be a tool somewhat harder to master than first anticipated. One dimension is the building blocks described by the standards. Another dimension is how these standards are interpreted and implemented by the various browsers (and how their differences create headaches long after their release). Yet another dimension is how these rules are combined, giving leeway to several techniques that become de facto standards for how to solve certain problems that arise again and again.
Finally, there is the dimension of magnitude. As web projects grow, there is high probability that their CSS rules will grow too. As such, some ideas for how to keep your rules structured in an intuitive and clean way are nice to have. To help guide us, we can probably learn from knowledge amassed in our community. As web developers, we like to bundle that knowledge into acronyms that describe certain principles.
- DRY: If you’ve solved a problem once, re-use that solution.
- DRO: If others have solved a well-known, defined problem once, why don’t re-use their solution?
- SoC: Rules that grouped into sensible expressions are more easily reused.
I’ve focused these TLAs on the need of re-usability. The level of re-usability is, in my opinion, the number one driving force in helping us to keep our CSS rules maintainable. It may also help us in our design, as it may hint that certain design choices introduce unnecessary amount of CSS rules, and that we should try to reuse our existing first. This may lead to a more consistent design, keep us away from unnecessary clutter, and allow us to follow another principle that’s been abbreviated, namely YAGNI.
The structure
So, with all this in mind, how should the structure look like? My best tip is to draw upon the features of CSS, starting with selectors. The essence are ids, classes, tags, pseudo-selectors and the universal selector (*). Using this as base also corresponds better with CSS specificity which can be a real pain in the ass when not considered.
Another tip is to use a dynamic stylesheet language, like LESS or Sass, as they drastically ease the work of writing CSS by introducing variables, nesting, mixing, operators, and functions. Related to the latter is CSS framework that are aimed at authoring CSS, focusing more on introducing mixins for explicit use by the implementer. I can recommend Compass, but inuit.css may also be interesting to take a look at. Both of these are based on Sass, and currently I’m inclined to use Sass over LESS, but it really depends on your personal taste.
In addition to dynamic stylesheet languages and authoring CSS frameworks, there are several other kinds of frameworks that have a greater impact at guiding our design. On my workplace we’ve introduced Bootstrap with success, and it has increased the rate of prototyping tremendously. Other frameworks are YUI CSS, Foundation, Blueprint, and Skeleton. They also guide some decisions, which may be good or bad depending on how you look at it. Common for all are that they introduce specific design elements, such as typography, form styles, navigation elements, buttons, icons, etc, enabling you to get something good-looking quite fast. As such, I wouldn’t recommend combining them, as their use of semantics may differ.
A last slew of CSS frameworks are those targeting specific features. Perhaps the most popular these days, with RWD being such a trend, is the one focusing on grids. Popular amongst these are 960.gs, 1140px, and Less Framework 4. These are good starting points, and may be a easy template for people not good with design (myself included), but if you truly want something that is yours, then you need to look at how designers create grids. If you need more convincing, read The Infinite Grid at A List Apart, and/or if you want to learn a little bit more about the basics of grids, check out Rolling Your Own Grid Layouts on the Fly Without a Framework at Design Shack.
Now, lastly, there are guides such as OOCSS and SMACSS. These are extensive guides that may teach you one or two things about structuring CSS, and I recommend them both.
An example
Now, finally, lets look at an example, namely the structure used for the theme used by this blog (unless I’ve gone tired of it and changed it, of course), minimalist. It’s written in Sass, and makes use of Compass and a customized version of Bootstrap (thanks to their very nice customize-tool). One final note is that I use ems as the measure unit for my design.
The structure is as follows:
| lib |- bootstrap.min.scss |- bootstrap.scss | mixins |- grid.large.scss |- grid.medium.scss |- typography.scss | patterns |- block.large.scss |- block.medium.scss |- block.scss |- bootstrap.scss |- tags.medium.scss |- tags.scss | unique |- master.large.scss |- master.medium.scss |- master.scss |- rss.large.scss |- rss.scss | variables |- color.scss |- dimension.large.scss |- dimension.medium.scss |- dimension.scss | style.large.scss | style.medium.scss | style.scss
The five directories are lib, mixins, patterns, unique, and variables. These are included by the various style files, which themselves are linked to by using mediaquries in the tags, e.g. <link rel="stylesheet" type="text/css" media="all and (min-width: 30em)" href="minimalist/style.medium.css" />
. The only responsibility the style-files has, is to include the necessary files for the different modes, in the correct order. First of all the order ensures that dependencies are handled, secondly it reflects the CSS specificity, e.g.:
@import "compass/reset"; @import "lib/*"; @import "variables/*"; @import "mixins/*"; @import "patterns/*"; @import "unique/*";
The different style files represents the different steps, and somewhat mimics the width of a mobile, pad, and desktop viewport. But this is a truth with modifications, as I use em as the basic unit of the design, which means it really depends on whatever default font-size the user has.
This structure also allows me to reuse components between size-dimensions, as exemplified by mixins/grid.large.scss
that imports from mixins/grid.medium.scss
. This is done so that the *.large files uses the variables defined in variables/dimension.large.scss
, but reuses the components defined in grid.medium.
As minimalist is quite, well, minimal, it doesn’t contain that many rules (19,15KB altogether, with comments and not minimized), but I have pretty much the same setup at work, and there it works splendidly, with lots of lots of rules.
The process
The last note will be on the process of writing rules. Another aspect my approach is that it guides the naming of components, with (mostly) all of the rules in pattern prefixed with the name of the file in which it is located, e.g. .block-container
is in patterns/block
and #MasterAside
is located in unique/master
. This guideline allows for quick debugging, and speeds the process of discovering (which is an issue I probably will write more on later).
An exception to the naming conventions are the files patterns/bootstrap
and patterns/tags
. The former gives “overrides” to the rules implemented in the lib/bootstrap
(e.g. if I want my own style at buttons), while the latter is default rules for tags. As a general rule I try not to write to many rules concerning tags, as they quickly become excessive (remember SoC), but e.g. links are in general a certain color, and that should be expressed.
Hope you have enjoyed reading about my tips on structuring and writing CSS rules, and if you have some of your own, I would love to hear them.