« resources

Company Workshop

Naming & Organizing Conventions

towards a cascade-aligned programming

workshops.oddbird.net/rf24/conventions/

Cmd/Ctr-K for Controls

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

  1. Mental Model

  2. Writing Selectors

  3. Organizing Rules

  • But the rules we define
  • For naming and organizing selectors
  • Often reflect some mental model of the language
  • How it works, and how we interact with it

Branded… Conventions are Useful

(as a point of reference)

Different Project Needs

  • Important to remember
  • Different projects have different needs,
  • 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 work for the rest of us
  • 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 who says
  • 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
  • To make CSS maintenance go away
  • If you refuse to weed the garden
  • Then the garden will have weeds

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
  • Conventions need to be documented and maintained

Prioritize Team Conversations

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

If it’s not documented, It Doesn’t Exist

  • This documentation is essential
  • Communicate our priorities and goals and approaches
  • With new team members, or with ourselves next week
  • If a convention isn’t documented, it doesn’t exist
  • It will be impossible to maintain
  • Most of conventions build on old ideas…
Headshot of Natalie Downe.

Natalie Downe

CSS Systems, 2008

  • 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

  • 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… [demo link]
  • Block elements expand on the block axis
  • If they can’t expand
  • Content has nowhere to go
Headshot of Nicole Sullivan.

Nicole Sullivan

Object Oriented CSS, 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

Beyond Reusable Components

  • A reminder
  • 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…

  • I’m going to quote these two a lot
  • Nearly every convention since
  • Is built on the ideas they presented
  • 16 years ago

Macro Before Micro

From CUBE CSS by Andy Bell
  • Something they all share
  • 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

Rely on… Cascade and Inheritance

  • This is what cascade & inheritance were designed for
  • Achieving broad consistency
  • With very little code
  • And then providing targeted overrides as needed

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

  • Both HTML & CSS provide a starting point
  • built-in naming & organizing convention

Start with… Semantic HTML

  • Converting a static design to code
  • Starts with semantic HTML

Built-in Functionality

  • HTML gives us so much for free!
  • Before we start adding any classes
  • We get built-in naming
  • From meaningful HTML elements and attributes
  • Also interactive links, buttons, form controls, etc

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?
avatar

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

— Ben Myers, Style with 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
css…
.flow > * + * {
  margin-block-start: var(--flow-space, 1em);
}
Axiomatic CSS and Lobotomized Owls by Heydon Pickering
  • Selector combinators let us expand on that
  • Defining relationships

Intelligent” Selectors

No “intervention by the author”

Semantic CSS With Intelligent Selectors by Heydon Pickering

Dealing With Specificity

Selectors (Level 4)
  • While we’re talking about selectors
  • Let’s dig into specificity a bit
css…
* { /* universal */ }
p { /* type */ }
.summary { /* attribute */ }
#call-to-action { /* id */ }
Simple Selectors
  • There are four ‘categories’ of selector
  • Each with increasing priority in cascade…
css…
* { /* 'universal' */ }
The universal (star) selector
  • The universal (star) selector
  • Alone in its category…
OddBird.net with red outlines around every element on the page
Similar to initial values - generic and universal
  • Selects all HTML elements
  • (but not pseudo-elements like before or after)
  • We can use this for extremely generic resets
  • Or initial values, like we get from the spec
  • But more often use it contextually
  • Narrowed by additional selectors
css…
button, div, span {
  /* 'type' (element) */ }
::before, ::after, ::part() {
  /* 'pseudo-element' */ }
Type (element) selectors
  • Element & pseudo-element ‘type’ selectors
OddBird.net with red outlines around every link on the page
Similar to browser defaults - provide a baseline
  • Are much more targeted, but still fairly broad
  • Help us establish broad defaults
  • Similar to user agent styles
css…
.action, .summary {
  /* 'class' */ }
:hover, :user-invalid {
  /* 'pseudo-class' */ }
