slides.oddbird.net/workshops/23-smashing-de/1-cascading-1/

Cascading Styles pt. 1

slides.oddbird.net/workshops/23-smashing-de/1-cascading-1/

@ Smashing Conf Freiburg

Web for all. Web on everything.

W3C Mission, Design Principles

It is required that HTML be a common language between all platforms

WWW Project

…This implies no device-specific markup, or anything which requires control over fonts or colors.

WWW Project

Gutenberg Press

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

– John Allsopp, 2000

Web styles… Must Be Contextual

Responsive to constant change

@media prefers-reduced-motion

@supports container-type: inline-size

Animation of twitter-like posts appearing

WWW parsers should ignore tags which they do not understand, and ignore attributes which they do not understand of tags which they do understand.

WWW Project

The web is designed for Progressive Enhancement

Provide hints that the browser may or may not use.

– Håkon Lie

Browsers Can Ignore Declarations

body {
/* Browser default `display: block` */
display: flex;
display: grid;
}

You can use it and not use it at the same time, because it works and it doesn’t work at the same time. It’s Quantum CSS! It’s Magic!

– Jen Simmons, Intro to Resilient CSS

Font Stacks

font-family: Consolas, Menlo, 'Courier New', monospace;

Providing Progressive Layers of Style

e.g. Mobile First

Browsers need To Understand Priorities

There are too many variables to consider. The point of CSS is to make it so you don’t have to worry about them all. Define some constraints. Let the language work out the details.

– Keith J Grant

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

– Rachel Andrew, 2018

We’re designing dynamic content with unknown collaborators on an infinite and unknowable canvas, across operating systems, interfaces, writing-modes, & languages

– me

HTML totally eliminates any visual creativity that a document’s designer might have.

– Roy Smith, 1993

The web would have become a giant fax machine where pictures of text would be passed along.

– Håkon Lie

<CENTER>This text is centered</CENTER>

<MULTICOL COLS="3" GUTTER="25">
<P><FONT SIZE="4" COLOR="RED"></FONT></P>
</MULTICOL>
<p><font color="red"></font><p>
<p><font color="red"></font><p>
<p><font color="red"></font><p>
<p><font color="red"></font><p>
<p><font color="red"></font><p>
<p><font color="red"></font><p>

A simple mapping between HTML elements and presentation hints.

– Håkon Lie

CSS Declarations

provide the presentation hints

p { color: red; }
<p></p>
<p></p>
<p></p>

Entire Style Sheets

<link rel="stylesheet" href="so-many-hints.css">
<style>...</style>

An ordered list (cascade) of style sheets. Referenced from the same document.

– Håkon Lie

💥🙈⁉️💥

<button style='color: blue'></button>
button { color: violet; }

For Browsers… Every Property
on Every Element
Must Have a Single Value

🤯⁉️

color: teal;
color: violet;
color: oklch(79.269% 0.171 70.67);
color: not-real;

The 🌊 Cascade Resolves 💥 Conflicts

Rules for… Cascading filters out
Inheritance fills in

  1. Is it marked as !important?
  2. Who requested the style?
  3. Does it come from the shadow DOM?
  4. Is it an inline style?
  5. What cascade layer is it in? (new)
  6. What is the selector specificity?
  7. How close is the scope root? (proposed)
  8. Which comes last?

This proposal tries to soften the tension between the author and the reader.

– Håkon Lie

The author often wants to give the documents a distinct look and feel, the user will set preferences to make all documents appear more similar.

– Håkon Lie

The user/browser specifies initial preferences and hands the remaining influence over to the document.

– Håkon Lie

body { margin: 8px; }
a:link { color: blue; }
div, section, article, p, ol, ul /* etc */ {
display: block;
}
h1, h2, h3, h4 /* etc */ {
font-weight: bold;
font-size: something big I dunno;
}

Initial Values are… Defined by Specification

Initial Values are… Specific to Each Property

Initial Values are… The Same On All Elements

👥 User Styles

Establish desired preferences

Cascade 🗺 Origins

  1. 🖥 User Agent (goes first)
  2. 👥 User (override browser)
  3. 🎨 Author (most powerful)

If conflicts arise the user should have the last word

– Håkon Lie

  1. ❗🎨 Author Important (goes first)
  2. ❗👥 User Important (override authors)
  3. ❗🖥 User Agent Important (most power)
  1. 🖥 User Agent Defaults
  2. 👥 User Preferences
  3. 🎨 Author Styles
  4. ❗🎨 Author Important
  5. ❗👥 User Important
  6. ❗🖥 User Agent Important

