slides.oddbird.net/mixins/cssday/

CSS Functions & Mixins Is Sass Dead Yet?

slides.oddbird.net/mixins/cssday/

@ CSS Day, NL

How many of you Wrote CSS Before Nesting?

(Baseline 2023)

How many of you Wrote CSS Before Nesting
and Color-Mix()?

(Baseline 2023)

How many of you Wrote CSS Before Nesting
and Color-Mix()
Wrote CSS Before Custom Props?

(Baseline 2017)

How many of you Wrote CSS Before Nesting
and Color-Mix()
Wrote CSS Before Custom Props
Wrote CSS Before Sass
Built Sites Before CSS
Built Sites Before <font>
Are Really Old?

No Deep-Nesting
No Color Spaces
No Variables
No Build Steps

Things were also Way More Complicated

lol, Grid Systems

.col2of6 {        /* where is col2of6? */
  float: left;    /* why do we float it? */
  display: inline;      /* what? */
  width: 31.707%; /* where’s that % from? */
  margin-right: 2.439%; /* another one? */
}

The Meaning Problem… Repetition is hard to maintain.
Relationships are hidden.
Reasons are unclear.

/* originally +grid-col(3) */
article {
  @include span(3);
}

A simple language Can Cause Complex Code

Some language complications Can Simplify Code

article { grid-column: span 3; }
main { grid-area: main; }
@function --my-function(--optional, --parameters) {
  result: 4; /* returned value */
  --any-logic: using custom property syntax;
  --declarative: like any other CSS context;
}

CSS Functions Act Like Values

button {
  padding: --space();
  background: --theme-color(brand);
  border: var(--border-width);
}

A declarative Bucket of Unordered Properties

External Variables Are Available Inside

Parameters & Internal Variables are Private

Can Contain Media & Other Conditions

@mixin --my-mixin(--optional, --parameters) {
  /* all styles are output? */
  --this-is: public;
  padding: 1em 2em;
}

CSS Mixins Act Like Nested Rules

aside {
  @apply --callout-box(info);
  position: relative;
}

Very Limited Prototype

These things will eventually work…

  • Directly nested styles
  • Parameters
  • Moving definitions later

Inline conditions With the if() Function

Conditions…

  • media()
  • supports()
  • style()

Just the latest Inspired By Sass et al

  • Variables
  • Math and color functions
  • Nesting
  • if()
  • @function
  • @mixin
screenshot

Cascade & inherit As Properties of Elements

Sass variables use Lexical Scope

html { $color: green; }
body { /* $color == undefined */ }

Custom properties use DOM Scope

html { --color: green; }
body { /* --color == green */ }

Value Resolution

  1. Filtering
  2. Cascading
  3. Defaulting (includes inheritance)
  4. Resolving
  5. Formatting
  6. Constraining

On each html element
For every css property
We need exactly one value

Filtering Finds Relevant Declarations

  1. In a stylesheet that applies (see media attr)
  2. Not in a false conditional rule (see at-rules)
  3. In a selector that matches the HTML Element
  4. Is syntactically valid

✅ Valid Syntax

html { color: teal; }

Not Valid Syntax

html { color: 3em; }
html {
  /* color: <color>; */
  color: teal; /* applied! */
  color: 3em; /* discarded */
}

✅ Valid Syntax

html { color: var(--my-property); }

✅ Valid Syntax

html { --my-property: teal; }

✅ Valid Syntax

html { --my-property: 3em; }

✅ Still Valid Syntax

html {
  --my-property: 3em;
  color: var(--my-property);
}

✅ Still Valid Syntax

html {
  --my-property: 3em;
  color: var(--my-property);
}

@property --my-property {
  syntax: "<color>";
  initial-value: teal;
  inherits: true;
}

Declarations containing The var() function

Are not evaluated at parse time

Declarations containing The var() function
or if() function
or any --custom() function

Are not evaluated at parse time

Invalid At Computed Value Time

“IACVT”

Value Resolution

  1. Filtering
  2. Cascading (resolving conflicts)
  3. Defaulting
  4. Resolving

Cascade… Resolves Conflicting Values

When we have multiple declarations

Like other properties Variables Cascade

html {
  --color: white !important;
  --color: black;
}

Variables inside Functions Don’t Cascade

Cascade Still Includes

  1. Origins
  2. Context (Shadow vs Light DOM)
  3. Element Attachment (Inline vs Selectors)
  4. Layers
  5. Specificity
  6. Scope
  7. Order of Appearance

Value Resolution

  1. Filtering
  2. Cascading
  3. Defaulting (filling in empty values)
  4. Resolving

Defaulting process Depends on the Property

Some Properties Inherit

html { color: red; }
body { color: blue; }
body > main { /* inherits… ? */ }
html { color: red; }

body > main { /* inherits… ? */ }
html { color: red; }
/* body inherits red from html */
/* body > main inherits red from body */ }

Custom properties Can Carry Hidden Context

Allowing us to Inherit Across Generations

Generally… Un-styled Inline Boxes (spans)
Should Blend In

And so… Text Styles Inherit

While layouts and other… Box Styles Do Not Inherit

Each property has an initial value, defined in the property’s definition table.

– Cascade & Inheritance, § 7.1. Initial Values

  • pick a property (display?)
  • Look it up on MDN
  • Check ‘formal definition’
  • Link to spec

Custom properties… Have No Definition Table?!

Default initial value “The Guaranteed Invalid Value”

like Undefined in JS

@property --border-size {
  syntax: "<length>";
  initial-value: 1px;
  inherits: false;
}

Typed properties Will Never Fallback

Function Types

@function --color() returns <color> {/* … */}

explicit defaulting… “Global Keywords

  • initial (from spec)
  • inherit (from parent element)
  • unset (inherit or initial)
  • revert (from browser)
  • revert-layer (previous layer)

Defaulting keywords Apply To Custom Properties

Functions should Pass Through Keywords

(not implemented yet)

Value Resolution

  1. Filtering
  2. Cascading
  3. Defaulting
  4. Resolving

Computed Values Inherit

Move through DOM tree Resolve Parent,
then Default Children

Browsers Optimize Constantly

To cause issues Trigger Re-Style on More Elements

If you don’t need it anymore… Then Don’t Use It 🎉

But if you’re Building Design Systems

Sass provides… Loops, Lists, & Objects 🎉

Why make the browser Solve Server-side Problems?

It still isn’t (But With More Features)

But improving The Syntax & Maintainability

If you just want… To Code Some Styles Good