[type=“submit”] {
  /* 'attribute' */ }
Attribute selectors
  • Attribute selectors
  • Include classes and pseudo-classes
  • Select elements based on any attributes or states
  • Classes are just a special attribute shorthand
  • Where we have the most control & flexibility
OddBird.net with red outlines around only the nav links which have a data-nav attribute
Establish reusable patterns
  • Great for defining reusable patterns
  • Become the backbone of our design systems
css…
#send { /* 'id' */ }
ID selectors
  • Finally ID selectors
  • Valid ID’s are required to be unique on a page
OddBird.net with red outlines around only the logo
One-off overrides
  • Should only ever select one element per page
  • Extremely targeted/specific styles
css…
h2:has(> button[aria-expanded="false"]) + div {
  display: none;
}
Disclosure Widgets by Adrian Roselli
  • We can combine these selectors
  • to express fairly complex ideas
  • Read from right to left…
  • A div that comes after an h2
  • (which has a button child, that is not expanded)
  • Look at all that information we’re communicating to the browser!

Specificity is a “Heuristic

a practical assumption that approximates the goal
  • But what we’re worried about now
  • Is the specificity of a selector in the cascade
  • And for this step the browser uses a heuristic
  • a practical assumption

More Explicit Selectors
are Likely
More Important

  • More explicit selectors
  • (more narrowly targeted to specific elements)
  • are likely more important than less specific selectors
  • That makes some sense, right?
  • One-offs override reusable patterns,
  • which override element defaults,
  • which override global initial values?
css…
/* 1 IDs, 2 attributes, 2 element type */
/* specificity: 1,2,2 */
form#contact button[type='submit']:active {
  border-color: seaGreen;
}
  • So we count up how many terms we used in our selector,
  • And which category those terms belong to
  • Here the border-color declaration has a selector
  • With 1 ID
  • 2 Attributes
  • 2 Element types
  • A specificity of 1, 2, 2
Our old coin sorter, with all slots crossed off except for the largest one with coins in it, and an arrow pointing at those coins that says 'move on'
  • The total isn’t what matters
  • We actually compare the categories one at a time

Like Versioning [1,0,2] vs [0,3,2] vs [0,2,3]

  • Like software versions
  • We can look at the first number
  • That might give us a winner already

Move on when tied [0,3,2] vs [0,2,3]

  • We only have to look at the next column (attributes)
  • If there’s a tie in the first

Heuristics Are Assumptions

  • It’s a good heuristic
  • Most of the time
  • But heuristics are assumptions, and…

Assumptions Often Fail

Especially “At Scale

  • Assumptions always fail at some point
  • So the more code we write,
  • (The larger our code base)
  • The more likely we are to find those exceptions…
css…
/* …default table styles… */
table[rules=cols i] > tfoot > tr > td,
table[rules=cols i] > tfoot > tr > th,
table[rules=all i] > tfoot > tr > td,
table[rules=all i] > tfoot > tr > th {
  border-color: black;
}
html.spec.whatwg.org
  • Even browsers have some very specific defaults
  • Would be an issue, without origins
  • It’s good for this declaration to be specific
  • But it’s still just a specific default
  • (essential the specificity is contained)
  • On the other end…
css…
[hidden] { display: none; }
  • There are some broadly-defined defaults
  • Like display:none on the hidden attribute
  • Are really important!
  • Don’t want to override setting display to grid.
  • It’s a simple selector with broad reach
  • But shouldn’t be low priority

One Flexible Layer

  1. Universal *
  2. Element types
  3. Reusable .classes & [attributes]
  4. Unique #IDs
  • This becomes especially problematic
  • Because we only fully control
  • One of Four specificity categories
  • (Class and attribute selectors)
  • All the rest are limited in some way
css…
.block .element.modifier { /* 3 */ }
.block__element--modifier { /* 1 */ }
  • So we spend our time
  • Arguing over how many classes or attributes to use
  • Forcing lower and lower specificity
  • Through intricate naming conventions…
  • But that all requires careful coordination…