👎🏼 Authors Override Styles

in a rage-fueled display of brute force

👍🏼 Users Protect Styles

because legibility is important

Often Isolated

  1. 🎨 Author Styles
  2. ❗🎨 Author Important
  3. ❗…
  4. ❗…

For Custom Elements

(we won’t cover this in detail)

  • For normal styles, light > shadow
  • For important styles, shadow > light

Web ‘Components’ Are Not Site Components

Element-Attached Styles

<!-- Element-attached/inline -->
<button style='color: blue'></button>
/* Selectors */
button { color: violet; }

CSS Selectors & Specificity

(we’ll come back to layers)

Dealing With Selectors

.this-is a.selector {
/* declarations: here; */
}
button          { background: gray; }
.action { background: darkblue; }
[type=“submit”] { background: darkgreen; }
#send { background: maroon; }

Each Selector has a Weight Based on How Specific It Is

Heuristic

a practical assumption that approximates the goal

More Specific Styles
Likely
More Important

Four layers

  1. Universal * (go first)
  2. Element types (p, ul, body, etc)
  3. Reusable .classes & [attributes]
  4. Unique #IDs (most power)

Like Versioning (ID).(Class/Attr).(Element)

#contact-form .actions button[type='submit']:active { }
/* Specificity 1.3.1 - 1 ID, 3 Attrs, 1 Element */
#contact-form .actions button[type='submit']:active { }

Often written with commas Specificity of [1,3,1]

Compare from the left 1,0,2 vs 0,3,2 vs 0,2,3

Compare from the left 1,0,2 vs 0,3,2 vs 0,2,3

Assumptions Often Fail

Especially “At Scale

/* …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;
}

One Flexible Layer

  1. Universal *
  2. Element types
  3. Reusable .classes & [attributes]
  4. Unique #IDs
.block .element.modifier { /* 3 */ }
.block__element--modifier { /* 1 */ }
.🤬-bootstrap {
font-weight: bold !important;
}
@layer settings {}
@layer tools {}
@layer generic {}
@layer elements {}
@layer objects {}
@layer components {}
@layer overrides {}
@layer reset {
audio[controls] { display: block; }
[hidden] { display: none !important; }
}
  1. @layer settings { … }
  2. @layer tools { … }
  3. @layer generic { … }
  4. @layer elements { … }
  5. @layer objects { … }
  6. @layer components { … }
  7. @layer overrides { … }
  1. @layer Utilities { … }
  2. @layer Components { … }
  3. @layer Themes { … }
  4. @layer Frameworks { … }
  5. @layer Resets { … }
@layer reset { /* least powerful */ }
@layer default { /* … */ }
@layer theme { /* … */ }
@layer components { /* more powerful */ }
/* unlayered styles: most powerful */
@layer framework {
#menu .dropdown .menu-item {
background: whitesmoke; /* ✅ specificity! */
}

.menu-item {
background: lightcyan;
}
}
@layer framework {
#menu .dropdown .menu-item {
background: whitesmoke;
}
}
@layer override {
.menu-item {
background: lightcyan; /* ✅ layer! */
}
}
@layer one {}
@layer two {}
@layer one {}
@layer three {}
@layer one {}
@layer generic {
audio[controls] { display: block; }
}

@layer theme { /* … */ }

/* still a lower layer than "theme" styles */
@layer generic {
[hidden] { display: none !important; }
}
@layer generic {
audio[controls] { display: block; }
[hidden] { display: none !important; }
}

@layer theme { /* … */ }

Explicit Layer Order

Define it once, at the start

/* 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 {}
@layer components {
@layer state {}
}

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

@layer system.theme {}
@layer system.components {}
@import url(system.css) layer(system);

@layer system.theme {}
@layer system.components {}
@layer system.custom {}
@import url(bootstrap.css) layer(bootstrap.theirs);

@layer bootstrap.ours {
/* anything here will override bootstrap */
}
@layer components {
@layer defaults, themes, state;
}

Like Origins, ❗️important Layers Reverse

  1. Resets
  2. Themes
  3. Components
  4. ❗important Components
  5. ❗important Themes
  6. ❗important Resets
@layer reset {
audio[controls] { display: block; }
[hidden] { display: none !important; }
}

Prioritize -> Layers
Protect -> Importance

Not Just… ‘This is !important

(layers lower importance by default)

X Overrides Y
Because
‘Components’ Override ‘Defaults’