Upload
michal-pierzchala
View
553
Download
0
Embed Size (px)
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