important 💣

  • Which can fall apart
  • If someone brings importance
  • To a specificity fight…
css…
.🤬-bootstrap {
  font-weight: bold !important;
}
  • Or a third-party tool
  • Doesn’t play by the same rules

😩🤬😩

  • And then we get frustrated
Specificity is Useful [present, debug]
  • Which could be a useful tool

demo:

  • We want modifiers to override defaults
  • Source order is fragile

When specificity falls short We Need an Escape Hatch

(still meaningful and expressive)

  • Still, there are time
  • When specificity falls short
  • We need an escape hatch
  • that’s still meaningful and expressive
Inverted triangle with
range across the top,
and specificity/explicitness
down the sides
Inverted Triangle CSS by Harry Roberts
Upside-down headshot of Harry Roberts.

Harry Roberts

Inverted Triangle CSS, 2014

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
range across the top,
and specificity/explicitness
down the sides
Inverted Triangle CSS by Harry Roberts
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
Inverted Triangle CSS by Harry Roberts
Inverted triangle with layers,
wide top to narrow bottom:
settings, tools, generics, elements,
objects, components, overrides
Inverted Triangle CSS by Harry Roberts
  1. Elements grouped by Type
  2. Classes grouped by Effect
  3. IDs grouped by Component
From 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)
From 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
Inverted Triangle CSS by Harry Roberts
css…
@layer settings {}
@layer tools {}
@layer generic {}
@layer elements {}
@layer objects {}
@layer components {}
@layer overrides {}
  • These provide us with…

Layers of Specificity

  • Layers of specificity
  • First we choose the declaration
  • In the highest layer
  • And only if there are multiple from that layer
  • Then we compare specificity

@layer { … }

  • A layer rule starts with at-layer
  • And then brackets
  • We can put any CSS inside those brackets…

@layer <name> { … }

  • And we can optionally give our layers a name
  • Any name we want
css…
@layer reset {
  audio[controls] { display: block; }
  [hidden] { display: none !important; }
}

@import url(…) layer;
@import url(…) layer(<name>);

  1. @layer settings { … }
  2. @layer tools { … }
  3. @layer generic { … }
  4. @layer elements { … }
  5. @layer objects { … }
  6. @layer components { … }
  7. @layer overrides { … }
As many layers as we want!
  1. @layer Utilities { … }
  2. @layer Components { … }
  3. @layer Themes { … }
  4. @layer Frameworks { … }
  5. @layer Resets { … }
Any names that we want!
css…
@layer reset { /* least powerful */ }
@layer default { /* … */ }
@layer theme { /* … */ }
@layer components { /* more powerful */ }
/* unlayered styles: most powerful */
Stack in the order they’re introduced

@layer <name>, <name>, <etc>;

Explicit Layer Order

Specificity is Contained

Only compared inside a layer

Quick Layers Live Demo [present, debug]

demo:

  • Source order is fragile, layers are explicit
  • Specificity only matters inside a layer
  • Un-layered styles win by default
  • Layers stack in order
  • Define the order up front
css…
/* establish layer order */
@layer one, two, three;

/* add code to layers as needed */
@import url(two.css) layer(two);
@layer three {}
@layer one {}
@layer two {}
  • Generally, imports have to come first
  • Layer lists are allowed before imports
  • Order matters!
css…
@layer components {
  @layer state {}
}

/* access nested layers */
@layer components.state {}
Nesting Layers
css…
/* system.css */
@layer theme {}
@layer components {}
Nesting Layers (in files)
css…
@import url(system.css) layer(system);

@layer system.theme {}
@layer system.components {}
Nesting Layers (from imports)
css…
@import url(system.css) layer(system);

@layer system.theme {}
@layer system.components {}
@layer system.custom {}
Nesting Layers (from imports)
  • Add your own sub-layer to an imported layer!
