slides.oddbird.net/variables/smashing1020/

When Variables Cascade

@ SmashingConf Austin

I heard You Like Variables

a {
color: $brand-primary;
}
a {
color: @brand-primary;
}
render(
<a css={css`
color:
${brandPrimary};
`
}>...</a>
)

$name: value;

color: $name;

color: value;

Re-use Common Values

Single Source of Truth

Don’t Repeat Yourself

Provide Meaningful Names

hsl(329.8 67.7% 57.5%)

$brand-primary

$action

What about Variables In CSS?

2006… currentColor

From SVG 1 Borrowed for CSS 3

We Don’t Assign A Value

The current value Of the Color Property

From The Cascade

currentColor Also Cascades!

2014… Custom Properties

--aka: 'css variables';

Data on support for the css-variables feature across the major browsers from caniuse.com

-webkit-property
-moz-property
-<empty>-property

--property: value;

var( --property )

html {
--property: hsl(329.8 67.7% 57.5%);
}

a {
color: var(--property);
}

.ಠ_ಠ {
  --(╯°□°)╯: ︵┻━┻;
} is valid CSS.

– Tab Atkins, @tabatkins

Custom Properties Inherit By Default

Establish Global Design Tokens

// colors
$brand-color: hsl(330, 100%, 45%);
$action: $brand-color;

// sizes
$gutter: 1.5rem;
$spacer: $gutter * 3;
html {
/* colors */
--brand-color: hsl(330, 100%, 45%);
--action: var(--brand-color);

/* sizes */
--gutter: 1.5rem;
--spacer: calc(var(--gutter) * 3);
}

Not a Total Replacement

Like having Back-End & Front-End

They have Different Strengths

Use them Together NSYNC

Define CSS Properties From Sass Variables

$gutter: 1rem;
html { --gutter: #{$gutter}; }
$brand-colors: (
'brand-blue': hsl(195, 52%, 31%),
'brand-orange': hsl(24, 100%, 62%),
'brand-pink': hsl(330, 100%, 45%),
);
html {
@for $name, $value in $brand-colors {
--#{$name}: #{$value};
}
}

More than Global Tokens

Custom Properties

defined by systems, components, etc

Values That Change

Different States

hover, focus, active, etc

Different Variations

info, warning, error, etc

Different Context

light/dark mode, viewports, etc

The 🌊 Cascade Resolves Conflicts

  1. 🗺 Origin &importance
  2. 🎯 Selector Specificity
  3. ⏭ Source Order

Layered Origins

  1. 🎨 Author Styles
  2. 👥 User Preferences
  3. 🖥 User Agent Defaults
  1. ❗🖥 User Agent Important
  2. ❗👥 User Important
  3. ❗🎨 Author Important
  4. 🎨 Author Styles
  5. 👥 User Preferences
  6. 🖥 User Agent Defaults
  1. 🎠 Transitions
  2. ❗🖥 User Agent Important
  3. ❗👥 User Important
  4. ❗🎨 Author Important
  5. 🏇🏽 Animations
  6. 🎨 Author Styles
  7. 👥 User Preferences
  8. 🖥 User Agent Defaults
  1. Inline styles
  2. Unique IDs
  3. Reusable classes & attributes
  4. Element types
  5. Universal *

We need Custom Cascades

With Custom Properties

Capture Cascading Values

Apply them Somewhere Else

For contextual styling Proximity Matters

The 🌊 Cascade Ignores Proximity

🧬 Inheritance Is All Proximity

Custom Properties Inherit By Default

Reset Inheritance With Explicit Selectors

Define Anywhere

Define Locally

button {
--btn-color: green;
}

Define Universally

Functionally “turns off” inheritance

* {
--border-width: 0;
}

Complex Selectors

.typeset > * {
--grid-area: content;
}

Define Nowhere

.typeset > * {
grid-area: var(--grid-area);
}

var( --name , fallback)

Define Nowhere

.typeset > * {
grid-area: var(--grid-area, content);
}

Fallback for Undefined Properties

Font Stacks

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

Undefined properties Allow Inherited Values

Unlike normal properties We Can Apply Selectively

Great for Contextual Variations

Global keywords Resolve on Custom Properties

They are not passed along as a value

Global keywords Inherit, Initial, Unset, Revert

Un-define Using initial Keyword

Universal Un-Define

* {
--grid-area: initial;
}

Layering Modifiers

  1. State
  2. Variation
  3. Object
  4. Context
  5. Global Defaults

Layering Modifiers

  1. State
  2. Variation
  3. Context
  4. Object
  5. Global Defaults

Font Stacks

Consolas, Menlo, 'Courier New', monospace

Intent Stacks

state, variation, object, context, default

var( --name , fallback)

Only One Fallback

Allows List Values

var(--my-font, Baskerville, Georgia, serif)

Nested Fallbacks

var(--my-color, var(--other-color, pink))

[data-theme] {
background-color: var(--theme-bg, var(--global-bg));
color: var(--theme-color, var(--global-color));
}
[data-theme='light'] {
--theme-bg: var(--neutral-light);
--theme-color: var(--neutral-dark);
--theme-link: var(--primary-dark);
}

[data-theme='dark'] {
--theme-bg: var(--neutral-dark);
--theme-color: var(--neutral-light);
--theme-link: var(--primary-light);
}
html {
@media (prefers-color-scheme: dark) {
--os-mode: -1;
}

@media (prefers-color-scheme: light) {
--os-mode: 1;
}
}
[data-colors='light'] {
--html-mode: 1;
}

[data-colors='dark'] {
--html-mode: -1;
}
[data-colors] {
--mode: var(
--user-mode, var(
--html-mode, var(
--os-mode, 1
)
)
);
}
  1. Managing Context
  2. Managing Intent
  3. Describing Objects

Headshot of Nicole Sullivan

@stubbornella Nicole Sullivan

Revisiting Object Oriented CSS

Object Structure Minimal & Reusable

Object Skin Multiple Theme Options

Extending Selectors

The Sass @extends feature

<div class="media">
<img class="fixedMedia" src="myImg.png" />
<div class="text">...</div>
</div>

Extend Objects By Applying Multiple Classes

<div class="media media_reverse">
<img class="fixedMedia" src="myImg.png" />
<div class="text">...</div>
</div>
<div class="media media_rounded">
<img class="fixedMedia" src="myImg.png" />
<div class="text">...</div>
</div>

See the Pen Media Object by @mirisuzanne on CodePen.

Custom Properties Are Not Just Variables

Allow us to Define Our Own Cascades

Attribute Selectors Provide An Interface

  • [attr]Presence (even if empty)
  • [attr="..."]Exact match
  • [attr*="..."]Any match
  • [attr~="..."]Space-delimited (like classes)
  • [attr|="..."]Hyphen-delimited
  • [attr^="..."]Starts with…
  • [attr$="..."]Ends with…
  • [attr="..." i|s]Case sensativity