Scalable and Modular Architecture for CSS
SMACSS by Jonathan Snook is referenced in numerous articles about on CSS and so I finally decided to read it. I can see now how the ideas in this book would have served as a seed for conventions like ITCSS and BEM.
Structured and organized CSS is easier to build on and maintain. Naming conventions improve clarity. Independence from HTML structure means that components can be moved around freely. A balance between class name only selectors, and nested selectors is key for maintainable CSS. Overall our goal should be to increase semantics and decrease reliance on specific HTML structure.
SMACSS attempts to achieve this by creating categories of elements and by creating some conventions on how to split and write your CSS. The author makes it clear that these are just guidelines and need to change as per the project and its realities.
Elements
Base
These are the defaults, usually element selectors, but could also include attribute, pseudo, child and sibling selectors. They don’t include any class or ID selectors. CSS resets are part of the base.
Layout
These divide the page into sections. ID or class selectors can be used for these, though class selectors are preferred and should have the l-
prefix. If required, a combination of layout classes can be applied to a single element, for example l-stacked
and l-flipped
.
Layouts should only be concerned with laying things out in relation to each other. They shouldn’t care about the design of the modules, or the context in which they live. For example, an l-grid
or an l-stack
can exist in varied contexts.
Module
These are the reusable and discrete parts of the design. Use class selectors for these. Since they make up the bulk of the project they don’t have a prefix. Elements within the module shouldn’t be styled using their element selectors – for example, .card h1
is discouraged. This is because these selectors don’t hold any semantic information and rely on the HTML structure which is likely to change as the project grows. So, for elements inside the module use class selectors and add the base module name as a prefix.
While modules can sit inside layouts or other modules, they should be designed to exist as a standalone component. This ensures that they don’t break when moved around on the page.
When the same module is present in different sections, don’t use the parent selector to style the module differently. Instead, create a sub-class with the additional changes and include both classes in the HTML element:
<div class="pod pod-constrained">...</div>
State
These define how the modules and layouts will look in different states. Use class selectors for these, for example, – is-hidden
or is-expanded
. These are the only rules that are allowed to use !important
, but only if they really need to.
Apart from state changes that happen by adding class names, elements can have different states based on pseudo classes like :hover
or by using media queries. All states, including media queries should be defined alongside the module.
Theme
These describe how modules or layouts might look β fonts, icons, colors etc. Not used very often, but when they are they override modules, layouts and states.
Conventions
Files
The different CSS files can be broken down into the following:
- Site settings
- Mixins
- Base
- States
- Layouts (one CSS file for each)
- Modules (one CSS file for each)
These should be imported in the main CSS file in the above order.
Properties
Within a single CSS definition the properties should be ordered as follows:
- Positon
- Border
- Background
- Text
- Everything else