back to module

Smashing Workshops

Poetic CSS

Arrows navigate, cmd/ctrl-k for settings

A poll… OOCSS, ITCSS,
SMACSS, BEM, CUBE,
Utility-First, other …

What are you trying? Are you happy with it?

  • ✅ Love it
  • ⚠️ Could be improved
  • ❌ Needs to change
  • ‘Branded’ conventions
  • Built up over 20 years of CSS
  1. Writing Selectors

  2. Organizing Rules

  • Two primary concerns:
  • Writing selectors
  • (or naming the elements we select)
  • Organizing selector rules
  • Across an entire project

Hopefully… More Consistent Code

Hopefully… More Reliable Code

Hopefully… More Organized Code

Hopefully… More Maintainable Code

Mental Model…

  1. Writing Selectors

  2. Organizing Rules

  • But the rules we define
  • For naming and organizing selectors
  • Always reflect a mental model of the language
  • How it works, and how we want to interact with it
  • So I like to keep that in mind when comparing…

Branded… Conventions are Useful

(as a point of reference)

  • What I call the ‘branded’ conventions
  • BEM, SMACSS, etc
  • These are systems that someone is marketing to us
  • And they can be useful as a point of reference
  • But it’s also important to remember…

Different Project Needs

  • No single solution will fit every project
  • Or every team
  • We’re all working under different constraints…

Different Team Structures

  • Different team structures
  • Different budgets & priorities
  • And those differences matter…

Just… 🤷🏻‍♀️ Conventions

Your mileage will vary

  • All just conventions
  • A set of guidelines someone found useful
  • In their org, their team, their code
  • Your mileage will vary

Just because InstaSalesFace Did It

Doesn’t mean we all need to

  • Just because instaSalesFace did it
  • Doesn’t mean it will help anyone else
  • In fact, the tools people use at that scale
  • Are often absurdly overblown for the rest of us
  • They’re trying to solve problems most developers don’t have
  • So there’s not a single correct approach
avatar

I think they are all pretty neat and I see the point…

— Chris Coyier
  • I tend to agree with Chris Coyier
  • They’re all pretty neat…
avatar

But I’m a bunch of years into this and still generally… write the selector I need and then style with that.

— Chris Coyier

There’s no Miracle Cure

Conventions won’t save us

  • Important to say up-front, there’s no miracle cure
  • If we refuse to weed the garden over time
  • Then the garden will have weeds
  • That work doesn’t go away because we switch to utility classes,
  • Or move our styles into Javascript

It’s a Process

Conventions can develop over time

  • Maintaining a convention, like weeding, is a process
  • Not a technical problem to ‘solve’ and move on

Prioritize Team Conversations

  • The result of ongoing conversations
  • They can change over time

Natalie Downe CSS Systems

2008
  • Most of conventions build on old ideas…
  • In 2008 Natalie Downe gave a talk
  • Very formative for me

~2006-2010… Major CSS Libraries

YUI, Blueprint, 960gs, etc…

  • She was reacting the the trends of the time
  • Large CSS libraries, one-size-fits all
  • The precursor to Bootstrap today

Central Class Library

<div class=" column col6of12 last " >

  • These libraries provide a list of classes
  • Takes away a lot of the planning required, but…
avatar

CSS frameworks decrease the maintainability of code.

— Natalie Downe, CSS Systems
2008
  • Over time, frameworks make CSS harder to maintain
  • Our experience as well
  • Designed for general use, quick-start
  • More than you need, but never exactly what you need
  • Often get removed (painfully)

A CSS System

  • Glossary of shared vocabulary for developers
  • Reusable set of markup patterns & CSS
  • Personalized for an individual site
  • Instead she proposed
  • Customized libraries, specific to a need
  • Design systems, in CSS

A CSS System Overall Structure & Individual Components

  • Overall structure & individual components
  • These are distinct, and separate

Internals should be 100% Fluid

(this was before RWD & Media Queries)

  • Components should fit in any container
  • Be able to resize as needed

Fit inside Any Container

