CSS by the fireplace

A casual writing workshop for delightful stylesheets

Peter Szerzo

Cph Frontenders, April 12th, 2016

Hi, I'm Peter

I write front-end at Airtame.

I go by pickled-plugins on GitHub.

You can also find me at peterszerzo.com.

What's nice about this code?

class Person > ActiveRecord::Base
  field :first_name
  field :last_name
  has_many :hopes
  has_many :dreams
end

class PeopleController > ActionController
end

And how about this one?

import Task exposing (Task, andThen)
import TaskTutorial exposing (getCurrentTime, print)

port runner : Task x ()
port runner =
  getCurrentTime `andThen` print

Among others:

  • They read like English (like instructions).
  • They hide details (they are short!), but show where to look for them.
  • Arguably, they have few cryptic abstractions.

Why not in CSS?

CSS spoils your code

RuntimeException:
  - awkward selector div#header > button ~ p

Writing styles that read clearly is tricky:

a button
  has 6px padding
  has standard border radius
  is blue by default
  is red in primary state
  is green in success state

the header contains buttons spaced 10px apart

Does this resemble the way your designer describes a mock-up?

Spoiler

.button {
  padding: 6px;
  border-radius: $standard-border-radius;
  background-color: blue;
  &--primary { background-color: red; }
  &--success { background-color: green; }
  .header & { margin: auto 10px; }
}

What's stopping me from writing good CSS

  • At 15.30, I stop believing that I can.
  • I get less feedback (JS code reviews vs. CSS code reviews).
  • I get lost in the quirks and the cross-browser issues.
  • Why care - the design will change tomorrow.

Those are just the surface

Writing CSS is a bit like writing poetry in Danish. I need:

  • Vocabulary
  • Grammar
  • Syntax
  • Composition
  • Tools

How about JS?

  • loosely typed => we don't really ever know what's coming.
  • things like ==, null, undefined, NaN with straaange behavior.
  • also spoils your code.

Agreeing on stuff in JS

Here's a well-meaning fellow:

class Fellow {
  constructor() {
    this.name = "Jake";
    this.opinion = "The class syntax is kinda nice.";
  }
}

Agreeing on stuff in JS

And the surprise he's in for:

Object.create({}, {
  name: "Frank",
  hardPolicy: "Never hire guys like Jake."
});

...but we get by!

  • use strict.
  • Lint: ESLint, JSHint.
  • Type-check: Flow, TypeScript.
  • Use frameworks: React, Cycle.js.
  • Compile to JS from something else: Elm, Clojure, Scala, CoffeeScript.

What are CSS' remedies?

They are a little bit:

  • Less obvious.
  • A little scattered.
  • We talk about them less.

But they're around:

  • BEM
  • OOCSS
  • React styling
  • SMACSS
  • Tooling

Or, in the words of our English teacher

  • BEM => spelling & syntax
  • OOCSS => writing paragraphs
  • React styling => writing pro paragraphs
  • SMACSS => writing essays
  • Tooling => the spellchecker

BEM > Block, Element, Modifier

An analogy from natural language

  • EN: on the table
  • DK: på bordet => on tablethe
  • HU: az asztalon => the tableon

We agree on grammar rules for a reason.

BEM > The CSS

/* A block. */
.header {}

/* Its element. */
.header__nav {}

/* Its modifier. */
.header--compact {}

BEM > The HTML

<header class='header header--compact'>
  <div class='header__content'>
    <nav class='header__nav'></nav>
  </div>
  <div class='header__overlay'>
  </div>
</header>

BEM > SASS syntax

We get high-level overview

.header {
  &__content {} /* .header__content */
  &__overlay {}
  &__nav {}
  &--compact {}
}

BEM > Some house rules

/* Flat element structure */

/* Too nested. */
.header__content__button {}

/* The BEM way. */
.header__button {}

BEM > Some house rules

<!-- No global modifiers. -->

<!-- Not encapsulated and slower. -->
<header class="header expanded"></header>

<!-- The BEM way. -->
<header class="header header--expanded"></header>

BEM > The benefits

  • New grammar: __, --.
  • Namespacing.
  • Low specificity: it looks nested, but it isn't.
  • It provides some good incentives for refactoring.

BEM > Incentives

/* Against BEM rules. */
.header__content__button {}

/* Better - and also reusable across the project. */
.flat-button {}

BEM > Alternatives

Also worth checking out:

OOCSS

Object-oriented CSS

Separate structure from skin.

Separate container from content.

OOCSS > Structure and skin

