Scalable CSS Architecture

Preview:

Citation preview

Scalable CSS Architecture

Artur Kot & Michał Pierzchała

Does it even exist?

Scalable CSS? Maintainable CSS?

What we need

Modularity Encapsulation Predictability

What we have

What we really have

Cascade Global namespace Selectors specificity

Solution?

–David Heinemeier Hansson

“Convention over configuration”

Like in JavaScript

Embrace the good parts Throw away the bad parts

Introducing

ITCSSInverted Triangle

CSS

// main.scss

@import 'settings/*'; @import 'tools/*'; @import 'generic/*'; @import 'elements/*'; @import 'objects/*'; @import 'components/*'; @import 'trumps/*';

used with preprocessors font definitions, colours, variables, etc.

1. Settings

2. Toolsglobally used mixins and functions

normalising styles box-sizing

3. Generic

4. Elementsbare HTML elements

reset lists, anchors, etc

simple & reusable containers, grids, global animations, etc

5. Objects

6. Componentsactual UI

CSS ❤ components

utilities and helper classes visibility, alternative colours

override anything

7. Trumps

Some constraints and recommendations

Groups order is crucial (Inner order doesn’t matter)

Avoid “!important”

Use BEM (Block Element Modifier)

<section class="c-component c-component--small"> <div class="c-component__bg"></div> <h2 class="c-component__heading">A component!</h2> <div class="c-component__child"> Lorem ipsum dolor sit amet, consectetur adipisicing elit <button class="c-component__grandchild">inside</button> </div> </section>

• .[component-name]__[child]—[modifier] • Remember that it’s on only a convention! • Use 🍌 instead of __ or 🍓instead —

if you like • Important: separation of the parent

element and its children. • Be consistent.

JS hooks

• .js-[name] • readonly to identify DOM elements for JS • can’t be styled!

State classes

• .is-[name] • .has-[name] • should be used in favour of —modifiers

in case a component changes its state after the page is loaded

• handy to use with JS

Resist from nesting

Temptation to target tags.c-my-list li { [item styles] }

<ul> <li> <div class=”c-some-component-with-a-list”> <ul> <li>another list!</li> <li> and now you need to override

.c-my-list li with stronger selector...</li> </ul> </div> </li> </ul>

• You can’t predict the future. It’s possible that a sneaky designer could design a nested list inside your element. What to do then? More nesting. :)

• It, obviously, works but what if you’ve got identical list but with divs instead of lis?

• Usually, nesting is like a domino effect: one innocent nested selector results in dozen deeper nested selectors. Avoid when possible.

You can’t entirely avoid nesting. It’s impossible.

The goal is to minimise it and its side effects.

.c-component { /* third-party code */ .super-slick-slider { float: left !important; }

/* state affects children */ &.is-open { .c-component__grandchild { display: block; }

.c-component__inner { display: flex; }

.c-component__inner-most { color: red; } } }

.c-component { /* state classes */ &.is-open, &.has-popup { display: block; } /* state pseudo-selectors */ &:hover, &:focus, &:nth-child(2n) { border-bottom: 1px solid; }

/* relationships */ + &, ~ &, > &, * { display: none; } }

Do Repeat Yourself

If it makes your life easier (usually does)

extra bytes will be squashed by gzip anyway…

Tricky MQ nesting

.c-component { @media { &.is-cos { @media { color: red; } } } }

.c-component { color: blue;

@media { color: red; }

&.is-cos { @media { color: yellow; } } }

BAD GOOD

Keep it tidy

Sync filenames with naming

/* _my-pretty-component.scss: */

.c-my-pretty-cmp { color: brown; }

/* _my-pretty-component.scss: */

.c-my-pretty-component { color: blue; }

BAD GOOD

Do not mix components with each other

Not in stylesheets

/* Some time before */

.c-my-box { width: 320px; }

.c-my-box__inner { padding: 20px; background: blue;

.c-my-other-box { color: white; } }

/* Few weeks later… */

.c-my-other-box { color: white;

/* Doesn’t work :( */ &--pink { color: pink;

} }

Nor in the markup<div class=”c-boxie c-footer”></div>

.c-boxie { display: block; }

.c-footer { display: flex; }

What display will it get?

Objects for reusability Components for explicitness

Use objects for mixing with component!

<div class=”o-boxie c-footer”></div>

.o-boxie { display: block; }

Trumps are the new “!important”

<h3 class=”o-title t-color-blue”>Heading</h3>

.o-title { font-size: 12px; color: red; }

/* trumps/utilities.scss */

.t-color-blue { color: blue; }

It’s easier to maintain separated UI components than ones mixed in HTML markup

Take it serious

It Just Works™ for CSS, SCSS, LESS

Piece of cake

Critical CSS or PRPL?

/* critical.index.scss */

@import 'settings/*'; @import ‘tools/*'; @import 'generic/*'; @import 'elements/*'; @import 'components/colorbar'; @import 'components/header'; @import 'components/hero';

Kinda

Use in existing messy codebase?

Gradual adoptionNeeds pre-/post-processor (sorry CSS 😞)

#create #strongest #selector { @import 'settings/*'; @import 'tools/*'; @import 'generic/*'; @import 'elements/*'; @import 'objects/*'; @import 'components/*'; @import 'trumps/*'; }

With predefined and ready to use (or remove) components

Featured in Chisel, our new project generator

ITCSSISAWESOMER

Cool JS-based alternatives

CSS Modules CSS in JS

Available with Webpack & Browserify

Thank you.

Artur Kot & Michał Pierzchała

Recommended