(which may provide sizing)

Container Queries help here!
  • Sizes come from the container
  • Define the layout context for descendants
  • Components get put into different containers on the page

Afraid Of Heights

(the variable axis for blocks)

  • But usually don’t set the height
  • The variable axis for block elements
  • Content needs somewhere to expand
Blocks of text stack… [flow-block: flow-block]
  • Block elements expand on the block axis
  • If they can’t expand
  • Content has nowhere to go

Nicole Sullivan OOCSS

2009
  • Nicole Sullivan’s OOCSS
  • (came out around the same time)
  • Highlights similar ideas
avatar

A CSS “object” is a repeating visual pattern, that can be abstracted into an independent snippet of HTML, CSS, and possibly JavaScript.

— Nicole Sullivan, OOCSS
2009

Beyond Reusable Components

  • Not just components are reusable…

Components Share Patterns

Avoid even unique component styles

  • But the patterns that we use
  • across components

Combined into custom… Object Libraries

  • Snippets combined into a custom
  • Library of reusable patterns

1. Separate Structure & Skin

  • First rule of OOCSS
  • Separate structure (of object)
  • from skin (of that object)

Object Structure Minimal & Reusable

Object Skin Multiple Theme Options

  • Not necessarily distinct elements

Mix & Match Structures & Skins

(Unique components, without unique CSS)

  • But distinct selectors, so we can mix/match
  • If we build the patterns to be reusable

New pages should Rarely Require New CSS

  • This is the goal of a good system
  • Can we re-use existing styles across pages?
  • Even better: across components/features?

2. Separate Container & Content

e.g. “internals should be fluid”
  • Second, we separate
  • container and content
  • Similar to CSS Systems

Be Flexible

  • Container sets width
  • Content sets height
e.g. “be afraid of heights”

2009-Present Systems & Objects Repackaged

SMACSS, BEM, ITCSS, CUBE, etc…

Nearly every convention since is built on the ideas Natalie & Nicole presented 16 years ago.

Rely on… Cascade and Inheritance

  • And it mostly comes back to rules we find in the cascade
  • This is what the cascade & inheritance were designed for

Work from broad defaults at the start, towards narrow overrides at the end.

— Cascading Conventions
Cascade order of appearance
  • Efficiently describing broad patterns
  • And then providing targeted overrides as needed
Inverted triangle with
range across the top,
and specificity/explicitness
down the sides
2014 [Harry Roberts, Inverted Triangle CSS]

Narrow » Broad Reach How Many Elements?

Low » High Specificity What Selector Weight?

Generic » Explicit What Desired Impact?

From p {} through .text-center {}

Inverted triangle with layers,
wide top to narrow bottom:
settings, tools, generics, elements,
objects, components, overrides
2014 [Harry Roberts, Inverted Triangle CSS]
A graph
with specificity on the vertical axis,
and code line numbers horizontal,
divided into layers,
and a line showing that
specificity should only increase
throughout the code base
2014 [Harry Roberts, Inverted Triangle CSS]
  1. Elements grouped by Type
  2. Classes grouped by Effect
  3. IDs grouped by Component
2008 [Natalie Downe, CSS Systems]
  1. General Styles (resets, type, colors)
  2. Helper Styles (forms, errors, alerts)
  3. Page Structure
  4. Page Components
  5. Overrides (avoid when possible)
2008 [Natalie Downe, CSS Systems]
Inverted triangle with layers,
wide to narrow -
the top layers are sass-only, no output,
then global css layers,
and finally scoped components
2014 [Harry Roberts, Inverted Triangle CSS]
avatar

Macro Before Micro

— Andy Bell, CUBE CSS
2020
  • Working from the macro to the micro
  • Broad strokes, then minute details
avatar

Most of the work is already done for you with global and high-level styles.

— Andy Bell, CUBE CSS
2020
The inverted triangle but with Andy's CUBE names in place of Harry's layer names, so it says tokens, tools, compositions, utilities, blocks, and exceptions.
Cube roughly mapped to ITCSS

