This article is the practical/technical continuation of the previous ‘theoretical’ part of Better CSS: design, architect, build.
There are myriad tools and methodologies to help build and architect your project’s CSS. I’m in no way advocating a ‘best practice’, but (because I’m zealously fond of CSS) I’d like to share my favourite combo to design, architect and build CSS.
Wow! Many tools. Such choice
TL;DR - I adopt the Atomic Design visual design system, architect with ITCSS, and build with BEM and OOCSS techniques, using SCSS running on Gulp.
Most of us are using CSS preprocessors like Sass, Less, Stylus, etc., and are likely to be adopting at least one of the popular methodologies (e.g. OOCSS, BEM, SMACSS, ITCSS etc) in our projects.
There are myriad ways to architect your CSS, and we consciously choose our approach in order to foster:
- Maintainability: CSS is tidy, easily managed, and readily reusable by developers
- Scalability: It supports growth
- Performance: It loads quickly on the client side.
My preferred approach is to firstly get into the design mindset, establish a plan and structure, and then choose and apply the most appropriate and efficient techniques for the project.
Put on your designer cap with Atomic Design
Before you code, think about the design. Atomic Design is my preferred principle to frame the design system.
(Note: here we’re discussing the Atomic Design ‘principle’, not to be confused with the ‘CSS methodology’ Atomic CSS / ACSS)
In the world of responsive web design, we need to go beyond the traditional full page top down high-fidelity design process, and start thinking components—to design and build upwards from the basic atomic elements. The ‘Atomic Design’ metaphor guides us to deconstruct design into distinct layers —starting from the smallest atomic elements that amalgamates the components, and coming together to construct the overarching page layout.
There are 5 distinct layers:
Atomic Design diagram, taken from the author Brad Frost’s blog.
- Atom: the smallest individual element, e.g. a <button>, <p> text, a text input field
- Molecule: formed by a group of atomic elements, e.g. search UI with text input, label and a button
- Organism: a component amalgamated with molecules and atoms, e.g. website header, navigation menu, blog summary list item
- Template: skeleton layout built together with components, e.g. a home page page type
- Page: a web page design with all the features, real content and media, e.g. home page, contact page.
Once we have the design system in mind, we have a better idea of how to structure it, and then we start to plan the CSS architecture.
Architect with ITCSS
ITCSS stands for Inverted Triangle Cascading Style Sheet. This methodology allocates and groups your styles based on their purpose, and arranges them in order of specificity and range of influence (as per the inverted triangle metaphor).
It’s generally structured and ordered in the following manner:
Screenshot taken from the ‘Managing CSS Projects with ITCSS’ presentation by Harry Roberts.
- Settings: global variables, such as brand colours, configs etc
- Tools: mixins and helper functions
- Generic: ground zero styles, reset styles such as normalize.css
- Elements: a.k.a. Base, unclassed html elements, e.g. headings, lists, tables, this is the last layer that styles tag selectors
- Objects: no cosmetic design patterns. Class only styles from here onwards. Classes here are loosely named and I start doing OOCSS here (e.g. .button, .list-item, grid systems etc)
- Components: rich design UI styling. Class names here are more specific. This layer usually has the biggest volume
- Themes: if applicable, thematic styles are placed here (e.g. seasonal Christmas theme)
- Trumps: utilities, helpers and overrides. !important is often used.
Referring back at the inverted triangle metaphor the higher layers have broader range of influence. Variables such as colors declared in Settings has potential effect throughout the entire site, as opposed to a trump class like .is-red, which only affects the element it's applied on.
Screenshot taken from the ‘Managing CSS Projects with ITCSS’ presentation by Harry Roberts.
Specificity boosts as you move down the triangle. For instance, the general heading font sizes are declared in the Elements layer, if the design has a different heading size in the hero banner, then it’s easily overwritten by the latter Hero Banner Component.
What it looks like in the file system
I apply ITCSS with Sass (with SCSS syntax), and on the file system a SilverStripe theme may look something like this:
For ease of access, I prefer to group the files into respective folders and each with an entry Sass partial file (e.g. ./components/_components.scss) to import the children snippets.
The main Sass file only @imports main entry partial files, nothing else:
main.scss
@import ‘settings/settings’;
@import ‘tools/tools’;
@import ‘generic/generic’;
@import ‘elements/elements’;
@import ‘objects/objects’;
@import ‘components/components’;
@import ‘themes/themes’;
@import ‘trumps/trumps’;
And in each of the main partial file, include the children snippet partials:
objects/_components.scss
@import ‘header-search’;
@import ‘hero-banner’;
@import ‘top-navigation’;
After everything is properly organised and linked, then you start to style in the snippet partials (e.g. _header-search.scss).
When done editing, main.scss is compiled into main.css and then included by the website.
Build it with BEM and OOCSS
BEM stands for Block, Element, Modifier. In the context of a CSS technique, this methodology fosters modularity, and its distinct class naming convention is descriptive and readily understood.
I like BEM’s flexibility, which allows me to blend some OOCSS (Object Oriented CSS) techniques to into my CSS build.
What it looks like
Let’s put the above into a real example, say we’re trying to build a hero banner with a heading and calls-to-action:
<header class=”banner hero-banner clearfix” role=”banner”>
<h1 class=”banner-heading hero-banner__heading”>Hello, world!</h1>
<p class=”banner-text hero-banner__text”>I am the almighty hero banner.</p>
<a class=”button hero-banner__button hero-banner__button--state-success f-left”>Sign Up</a>
<a class=”button hero-banner__button f-right”>Login</a>
</header>
Say, a developer is looking at this call-to-action’s class name:
.hero-banner__button--state-success
The developer can readily recognise and understand its semantics:
- hero-banner is its wrapping Block
- This Element is a button
- It has a state (Modifier) of state-success.
Create meaningful names with Atomic Design
The Atomic Design thinking helps us with creating useful and meaningful class names. Using the above hero banner example, we can conceptualise this component as follows:
- Hero banner is a molecule
- It’s composed of 3 types of atoms:
- Heading
- Text
- Buttons.
Nesting considerations
You’ve probably noticed BEM’s idiosyncratic reliance on the absence (or minimal) of CSS nesting. Nesting is a redundant practice here, as OOCSS decouples styling and html markup, and BEM’s naming convention already lexically represent the component’s structure.
Personally, I’m a big fan of the no-nesting paradigm. It’s more modular and helps to keep the stylesheet clean and simple.
One exception where nesting becomes sensible is within ITCSS’s Themes layer.
Say we’re introducing a seasonal Christmas theme. We could wrap the necessary components with .xmas and easily theme it up, for example:
./themes/_xmas.scss
.xmas {
.header {
background-image: url(‘../images/xmas/bg-jingle-bells.jpg’);
}
.footer {
background-image: url(‘../images/xmas/bg-north-pole.jpg’);
}
}
Putting it all together
Let’s try a more complex example. We’ll build a header with a logo, navigation and search box.
Firstly, we’ll use the Atomic Design system to understand how we should construct our components:
Header: organism
- Branding: molecule
- Logo: atom
- Slogan: atom
- Search: molecule
- Text field: atom
- Button: atom
- Navigation: molecule
- Navigation item 1: molecule
- Link: atom
- Toggle: atom
- Menu: molecule
- Navigation item 2: molecule
- ...
- Navigation item 3: molecule
- …
- ...
In the navigation molecule, note that navigation items can still be broken down, so it’s still labeled as a molecule.
Secondly, abiding to the ITCSS structure, we know where to allocate styles that influence the header:
- Settings: variables like colors and font sizes
- Generic: reset styling, box-sizing
- Elements: form elements, list styling
- Objects: text input field, buttons, navigation items
- Components: cosmetic treatment specifically for branding, search field and header navigation.
Then in html, code the structure and apply the OOCSS and BEM naming convention:
<header class=”header”>
<!-- Branding -->
<a class=”branding” href=”/”>
<img alt=”Doge Inc.” class=”branding__logo”>
<p class=”branding__slogan”>Wow! Such brand, many logo</p>
</a>
<!-- Site search -->
<form action=”/” class=”form site-search” name=”form_siteSearch”>
<input class=”input-text input-text-lg site-search__input-text” name=”text_siteSearch” placeholder=”Wow! Many serach!” type=”search”>
<button class=”btn btn-lg btn-primary site-search__btn” type=”button”>Go!</button>
</form>
<!-- Top navigation -->
<nav class=”top-nav”>
<ul>
<li class=”top-nav-item top-nav-item--first”>...</li>
<li class=”top-nav-item”>
<a href=”top-nav-item__link”>About Us</a>
<button class=”top-nav-item__toggle top-nav-item__toggle--collapsed text-hide” type=”button”>Show</button>
<ul class=”dropdown-menu top-nav-menu”>...</ul>
</li>
...
<li class=”top-nav-item top-nav-item--last”>...</li>
</ul>
</nav>
</header>
And lastly, apply your styling to the respective partial SCSS files, and there you have it: scalable and maintainable CSS!
Making it work for everyone
No matter what your approach and toolkits, make sure it's well shared with developers, designers, and stakeholders if they want to be involved.
Start the conversations and brainstorming sessions early, document your approaches and coding style guide, agree on the use of vocabulary and naming conventions (This is the fun part. Don’t like the atomic analogy? How about soldiers > squads > battalion > templates > pages?). And as always, keep CSS sane, lean and simple.
How do you do yours? Feel free to leave your feedback in the comments below!
Post your comment
Comments
One of the downsides I have run into with using Atomic Design and ITCSS is the naming conventions. With Atomic Design it can get a bit awkward trying to communicate with others who may not have bought into the analogy about "atoms" and "molecules". With ITCSS is can get confusing for developers when using overloaded terms like "objects", "generics", and "settings".
I recently developed a conceptually similar framework with some terms that may be more palatable for my designers and developers. I also built some tooling around it for scaffolding and maintenance: https://projectclarion.com/
Posted by Burton Smith, 15/07/2018 12:06am (6 years ago)
Posted by Tim Kelly, 18/05/2017 5:02pm (8 years ago)
Posted by WhiteNight, 10/02/2017 9:42am (8 years ago)
o- for organisms
m- for molecules
a- for atoms
did you think about that?
Posted by jackblack, 25/08/2016 8:30am (8 years ago)
No one has commented on this page yet.
RSS feed for comments on this page | RSS feed for all comments