css…
@import url(bootstrap.css) layer(bootstrap.theirs);

@layer bootstrap.ours {
  /* anything here will override bootstrap */
}
css…
@layer components {
  @layer defaults, themes, state;
}
Order Nested Layers

Not Escalating ❗️importance

Managing Priorities

More Cascade Control
Fewer Specificity Hacks

Like Origins, ❗️important Layers Reverse

  1. Resets
  2. Themes
  3. Components
  4. ❗important Components
  5. ❗important Themes
  6. ❗important Resets

Protect Styles From Future Layers

Getting Started

my recommendations

(your mileage may vary)

Define a A Layer Order

See example layer orders
css…
/* add as the first styles */
@layer reset, framework, components, utilities;
Start simple, and append as needed…
html…
<style>/* keep this before linked styles */
@layer reset, framework, components, utilities;
</style>
<link rel="stylesheet" href="">
<link rel="stylesheet" href="">
Can live in the HTML / template

If Possible Layer Overall Architecture

html…
<style>
@layer reset, framework, components, utilities;
@import url() layer(reset);
@import url() layer(framework);
</style>
Use (non-nested) imports

Prioritize Dependencies

*Including inter-org dependencies

  • Like resets, design systems, component libraries
  • Anything not project-specific

Clearly define… Each Tool’s Priority

Clearly define… Tool-Specific Overrides

css…
@import url(bootstrap.css) layer(bootstrap.vendor);

@layer bootstrap.overrides {
  /* anything here will override bootstrap */
}

As you go, Update Layer Order

Working from Lowest to Highest

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
Inverted Triangle CSS by Harry Roberts
html…
<template></template>
<style>
@layer components {
  /* … */
}
</style>
Single File Components

Don’t (Usually) Need Layers Per-Component

As useful, Layer Inside Components

Once We Start Layering

*the styles will be hidden from older browsers

There’s No Harm Layering More

Encourages Nuanced & Explicit Priorities

For flexibility… Layer Everything

Use un-layered for Prototyping & DeBugging

Tools should Understand Design

Can it handle colors and lengths?

Tools should Let Us Use CSS Features

(otherwise ‘tools’ become obstacles)

html…
<div class="Bgc(#0280ae.5) C(#fff) P(20px)">...</div>
No relation to Atomic Design
html…
<body class="bg-green black-70 pa4">
  <h1 class="f1">...</h1>
</body>
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 ¯\_(ツ)_/¯

Often called Functional CSS

CSS is All About Context

Design is All Side Effects

CSS can’t be Functionally “Pure

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
css…
.btn {
  @apply font-bold py-2 px-4 rounded;
}
.btn-blue {
  @apply bg-blue-500 text-white;
}
.btn-blue:hover {
  @apply bg-blue-600;
}
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 photo: CSS Systems
Avoid Cute Duckling Scams

Paradigms… Object-Oriented or Functional

  • CSS is classes with properties, and inheritance
  • It’s clearly meant to be ‘object oriented’
  • These comparisons can be useful
  • But CSS isn’t a general-purpose language
  • It’s domain-specific, resilient, and contextual

Websites don’t need to cannot possibly look the same in every browser.

— The web, paraphrased

  • We’ve talked a lot about resilience
  • A web on everything, for everyone
  • It’s fundamentally impossible
  • For our website to look the same everywhere
  • In every browser

The fact we can control a paper page is really a limitation of that medium.

— John Allsopp, A Dao of Web Design

  • And that’s a feature of the medium
  • A design decision that’s been built-in
  • And so CSS is easiest to write & maintain
  • When we embrace the way it’s designed
  • (The Dao of web design)
avatar

Be the browser’s mentor, not its micromanager.

Andy Bell

  • And our role in the system
  • To quote Andy Bell
  • We want to be the browser’s mentor
  • And not it’s micromanager

Define some constraints. Let the language work out the details.

— Keith J Grant

Resilient, Declarative, Contextual
  • We want to
  • Design some constraints
  • Let the language work out the details

