How to write scalable, modular CSS
{
"name": "Riccardo",
"surname": "Zanutta",
"interests": [
"Web", "Technology", "Sports"
],
"work": [
"@frontend-developer", "@ideonetwork"
],
"tech": [
"HTML", "CSS", "JavaScript", "React.js"
]
}
Cascading Style Sheets (CSS) is a style sheet language used for describing the presentation of a document written in a markup language.
CSS level 1 was released in 1996, and republished with corrections in 1999.
CSS is code as much as JavaScript, PHP or anything else, and we should pay attention to the way we write it.
Otherwise, it may cause things to be more complicated than they should be.
A scripting language that extends the language and gets compiled into regular CSS.
.sass
.foo
color: black
// indentation
.scss
.foo {
color: black;
}
.foo {
color: black;
}
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
body {
font: 100% Helvetica, sans-serif;
color: #333;
}
!important! Overly nested rules will result in over-qualified CSS that could prove hard to maintain and is generally considered bad practice.
.foo {
.bar {
margin: 0;
padding: 0;
list-style: none;
}
.baz {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
.foo .bar {
margin: 0;
padding: 0;
list-style: none;
}
.foo .baz {
display: block;
padding: 6px 12px;
text-decoration: none;
}
.foo {
font-weight: bold;
&:hover {
text-decoration: underline;
}
.in-home & {
font-weight: normal;
}
}
.foo {
font-weight: bold;
}
.foo:hover {
text-decoration: underline;
}
.in-home .foo {
font-weight: normal;
}
/* partial.scss */
.foo {
width: 100%;
}
/* app.scss */
@import "partial";
.bar {
background: white;
}
.foo {
width: 100%;
}
.bar {
background: white;
}
@mixin square($size, $color) {
width: $size;
height: $size;
background-color: $color;
}
.small-blue-square {
@include square(20px, blue);
}
.big-red-square {
@include square(300px, red);
}
.small-blue-square {
width: 20px;
height: 20px;
background-color: blue;
}
.big-red-square {
width: 300px;
height: 300px;
background-color: red;
}
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
@extend .message;
border-color: green;
}
.error {
@extend .message;
border-color: red;
}
.warning {
@extend .message;
border-color: yellow;
}
.message, .success, .error, .warning {
border: 1px solid #cccccc;
padding: 10px;
color: #333;
}
.success {
border-color: green;
}
.error {
border-color: red;
}
.warning {
border-color: yellow;
}
.foo {
@if 1 + 1 == 2 {
border: 1px solid;
}
@if 5 < 3 {
border: 2px dotted;
}
@if null {
border: 3px double;
}
}
@for $i from 1 through 3 {
.item- {
width: 2em * $i;
}
}
p {
border: 1px solid;
}
.item-1 {
width: 2em;
}
.item-2 {
width: 4em;
}
.item-3 {
width: 6em;
}
@nice-blue: #5B83AD;
:extend();
.a, #b {
color: red;
}
.mixin-class {
.a();
}
Stylus is a CSS preprocessor written in Node.js.
text-font-stack = 'Helvetica', 'Arial', sans-serif;
size(width, height = width)
width width
height height
.foo
size(100px)
"every piece of knowledge must have a single, unambiguous, authorative representation within a system."
.u-margin-top {
margin-top: 12px;
}
.u-margin-right {
margin-right: 12px;
}
.u-margin-bottom {
margin-bottom: 12px;
}
.u-margin-left {
margin-left: 12px;
}
Variables: why not?
$unit: 12px;
.u-margin-top { margin-top: $unit; }
.u-margin-right { margin-right: $unit; }
.u-margin-bottom { margin-bottom: $unit; }
.u-margin-left { margin-left: $unit; }
"[...] the practice of structuring information models and associated schemata that every data element is stored exactly only once".
If you can generate the same declaration 50 times without manually repeat it is DRY: you are generating repetition without actually repeating yourself.
Repetition in compiled code is fine, just avoid duplication data in source.
It is more a style guide than rigid framework: is an attempt to document a consistent approach to site development when using CSS.
SMACSS just provides basic guidelines. Use your own naming conventions for each of the categories and arrange them in your preferred way, as long as you document your approach so that other developers can follow along.
- Whiskey and Ginger Ale
- Beer
- Vodka
.favorite {
color: red;
font-weight: bold;
}
ul#summer-drinks li {
font-weight: normal;
font-size: 12px;
color: black;
}
The order of selectors in your CSS does play a role and the "further down" one does win when the specificity values are exactly the same.
.favorite {
color: red;
}
.favorite {
color: black;
}
The color will be black.
ul#summer-drinks li.favorite {
color: red;
font-weight: bold;
}
html body div#pagewrap ul#summer-drinks li.favorite {
color: red;
font-weight: bold;
}
.favorite {
color: red !important;
font-weight: bold !important;
}
CSS applies vastly different specificity weights to classes and IDs. In fact, an ID has infinitely more specificity value!
"There are only two hard things in Computer Science: cache invalidation and naming things." -- Phil Karlton
BEM, OOCSS, ACSS
BEM stands for Block Element Modifier and originated at Yandex. It provides a rather strict way to arrange your CSS classes into independent modules.
.block {}
.block__element {}
.block--modifier {}
.block__element--modifier {}
OOCSS is a programming paradigm. OOCSS stands for Object Oriented CSS.
"Basically, a CSS "object" is a repeating visual pattern, that can be abstracted into an independent snippet of HTML, CSS, and possibly JavaScript. That object can then be reused throughout a site. – Nicole Sullivan, Github (OOCSS)"
%icon {
content: '';
display: block;
&--pins {
@extend %icon;
background-image: url('../img/pins.svg');
}
&--heart {
@extend %icon;
background-image: url('../img/heart.svg');
}
}
%icon, %icon--pins, %icon--heart {
content: '';
display: block;
}
%icon--pins {
background-image: url('../img/pins.svg');
}
%icon--heart {
background-image: url('../img/heart.svg');
}
%font-stack--body {
font-family: 'Helvetica Neue','Helvetica', sans-serif;
}
%font-stack--headers {
@extend %font-stack--body;
font-weight: 600;
}
%type--base-body {
@extend %font-stack--body;
}
%type--base-h2 {
@extend %font-stack--headers;
font-size: 1.5em;
}
And now to the molecule! This is where it gets really delicious:
.metadata {
&__pin-type {
@extend %type--base-h2; //extend base header styling
}
&__caption {
@extend %type--base-body; //extending normal body copy
}
&__hearts {
&:hover {
color: red; //unique hover color
}
&:after {
@extend %icon--heart; // extending heart icon on pseudo element
}
}
&__pins {
&:hover {
color: green; //unique hover color
}
&:after {
@extend %icon--pins; // extending pins icon on pseudo element
}
}
}
.metadata__pins:after, .metadata__hearts:after {
content: ';
display: block;
}
.metadata__pins:after {
background-image: url('../img/pins.svg');
}
.metadata__hearts:after {
background-image: url('../img/heart.svg');
}
.metadata__pin-type, .metadata__caption {
font-family: 'Helvetica Neue','Helvetica', sans-serif;
}
.metadata__pin-type {
font-weight: 600;
}
.metadata__pin-type {
font-size: 1.5em;
}
.metadata__hearts:hover {
color: red;
}
.metadata__pins:hover {
color: green;
}
Atomic Design is a systems-thinking methodology solidified by Brad Frost
Create individual molecules or elements which, when combined and placed together, weave a web of modules, components, and eventually entire layout systems.
A good naming convention will tell you and your team:
They actually play together very nicely, especially when you throw Sass into the mix.
PostCSS is not a preprocessor per se; it doesn’t transform CSS. It provides a CSS parser and a framework for creating plugins that can analyse, lint, handle assets, optimise, create fallbacks, and otherwise transform parsed CSS.
PostCSS is agnostic to language format and allows for the syntax style of different preprocessors, like Sass and LESS, if needed.
"Wait! A CSS file?" Yup, a CSS file.
Ever wanted to learn Russian but were too busy writing CSS?
h1 {
размер-шрифта: 20пикселей;
цвет: красный;
цвет-фона: белый;
вес-шрифта: жирный;
}
h1 {
font-size: 20px;
color: red;
background-color: white;
font-weight: bold;
}
Improve the quality of your css with PostCSS: useful plugins.
a {
transition: transform 1s
}
a {
-webkit-transition: -webkit-transform 1s;
transition: -ms-transform 1s;
transition: transform 1s
}
Stylelint allows you to validate your CSS code against a predefined set of rules which can check your code for consistent formatting, usage of certain rules, units or directives, as well as potential mistakes (such as incorrect colors).
CSS4 will soon be upon us, and with it comes features such as native variables, custom media queries, custom selectors and new pseudo-links. While they are not yet supported in all browsers, they will be implemented in modern browsers as the specification gets approved
Over the next few years, the way we use CSS will change in many different ways. Every project will have different requirements, to which we will have to adapt our production methods. Working within a modular ecosystem like PostCSS allows us to pick and choose the features we want to complete a project.