CSS shines Building Systems

  • The goal is building systems
  • Rather than one-offs.
  • Find what is consistent across components
  • Build abstractions
  • This is where CSS shines…

Platform Built-in Naming & Organizing Conventions

Where these other approaches lose me is when they push away from using the built-in features of the language. Some of them getting more and more extreme about re-inventing solutions that already exist!

HTML has Built-In Functionality

It’s not just CSS, HTML also has built-in functionality that we should avoid duplicating.

avatar

I decided to stop using the word semantics. Instead I talk about the UX of HTML…

— Vasilis van Gemert, The UX of HTML
avatar

Instead of explaining the meaning of a certain element, I show them what it does.

— Vasilis van Gemert, The UX of HTML

headings, links, forms, buttons, dialogs, summary/details, landmarks, attributes, etc…

HTML also has Built-In Names

diff-css
/* doesn't have to be fancy */
- .btn { … }
+ button { … }
Craig Abbott, Our CSS isn’t opinionated enough

There’s been a decades-long trend to decouple styles from functionality, but I agree with Craig Abbott that flexibility comes at a cost.

We’re giving developers too many options to break a system that we should be helping them maintain.

Don’t like naming things? Then Stop Naming Everything

  • .btn » button
  • .btn-submit » button[type=submit]
  • .link » a:any-link
  • .hidden » [hidden]
  • .active » [aria-current]
MDN on aria-current
avatar

Without intervention by the author, [the p selector] already knows how to identify paragraphs.

— Heydon Pickering, Semantic CSS With Intelligent Selectors
avatar

Building with accessible semantics from the get-go can give you expressive, meaningful style hooks for free.

— Ben Myers, Stateful, Semantic Selectors
css
/* expressive semantics */
form:has(:invalid) [type="submit"] { … }

/* some name we came up with? */
.form__btn--submit--invalid { … }
  • We can reference els & attrs in selectors
  • Also have access to pseudo-classes & pseudo-elements
  • Extended with ARIA attributes as needed
  • Selectors help enforce/encourage semantic HTML patterns
  • When we reduce this to a class-name string,
  • We lose all the meaningful built-in associations
css
a[href*="://"] { /* external links */ }
a[href^="https:"] { /* secure links */ }
a[href$=".pdf"] { /* pdf links */ }

button[aria-pressed=true] { /* pressed buttons */ }
img:not([alt]) { /* images without alt text */ }
  • There’s so much we can do
  • Without ever coming up with our own names

Even ‘meaningless’ article & section Elements

  • Some of the newer elements don’t provide much
  • Unless we attach an accessible label,
  • article and section are basically fancy divs
  • We use them anyway!
  • Why make up our own names, when HTML provides them?

Dealing With Specificity

CSS Selectors Specification
  • We already talked about specificity

Specificity is Just a “Heuristic”

It’s useful until it isn’t

It’s a practical assumption that more targeted styles should override less targeted styles. That’s usually true!

css
h2:has(> button[aria-expanded="false"]) + div {
  display: none;
}
Adrian Roselli, Disclosure Widgets

And I think it’s something we should lean into rather than avoiding. Selectors are primarily for selecting, and they’re meant to be expressive.

css
.block .element.modifier { /* 3 */ }
.block__element--modifier { /* 1 */ }

Removing specificity is often accomplished by avoiding semantics, and re-naming everything in one place – where we’re most likely to have name conflicts.

❗important 💣

Then getting mad about the results, and using importance to blow up the whole thing.

So Many Rules

  1. Universal *
  2. Element types
  3. Reusable .classes & [attributes]
  4. Unique #IDs

We don’t need to limit ourselves in this weird way. Classes are not the only option, and we’re allowed to write full sentences.

css
.card.info { border-color: teal; } /* ✅ */
.card--warning { border-color: orange; } /* ❌ */
.card { border-color: gray; }
  • Specificity should be a useful tool
  • We want modifiers to override defaults
  • And source-order is a fragile way to do that
  • Removing all specificity makes life harder, not easier