.element {
  background-color: teal;
  border-radius: 2px;
  display: block;
  font-size: 14px;
  margin: 25px;
  padding: 5px;
  width: 100px;
}

OOCSS > Structure and skin

.structure {
  /* background-color: teal; */
  /* border-radius: 2px; */
  display: block;
  /* font-size: 14px; */
  margin: 25px;
  /* padding: 5px; */
  width: 100px;
}

OOCSS > Structure and skin

.skin {
  background-color: teal; 
  border-radius: 2px;
  /* display: block; */
  font-size: 14px;
  /* margin: 25px; */
  padding: 5px;
  /* width: 100px; */
}

OOCSS > Container and content

When to nest and what?

#main .title {
  display: block;
  font-size: 36px;
  font-weight: bold;
  color: blue;
  margin: auto;
  text-align: left;
}

OOCSS > Container and content

.title {
  /* I want some styles too! */
}

OOCSS > Container and content

By minimizing nesting:

  • CSS is faster (browsers read rules from right to left).
  • Lower specificity, less conflict, more re-use.
  • It encourages authors to write good abstractions of design intent.

OOCSS > Traditional OO

  • A class has one clearly defined (and named) responsibility.
  • A class has one reason to change.
  • Clear, sensible inheritance chains and overrides.

Is any of this applicable to CSS?

OOCSS > Traditional OO

Some questions to ask

How many blocks do I need to change for each minor change in the design?

How easily do I find these blocks?

Am I overriding too much in nested rules?

Is it clear what I'm overriding, and does it make sense with the naming?

React Styling > Code example

A lesson for traditional CSS

React Styling > Key points

In React, each component:

  • Is responsible for managing its interior behavior (state).
  • Works off of data passed down from the immediate parent (props).
  • Manages its direct children.

React Styling > Key points

In equivalent CSS, each module:

  • Is responsible for its skin.
  • Positions itself based on nested rules specified in the parent.
  • Positions and allocates space for its direct children.

React Styling - In practice

Styling react

  • Radium
  • React Style
  • JSS
  • React Inline
  • CSS Modules

SMACSS

Scalable and Modular Architecture for CSS

Categorize styles and set up rules for each:

  • Base
  • Layout
  • Module
  • State
  • Theme

SMACSS > Base rules

Usually applied using the element selector; no classes, id's or !important.

@import 'normalize.css';

body {
  overflow-x: hidden;
  overflow-y: scroll;
}

SMACSS > Layout rules

  • Like the structure from OOCSS.
  • Styles applied using HTML attributes, classes or id's.
  • Includes the grid system.
  • Also: position/size of the highest-level components of the page (sidebar, header).

SMACSS > Module rules

  • Like the skin from OOCSS, or a component.
  • Styled by class names. Avoid element and id selectors.

SMACSS > State rules

  • Augments and overrides other styles.
  • !important is appropriate here.

(current trends might move these rules inside module rules)

SMACSS > Theme rules

  • Augments or overrides other styles to allow for different website themes.
  • Overrides base styles (colors, borders) or even layout.
  • It is quite rare.

SMACSS > Wrap-up

These 5 categories and their rules, as they are, will probably not make sense for your next project.

Write your own Bootstrap.

Tons of alternatives: ITCSS, InuitCSS, Bootstrap, Foundation, Skeleton.

Tools

Main goals:

  • Enforce rules and ensure consistency.
  • Simplify re-factoring.

They are:

  • Pre-processors
  • Linters
  • Templates

Tools > Pre- and postprocessors

  • Sass, Less.
  • PostCSS and plug-ins: Sass-like features, CSS4, autoprefixer.

Tools > Linters

  • scsslint
  • sasslint
  • stylelint

Tools > Linters

{
  "selector-no-id": true,
  "selector-class-pattern": "/foo-[a-z]+/",
  "max-nesting-depth": 3,
  "declaration-no-important": true,
  "declaration-block-no-shorthand-property-overrides": true,
  "color-hex-length": "long",
  "declaration-block-trailing-semicolon": "always",
  "property-no-vendor-prefix": true,
  "value-no-vendor-prefix": true
}

Tools > Templates

CSS changes require changes the HTML ...% of the time.

If changing the markup is tedious and error-prone, we won't do it.

  • Template and partials: Handlebars, Jade, Jinja, Twig.
  • Components: React, Angular, Polymer.

What was all this, anyway?

  • Lots and lots of jargon and buzzwords.
  • Ways to construct a subset of CSS with good constraints (like Elm).
  • Some grammar and syntax that help express a design intent.

And finally...

This is the CSS - drop to your knees and put your hands behind your head!

Thank you and happy styling!