🏠

Dynamic CSS Layouts & Beyond

Miriam Suzanne | @mirisuzanne | @oddbird

OddBird

Dynamic CSS Layouts & Beyond

JSConf, US — August 21, 2018

OddBird Faces

OddBird

Full-Stack Agency

¯\_(ツ)_/¯

Let’s Talk About CSS

1993: HTML

Markup Language

1997: <font> && <table>

HTML 3.2

(╯'□')╯︵ ┻━┻

“TABLES ARE FOR DATA

1996 2000: Cascading Style Sheets

Principle of Least Power

CSS is Awesome (This is a Feature)

2000: A Dao of Web Design

John Allsopp

2007-2010: Major Grid Frameworks

Blueprint, OOCSS, 960gs

OddBird Faces

OddBird

est. 2008

  1. Systems > Frameworks
  2. Fluid Grids
  3. Static (px) | Elastic (em) Containers

👍

“Responsive” before Responsive™

👎

Ugly Math

target / context * 100%

.grid-span {
  width: 23.7288136%;
  margin-right: 01.6949153%;
  padding-left: 08.4745763%;
}

2009: Compass + Sass

Turing-complete CSS!

.grid-span {
  width: percentage(((3*4em) + (2*1em)) / ((12*4em) + (11*1em))); // 23.7288136%
  margin-right: percentage(1em / ((12*4em) + (11*1em))); // 01.6949153%
  padding-left: percentage(((1*4em) + (1*1em)) / ((12*4em) + (11*1em))); // 08.4745763%
}
.grid-span {
  width: span(3);
  margin-right: gutter();
  padding-left: span(1 wide);
}

Make Code Meaningful

(To humans && machines)

hsl(330, 100%, 45%) => $brand

We’re Naming Things!

“Code is Communication

—Sarah Drasner *

* (once)

2009: @media queries

Safari 4

2011: calc()

Firefox 4

Mixed-Unit Calculations

calc( 16px + 20% )

2011: Responsive Web Design

Ethan Marcotte

**!**👨

don’t be fooled…

Declarative Syntax != Static Results

Go with the flow!

Change Me!
Next In Flow
Last In Flow
  1. Fluid Grids
  2. Flexible Images
  3. Media Queries

2014: --css-variables

Firefox 31 (unless you count currentColor)

.example {
  --color: red;
  background: var(--red);
}

-<empty>-browser-prefix

--aka: 'custom properties';

var( --property-name , fallback)

Similar to Sass

(but not the same!)

$sass-variables: rad;

Variables Hold Data

$brand: hsl(330, 100%, 45%);

Variables are $reusable

(Don’t Repeat Yourself)

Sass Variables Scope

.example { $columns: 2; }
.nested-class { /* $columns == undefined */ }

@media (min-width: 30em) {
  .example { $columns: 6; }
  .nested-class { /* $columns == undefined */ }
}

CSS Variables Inherit

.example { --columns: 2; }
.nested-class { /* var(--columns) == 2 */ }

@media (min-width: 30em) {
  .example { --columns: 6; }
  .nested-class { /* var(--columns) == 6 */ }
}

Inherit Everywhere:

:root {
  --brand-color: hsl(330, 100%, 45%);
}

Don’t Inherit:

* {
  --brand-color: initial;
}

Safe Inline Styles

<button style="--color: blue;">

Use the Variable…

button {
  background: var(--color, red);
}

…or Ignore the Variable

button.green {
  background: green;
}

Avoid Nesting

button {
  background: blue
}

.this button {
  background: red;
}

…For Lower Specificity

button {
  background: var(--btn-color, blue);
}

.this {
  --btn-color: red;
}

Defaults & Missing Longhand

.example {
  --shadow-y: -1px;
  box-shadow: var(--shadow-x, 0)
              var(--shadow-y, 1px)
              var(--shadow-blur, 0)
              var(--shadow-color, currentColor);
}

Auto-Prefixing “Mixins”

* {
  --clip-path: initial;
  -webkit-clip-path: var(--clip-path);
  clip-path: var(--clip-path);
}

Combine with calc()

.example {
  margin: calc(1em + var(--extra-margin));
}

Global Settings…