When specificity falls short Use Layers & Scopes

(still meaningful and expressive)

Still, there are times when specificity falls short, and we need an escape hatch. That’s when we should consider using scope to target selectors more narrowly, or layers to clarify selector priorities.

A grid of overlapping
'scope' columns (buttons, cards, logins)
and 'layer' rows
(default, theme, component).
Each scope crosses all layers,
and each layer crosses all scopes.

Scopes help us organize by component, while layers help us organize by purpose. So a single file component will likely describe a single scope, while it might include several layers that are shared across multiple components.

scope

Browser support for scope

I know browser support for scope isn’t ready for most people, but it will be soon. We’ll talk more about progressive enhancements, but in the meantime there are a number of scoping tools that can help.

A graph
with specificity on the vertical axis,
and code line numbers horizontal,
divided into layers,
and a line showing that
specificity should only increase
throughout the code base
2014 [Harry Roberts, Inverted Triangle CSS]

On the other end we can use layers to start segmenting our code, so there’s less potential for specificity issues.

The same specificity graph,
with a solid line after the generic layer
where the specificity curve breaks
and starts lower
2014 [Harry Roberts, Inverted Triangle CSS]
The same specificity graph,
with solid lines after the generic and elements layers,
and the specificity curve
starting over lower down in each one
2014 [Harry Roberts, Inverted Triangle CSS]
The same specificity graph,
with solid lines after the generic, elements, and objects layers,
and the specificity curve
starting over lower down in each one
2014 [Harry Roberts, Inverted Triangle CSS]
The same specificity graph,
with solid lines between all five layers --
generic, elements, objects, components, and utilities --
and a separate specificity curve inside each layer
2014 [Harry Roberts, Inverted Triangle CSS]
html
<template>…</template>
<style>
@layer components {
  /* … */
}
</style>
Single File Components

Layer everything Mostly in Big Buckets

@layer reset, default, theme, patterns, layout, content;

Layering everything is good, because it keeps you flexible for adding new layers when and where you need. But generally I prefer large buckets over managing a long list of special layers.

Use un-layered for Prototyping & DeBugging

Encourages Nuanced & Explicit Priorities

How can we Use <feature> With <tool>??

Eg ‘tailwind’ or ‘Emotion JS’…

Tools should Understand Design

Can it handle colors and lengths?

Tools should Let Us Use CSS Features

(otherwise ‘tools’ become obstacles)

html
<div class="md:flex">
  <div class="md:flex-shrink-0">
    <img class="rounded-lg md:w-56" src="..." alt="">
  </div>
  <div class="mt-4 md:mt-0 md:ml-6">
    <div class="uppercase tracking-wide text-sm text-indigo-600 font-bold">...</div>
  </div>
</div>

I don’t Get It ¯\_(ツ)_/¯

When you… reduce the amount of time you spend writing and editing CSS… you must instead spend more time changing HTML classes…

— Nicolas Gallagher, About HTML semantics and front-end architecture
A woman in a suit kneels to pet cute ducklings while the mother duck removes a bill from her purse. The text underneath says colour.css / layout.css / typography.css
credit: CSS Systems
Avoid Cute Duckling Scams
Poetic CSS by OddBird
Miriam Suzanne, Poetic CSS Course

We’ve started to refer to the OddBird approach as ‘Poetic CSS’ – and I’m currently releasing a course about it. The first module is available, and more are coming soon. We’ll provide a discount for everyone here if you’re interested.

PoetiCSS

That’s a play on poetiCss, for any philosophy nerds

avatar

Say exactly what you mean using efficient and expressive language that has a broad reach and room for interpretation.

— Miriam Suzanne

I’d summarize it something like this.

Use built-in CSS Language Features

CSS provides a lot of expressive features – various selectors, specificity, layers, queries, units, inheritance, custom properties, and so on. These are all useful tools!

Like poetry, it helps to have a wide vocabulary, that is used efficiently.

Write Meaningful Selectors

The goal of a selector is to select things