If I were to brand OddBird Conventions

  • If I were to brand our conventions at OddBird
  • (at a high level)
  • The way we approach and write CSS,
  • I would call it something like…

Poetic CSS

  • Poetic CSS

PoetiCSS

  • Or poetiCss
  • For any philosophy nerds

Use built-in CSS Language Features

  • CSS provides a lot of features
  • Selectors and specificity
  • Attribute selectors and pseudo-classes
  • Layers, queries, custom properties
  • These are all useful tools!
  • Like poetry: wide vocabulary, used sparingly

We Mix & Match

CSS Systems, OOCSS, ITCSS, CUBE…

Follow the Cascade Prefer Global Styles

Write Meaningful Selectors

Not Just Classes

Use custom elements, attributes, ids, pseudos…

CSS Classes considered harmful by Keith Cirkel
css…
.card.big { /* classes */ }
.card--big { /* BEM */ }

/* Custom element with attributes */
my-card[data-size="big"] { /* … */ }
CSS Classes considered harmful by Keith Cirkel

Work In Layers

(with or without @layer)

A Wider 🌊 Cascade Allows More Nuance

Content… Should be Fluid

Containers… Provide Structure

Don’t Overly Sandbox

Styles should be reusable

From CSS Systems

Focus on What Not Where

From CSS Systems

Rarely use Location-Dependent Styles

From OOCSS

BEM often Gets This Backwards

  • On the surface this seems like a goal of BEM
  • But in practice it often ends up making the issue worse

The goal is… Portable Selectors

css…
/* .page header { … } */
.page__header {}
BEM Avoids Nesting
  • BEM syntax often avoids nesting
  • By combining context and content into a single selector
  • But that’s not more portable
  • It’s still tied to a specific context
css…
header.masthead {}
Prefer Modifiers
css…
/* Runs the risk of becoming out of date; not very maintainable. */
.blue { color: blue; }

/* Depends on location in order to be rendered properly. */
.header span { color: blue; }

/* Too specific; limits our ability to reuse. */
.header-color { color: blue; }

/* Nicely abstracted, very portable, doesn’t risk becoming out of date. */
.highlight-color { color: blue; }
Harry Roberts, CSS Guidelines

Context from Custom Properties

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

Take care Overriding Styles

css…
a:not([data-link]) {
  text-decoration: var(--link-decoration, underline);
}

nav {
  --link-decoration: none;
}
  • Use :not() to exclude selectors
  • Use custom properties to provide a default, and explicit override
  • (This also works as a solution to the question about display/hiding)

CSS Utilities Have One Job

  • The most popular and controversial trend
  • Is utility-first CSS
  • But utility classes have a long history
  • Going back to OOCSS, if not earlier
  • The job is to do one simple thing
  • (any simple thing)
css…
.wrapper {
  margin-inline: auto;
  padding-inline: 1rem;
  max-width: 60rem;
}
  • Useful!
  • For common & simple patterns
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;
}
  • Doesn’t have to be a class
  • We’ll often use attributes instead
  • I noticed that CUBE does too
  • I find these nicely parallel
css…
.bg-primary { background: #ff00ff; }
.bg-secondary { background: #ffbf81; }

[data-bg=primary] { background: #ff00ff; }
[data-bg=secondary] { background: #ffbf81; }
For stored values from data
  • This especially makes sense
  • When using them to pass info from a database or JS
  • We can provide tokens as utilities
  • And apply them in our markup if needed
css…
[data-bg] { background: var(--canvas-color); }
[data-bg=primary] { --canvas-color: #ff00ff; }
[data-bg=secondary] { --canvas-color: #ffbf81; }
css…
[style*='--canvas-color:'] {
  background: var(--canvas-color);
}
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

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

« resources

Company Workshop

Naming & Organizing Conventions

Bring this workshop to your company.
Slide Controls

View:

Navigate slides using the arrow-keys.