1 of 73

Slide Notes

Good evening.
Tonight I’ll talk about atomic css.
atomic css is something we came up with at Yahoo! (Media) to address 2 specific problems: Bloat and Poor Caching.

Atomic css

Published on Nov 18, 2015

When it comes to CSS, I believe that the sacred principle of “separation of concerns” (SoC) has lead us to accept bloat, obsolescence, redundancy, poor caching and more. Now, I’m convinced that the only way to improve how we author style sheets is by moving away from this principle.

PRESENTATION OUTLINE

acss.io

.

Good evening.
Tonight I’ll talk about atomic css.
atomic css is something we came up with at Yahoo! (Media) to address 2 specific problems: Bloat and Poor Caching.

Untitled Slide

We decided to tackle those 2 because our style sheets were getting bigger and bigger and we did not do a good job at caching those files.

Untitled Slide

We knew exactly where the bloat came from though.

Untitled Slide

It was because we were writing CSS every single day…

Untitled Slide

New declarations…

Untitled Slide

New rules…

Untitled Slide

New values…

Untitled Slide

New selectors…

Untitled Slide

And it kept on going...

Untitled Slide

But how come after so many years of writing style sheets we were still creating “Big Balls of Mud”?
http://en.wikipedia.org/wiki/Big_ball_of_mud

Untitled Slide

So we looked back at a few techniques…
Back in the day, clean/lean markup was the ultimate goal. We did not use too many classes.

Untitled Slide

But that was possible because our pages did not contain much.
With the kind of apps we are dealing with today, we can no longer afford to target generic selectors like that.

Untitled Slide

Doing something like this does narrow the scope but it is not a solution either as it completely ties the styling to the HTML structure.

As a side note, even though the specificity here is not that high, this kind of rules are hard to maintain. In general, high specificity is not the real problem, the real problem is when specificity is all over the place, like here (0,1,0; 0,2,1; 0,2,2; 0,2,3;).

Untitled Slide

It’s better to avoid targeting type selectors and use classes instead. Because it makes the structure irrelevant.
For example, now we could replace the
with a

here without having to edit the CSS.

Untitled Slide

But note that all these rules are sandboxed via a specific class - that we use as a contextual selector.

More on that later…

Untitled Slide

Today, we do without descendant selectors (or I should say descendant combinator) which also reduces specificity.
This follows the BEM methodology - which stands for "Block, Element, Modifier".

Untitled Slide

But the styling is still contextual because the prefix we use relates to a specific container.
Context limits scope but promotes redundancy.

Untitled Slide

So to recap:
Early on we used type selectors - which tied the styling to the HTML structure.

Untitled Slide

Then we dropped type selectors in favor of classes.
Styles were no more tied to the HTML structure.

Untitled Slide

We then narrowed the scope a bit more, thanks to combinators.
(note that this ties things back to the HTML structure though).

Untitled Slide

And we finally abandoned descendant selectors. But note that all this was done to facilitate maintenance - not to limit or reduce bloat.
Also, note that back in 2009 this approach was called "classitis" or even “The new CSS disease”. This is just to say that what is considered OK today was a big no-no a few years back.

Untitled Slide

There is also the case of the media object.
Is everybody familiar with this?
It is Nicole Sullivan who coined that term. The media object is a set of 3 classes meant to be applied onto 3 distinct elements to create a specific layout.

Untitled Slide

Those classes still relate to content, but there is some abstraction that facilitates reuse.

Untitled Slide

This abstraction saves us from grouping selectors like this.

Untitled Slide

But in my opinion, the media object is still too semantic.
Look at this “modal” for example.

Untitled Slide

It is the same pattern as the Media Object but we can’t really use those classes here.
Instead, we’d need to add new selectors to the style sheet even though we already have something that could work.

Untitled Slide

In a sense, the media object is similar to clearfix.
The classes involved are related to a specific layout, not to the content.
(As a side note - I’m curious - how do you guys use clearfix? Like the rule on the right or like the one on the left?)

Untitled Slide

Anyway, we wanted to maximize reuse, we wanted to move away from “my widget”, “his widget”, or “her widget” so we thought of adopting something similar to the clearfix philosophy.
Which is a class with a single purpose. A class that has nothing to do with content or context.

Untitled Slide

So we did something BOLD

Untitled Slide

We inlined 75% of our styling

Untitled Slide

Yes, we are now styling inline…

Untitled Slide

But not via the style attribute though. Instead of writing declarations inside a style attribute, we use classes that are mapped to those declarations.

Untitled Slide

Inline styling is not that bad. The scope is limited to the element on which we apply the classes and it is “portable” because the styling “follows” the markup.
The bad things about inline styling is the specificity, the verbosity, the fact that those bytes are not cached, and also the fact that browsers have to assess those styles once they get to them.

Untitled Slide

So this is the atomic way. We’ve stopped feeding the styles sheet; instead, we write more classes in the markup.
Yes, we do have a “semantic” class on the wrapper but we do not really rely on this for styling.

Untitled Slide

On the CSS side, it looks like this. Rules are mostly 1 liners.
For each class you use you get 1 style and 1 style only (kinda single responsibility principle).
We do not use descendant selectors and we do not use classes tied to content either (like using a prefix to reference a container for example).
And the same declaration does not exist in multiple places in the style sheet. Our CSS is much much DRYer than what it used to be.

Untitled Slide

