Thinking in Atomic
Learn the Atomic CSS principles that Atomizer is built on.
"Atomic CSS" is a CSS architecture. It is not opinionated; it simply defines a set of classes representing single-purpose styling units.
Be sure to read an interview with Atomizer Co-Founder Thierry Koblentz, The Making of Atomic CSS on CSS Tricks.
Atomizer implements a specific syntax to help you generate Atomic rulesets. It only creates a style sheet with relevant declarations to your project. These style declarations are generated from Atomizer classes within your project or custom values defined in the Atomizer config file.
Adopting an Atomic CSS methodology addresses common CSS challenges:
- Changes are predictable
- Because of the single responsibility principle (one class == one style) it is easy to predict what removing or adding a class will do.
- Scope is limited
- There is no reliance on descendant/contextual selectors — styling is done inside "[specificity layers](#style-sheets-organization)".
- CSS is lean
- There is very little redundancy and no dead weight (all styles are relevant to the project).
- Components are portable
- Classes used to style a component are not specific to that component, hence components can live in any other project that uses Atomizer [1].
- Beginner-friendly
- Writing efficient and correct selectors is often one of the hardest parts of CSS for new developers to master. With Atomic CSS, developers don't create bloat because they don't write the selectors, instead they mostly re-use existing classes. This can greatly simplify the learning curve for inexperienced developers.
Who's Atomizer for?
Atomizer is for developers who see the benefits of styling "outside of style sheets" — who want to write markup and styles in one place while benefiting from an Atomic architecture. It is a switch of priorities. You don't maintain style sheets but components.
Be pragmatic
Atomizer can live side-by-side with traditional style sheets. In cases where Atomizer doesn't seem the most pragmatic, you can always supplement with inline styles or external stylesheets. Use the right tool for the job.
Traditional style sheets may be helpful for styles that Atomizer cannot create, styles for elements that aren't under your application's control, or repeating elements that are not componentized [2].
Grids
There is no such thing as a "Grid" in Atomizer. Atomizer does not provide classes to create columns based on an opinionated construct (float
, inline-block
, etc.) Instead, Atomizer gives you all the tools you need to create any grid you want.
Specificity
0,0,1,0
to "infinity"
From By nature, Atomizer classes have very low specificity (0,0,1,0
). Atomizer creates a style sheet in which the specificity of every rule can be increased by using a namespace. The best practice is to keep specificity as low as possible, but depending on other rules in your project, you may want to include a namespace to increase the weight of Atomizer classes.
Remember that the weight of rules is not as important as making sure specificity is homogeneous across rules. For example, styles like these:
#namespace .myBox {} /* 0,1,1,0 */
#namespace .menu_item {} /* 0,1,1,0 */
#namespace .list_active {} /* 0,1,1,0 */
#namespace .article_summary {} /* 0,1,1,0 */
#namespace .nav_link {} /* 0,1,1,0 */
Are easier to maintain than styles like these:
.myBox {} /* 0,0,1,0 */
.menu .menu_item {} /* 0,0,2,0 */
ul.list .active {} /* 0,0,2,1 */
.main .article .summary {} /* 0,0,3,0 */
.nav .list .item a {} /* 0,0,3,1 */
Choosing to include a namespace or not, and to use a class or an id for the namespace depends on the weight of rules in other style sheets. For Atomizer classes to be relevant, they must have enough weight to overwrite non-atomic styles. The specificity may be the same as non-atomic styles as long as the Atomizer style sheet is included after other style sheets.
This table suggests the namespace to use depending on the weight of your other rules (Specificity Calculator).
Specificity | Namespace |
---|---|
0,0,1,1 |
No need for a namespace |
Less or equal to 0,0,1,1
|
Use html (type) for namespace |
Less or equal to 0,0,2,0
|
Use a class for namespace |
Less or equal to 0,1,1,0
|
Use a id for namespace |
More than 0,1,1,0
|
Use whatever it takes [3] |
You can set up a namespace in grunt-atomizer or via the Atomizer command line.
Style sheets organization
Take advantage of the cascade by creating "specificity layers" [4] and loading files in proper order.
Layer | Specificity | Style sheets |
---|---|---|
type selectors | 0,0,0,x |
normalize.css, base.css, etc. |
single class | 0,0,1,0 |
helpers.css, utility.css, etc. |
contextual selectors (any number of classes) |
0,0,x,x |
layout.css, custom.css, etc. |
Atomizer classes | 0,1,1,0 |
atomic.css |
@style |
1,0,0,0 |
Inline Styles |
!important rule |
Trumps all the above [5] | Can be anywhere (as an exception) |
This website uses *flat selectors* (0,0,1,0
), which allows us to follow the same logic as above without the need for a namespace.
- Unless that component relies on custom values from the config file - in which case, keys from that file would need to be added to the config of the other project [↩].
- An example of this could be the markup of a "button" that could appear in many places across a project (versus a unique "component" included in multiple places) [↩].
- The namespace can be anything, for example:
#someId #anotherId .andAclass
[↩]. - Specificity is something we want to leverage, not something we want to keep a lid on [↩].
-
!important
is not related to specificity per se [↩].