Follow the Cascade From Macro to Micro

Prefer Global Styles

A wider cascade Allows More Nuance

Let Specificity Help

Heuristics are useful

Use @layer for layering

Based on purpose

Use @scope for scoping

Based on context

css
@scope (prose-block) to ([data-scope]) {
  p { … }
  ul { … }
  blockquote { … }
}

Use Nesting for modifiers

css
a {
  &:any-link { … }
  &:focus, &:hover, &:active { … }
  &[aria-current] { … }
  &.call-to-action { … }
}

Enumerated classes Become Attributes

css
.card.big { /* classes */ }
.card--big { /* BEM */ }

/* Custom element with attributes */
my-card[data-size="big"] { /* … */ }
Keith Cirkel, CSS Classes Considered Harmful

Use Custom Elements

css
.Card { /* … */ }
my-card { /* … */ }
Keith Cirkel, CSS Classes Considered Harmful

Content… Should be Fluid

2008 [Natalie Downe, CSS Systems]

Layouts… Provide Structure

2008 [Natalie Downe, CSS Systems]

Don’t Overly Sandbox

Styles should be reusable…

2008 [Natalie Downe, CSS Systems]

Focus on What Not Where

2008 [Natalie Downe, CSS Systems]

Get context from Custom Properties

css
a { text-decoration: var(--link-decoration, underline); }
nav { --link-decoration: none; }
  • Custom properties can be set contextually

Take care Overriding Styles

css
h2, h3, h4, h5, h6 {
  margin-block-start: 1lh;

  &:first-child {
    margin-block-start: unset;
  }
}
css
h2, h3, h4, h5, h6 {
  &:not(:first-child) {
    margin-block-start: 1lh;
  }
}
  • Use :not() to exclude selectors
css
[hidden] { display: none !important; }
[visually-hidden]:not(:focus-within) {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}
CSS Utilities
  • Utilities are useful!
  • We’ll often use attributes instead of classes
  • I noticed that CUBE does too
html
<!-- Element-attached/inline -->
<div style="--ease: var(--in-out-back);">
css
[style*='--ease'] {
  --in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);
  --out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --in-out-back: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
Custom Property Utilities
Flexible Grid Settings: present, debug

Don’t trust CSS Abstinence Rules

  • Avoiding the core features of CSS
  • Doesn’t make it better,
  • It just makes us work harder
  • No wonder we think CSS is broken,
  • We’ve all collectively ‘agreed’
  • Not to use any of the features!

Trust The Flow

  • Trust document flow
  • (not just normal flow layout,
  • but the flow of each layout system)
  • The flow of value resolution,
  • Cascading and inheritance
  • The flow of browser/author/user collaboration

Think in Systems

  • Even when we’re working on details
  • We want to think in systems
  • Not just the individual components
  • But the patterns that they share
  • And how they combine to create new ideas
  • But those big ideas have to fit a small space…

Be Concise

  • We want to be concise
  • Only say what’s essential
  • To get our design across
  • (I don’t mean minimalist design always,
  • But minimal constraints to achieve it)

Rely on… Expressive SubText

  • Relying on the subtext implications
  • Like relative units and built-in keywords
  • Wherever we can, using implied or intrinsic
  • Rather than explicit constraints
  • To make sure we still…

Say What You Mean

  • Say what we mean
  • The goal isn’t brevity at all cost
  • But to convey as much information as possible
  • About our intentions
  • In syntax that the browser understands
avatar

CSS is unlike anything else… designed for the realities of a flexible, multilingual, multi-device web.

— Rachel Andrew, The Way We Talk About CSS

Write CSS
Not too much
Mostly Reusable Patterns

Next module… Modern & Resilient

« back to resources
SlideDeck Controls

View

Keyboard shortcuts
cmd/ctrl-k:
Toggle this control dialog
cmd/ctrl-shift-enter:
presentation (from first slide)
cmd/ctrl-enter:
presentation (from active slide)
alt-enter:
in speaker view (following active slide)

Color Settings