Because atomic classes are content agnostic we can now build this new module by adding a single new class. Which will also be re-usable.

Untitled Slide

All our classes can be used anywhere we want because none of them are related to content.

Untitled Slide

With atomic css we can use the exact same classes regardless of what they style.
We can use them each time we use the same pattern, or the same layout.

Untitled Slide

classes are for developers, they don’t make a document more “semantic” (microformats is a different story though).
The main goal here is to reduce bloat, so to better achieve this we must ignore content and context as much as possible.

Untitled Slide

Look at this snippet for example. It creates a working carousel.
We put things together in the markup, there is no need for “carousel” rules in the style sheet.
If we wanted to show only 2 items per view, we would simply replace W-20% with W-50% - that’s it.

Untitled Slide

Anywhere does not mean everywhere though.
The key is to know when to use a atomic class and when to use a component class. If the style is common to many modules, it is better to use a component class (a “semantic” class).

Untitled Slide

That’s why we don’t depend on atomic classes alone.
Basic component rules work best when the elements they style exist in multiple places.

Untitled Slide

Also, note that all atomic rules use an ID so we can easily overwrite a style from a component rule like the one above.
A atomic class can overwrite any rule based on class selectors - regardless of how many are being used.

Untitled Slide

We also heavily rely on helper classes. We have many of these. And notice here that even if we could style the “stretched” box using atomic classes alone, we still offer a component rule for this.
That’s because many developers are not sure about how all patterns work (the padding trick in this case) so less granularity helps here.

Untitled Slide

All this to say that even if we do use classic component rules, they are not the norm. They only represent a quarter of our core style sheet.
That file is 18KB minified and gzipped. It includes a base style sheet, a grid style sheet, helpers, and atomic classes.

Untitled Slide

And that helps a lot with caching.
Because before atomic, not much CSS was shared across teams.

Untitled Slide

The only style sheets common across sites were a reset and a grid style sheets. That was it!
And it was less than 2 KB.

Untitled Slide

And those files were not even cached because all files were bundled together - on a per site basis.

From web.archive: http://web.archive.org/web/20140313134714/https://www.yahoo.com/

Untitled Slide

Also, each module came with its own CSS file. And each time the CSS of one of these modules was updated we invalidated the cache.

Untitled Slide

So users following links from the Home Page would load a lot of new CSS

Untitled Slide

Going from one site to the next on our own network meant fetching more and more style sheets.

Untitled Slide

atomic css can change all that. We can share a core file because the styles it contains are not related to content at all.
That core file + a custom style sheet weigh less than 30KB. And we can build anything we want with 30KB.

Untitled Slide

We can also reduce the number of “maintainers” (those are the people who add new rules to the custom style sheet).
That’s because a 10KB style sheet is manageable, but a 60KB style sheet is not.

Untitled Slide

We have reduced the size of our style sheets because we have less of everything.
I’ll let you look at this for a minute.
Disclaimer: I’m not sure how reliable cssstats.com is.

Untitled Slide

What difference does that make?

Untitled Slide

A huge difference!
Users will be loading much less CSS while navigating across our network - because all they will be loading is the custom style sheet - not the core file.

Untitled Slide

The key points:
Maximum re-use of rules because they are content agnostic.
Single responsibility rules are easier to manage (add/update/delete). Deleting a module is enough to delete all the styles associated with it.

Untitled Slide

Before you ask...

Untitled Slide

Do we need to edit multiple files to change the styling of common elements instead of editing one style sheet.

Untitled Slide

We try to prevent maintenance issues by looking at what is common across a page. And then we choose to either use atomic classes or component classes.
On this slide, the green boxes show styles rather unique to these boxes, while outside of that we see styles common to different modules (i.e.: headings, border, padding).
Remember that the goal is not to make our life easier but to provide a better user experience to our users. That’s the agenda.
Note that the grid (the page layout) exists in one place, so atomic classes can be used there too.

Untitled Slide

Are we moving bloat from the style sheet to the markup?

Untitled Slide

These 2 snippets are from the previous examples, they are about the same size.

Untitled Slide

And this represents the average number of characters per class attribute on the page.
Note that Facebook appears to uglify some classes.

Untitled Slide

But if we put Gzip into the picture, then things look even better. That’s because a lot of repetitions means a better compression ratio.
From a few tests we ran, it’s about 35% for semantic classes versus 48% for Atomic classes.

Untitled Slide

How do we do Responsive Web Design?
How can we serve different styles if we style via markup?

Untitled Slide

Actually, we don’t really do “Responsive” at Yahoo! as we are treating Mobile differently from Desktop.
But you could use a suffix to differentiate the classes according to the context in which they apply.

Untitled Slide

Or you could go this route too. Something I usually prefer as it drives everything from the container.
http://jsfiddle.net/thierrykoblentz/s0qhoqum/1/

Untitled Slide

The syntax comes from Emmet, which is a plugin for many IDEs. It allows you to type a few characters and get property/value pairs.
Atomic classes are for the most part simple abbreviations.

Untitled Slide

This shows Emmet syntax and Atomic syntax side-by-side

Untitled Slide

We just replaced the colon (“:”) with a dash (“-”) as we didn’t want to use the escape character (“\”) everywhere

Untitled Slide

Also, note that we do not use “left” and “right” but instead “start” and “end”. So we can easily output a RTL style sheet using a pre-processor.

Untitled Slide

Any question?

Untitled Slide

Thank you!