:root {
  --susy-columns: 1;
  --susy-gutters: 0.25;
  --susy-spread: -1;
  --susy-container-spread: -1;
/*   --susy-static-grid: 1; */
/*   --susy-debug-color: green; */
}

A Variable for Every Function

* {
  /* gutter output math */
  --su-inside-gutters: calc(
      var(--gutter-width) * var(--gutters-inside)
    );

  --su-gutters-left: calc(
      var(--gutter-width) * var(--gutters-left)
    );
}

Media Queries…

@media (min-width: 30em) {
  /* settings */
  :root { --susy-columns: 5; }

  /* layout */
  [data-susy~='2']{ --span: 1; }
  [data-susy~='6'] { --span: 3; }
  [data-susy~='6'] * { --susy-columns: 3 }
  [data-susy~='3'] { --span: 3; }
  [data-susy~='4'] { --span: 2; }
  [data-susy~='4'] * { --susy-columns: 2 }
}

Background Images…

main {
  background-image: var(--debug-image);
  background-size: var(--debug-image-size);
  margin: var(--static-gutters) auto;
  overflow: hidden;
}

😆

Please Don’t Use It

Manipulate hsl() Values

* {
  --h: 330;
  --s: 100%;
  --l: 34%;
  background: hsl(var(--h), var(--s), var(--l));
}

Use Radial Values to Theme

* {
  --darken: calc(var(--l) - 20%);
  --complement: calc(var(--h) - 180);
  background: hsl(var(--complement), var(--s), var(--darken));
}

Use “Clamped” Values to Toggle

* {
  --threshold: 55; /* toggle 'contrast' between white & black */
  --contrast: calc((var(--l) - var(--threshold)) * -100%);
  color: hsl(var(--h), var(--s), var(--contrast));
}

Complement

JS getPropertyValue() & setProperty()

let currentColor = footer.style.getPropertyValue('--color');
footer.style.setProperty('--color', newColor);

Issues:

  1. Unknown value types (transition known properties, not variables)
  2. Don’t work inside url()
  3. var(--size)em => calc(var(--size) * 1em)

Houdini Properties & Values API *

* Experimental (behind Chrome flag)

CSS.registerProperty({
  name: "--brand-color",
  syntax: "<color>",
  initialValue: "pink",
  inherits: true,
});

Learn from Lea Verou

video | slides

2017: CSS Grid

Firefox 52 & Chrome 57 & Safari 10

Nothing Like It

At All

The Spec is Complex

Getting Started Is Not

Defined On Containers

.container {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-gap: 10px;
}

Optional Element Control

auto returns to the flow…

% => relative to parent width

vw => relative to the viewport

fr => relative to remaining space

1fr == minmax(auto, 1fr)

use minmax(0, 1fr) to allow shrinking

Single Source of Truth

body {
  grid-template-areas:
      'header               header'           auto
      'nav                  main'             1fr
      'footer               footer'           auto
    / minmax(14em, auto)    minmax(0, 1fr);
}
h1 { grid-area: header; }
nav { grid-area: nav; }
main { grid-area: main; }
footer { grid-area: footer; }

2018: Intrinsic Web Design

Jen Simmons

Fluid & Fixed

Stages of Squishiness

  1. fixed
  2. fr units (fluid)
  3. minmax() (fluid until fixed)
  4. auto (flow)

Truly Two-Dimensional Layouts

columns & rows!

Nested Contexts

flexbox, grid, float, etc…

Expand & Contract Content

justify, wrap, flex, etc…

Media Queries, As Needed

repeat( auto-fit , minmax( 20em , 1fr ))

Data-Driven Layouts

<div style=" --start: 30; --duration: 60;">

Bar Charts

<dl class="chart" style="--scale: 100">
  <dt class="date">2000</dt>
  <dd class="bar" style="--value: 45">45%</dd>

  <dt class="date">2001</dt>
  <dd class="bar" style="--value: 100">100%</dd>

  <!-- etc… -->
</dl>
```html
.bar {
  --start: calc(var(--scale) + 1 - var(--value));
  grid-row-start: var(--start);
}
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009

Have Fun!

gridbyexample.com

examples, templates, and fallbacks by Rachel Andrew

CSS is Awesome

Inspired by Stacy Kvernmo [permalink / source]

Stay in touch…