🏠

Don’t Use My Grid System The Past & Future of Web Layout

Miriam Suzanne | @mirisuzanne | @oddbird

OddBird

Don’t Use My Grid System The Past & Future of Web Layout

Covalence Conference — January 16, 2019

OddBird Faces

OddBird

Full-Stack Consulting Agency

CSS Layout

1993: HTML

Markup Language

1997: <table>

HTML 3.2

(╯'□')╯︵ ┻━┻

“TABLES ARE FOR DATA

👎

Limited Styling

👎

Strict (non-linear) Markup

👎

Accessibility Nightmare

“Code is Communication

—Sarah Drasner *

* (once)

Table Layouts Destroy Meaning

for both humans and machines…

1996 2000: Cascading Style Sheets

Principle of Least Power

CSS is Awesome (This is a Feature)

don’t be fooled…

Declarative Syntax != Static Results

Dynamic Relationships

how is this going to change…?

…when the content changes?

…when the viewport changes?

…when the context changes?

! 👨

Go with the flow!

Change Me!
Next In Flow
Last In Flow

Classic Layouts…

Position?

Relative positions have no effect on flow

Absolute positions remove from flow

Absolute (or Fixed) For Overlays Only

off-canvas, drop-downs, tooltips, modals, etc…

Floats?

float:left // float:right

Great for elements that should… float…

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Perspiciatis laudantium ea tenetur quas incidunt. Voluptatibus veritatis, rerum vitae illum, recusandae quis. Recusandae quisquam sunt id, eius debitis quos animi hic.
Last! (floating)

Requires ClearFix (Hack)

apply to any container element…

// "Micro" Clearfix Mixin
@mixin clearfix {
  &::after {
    clear: both;
    content: ' ';
    display: table;
  }
}

// "Micro" Clearfix Class
.clearfix::after { /* same… */ }
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Perspiciatis laudantium ea tenetur quas incidunt. Voluptatibus veritatis, rerum vitae illum, recusandae quis. Recusandae quisquam sunt id, eius debitis quos animi hic.
Last! (floating)

display: flow-root

the new clearfix alternative, with very little support…

👍

Flexible Markup & Nesting!

👎

Explicit Widths

floats aren’t very smart about context…

¯\_(ツ)_/¯

not the worst hacks

Display: Table?

div
div (width 40%)
div
div
div

Works like a table, but maybe more semantic [permalink / source]

No Margins, Use border-padding

2007-2010: Major Grid Frameworks

Blueprint, OOCSS, 960gs, Susy, etc…

12 column grid, single axis

Span some of those columns!

Add a gutter on the right margin…

Remove the last margin in a row…

Classes Are The API

class="column col6of12 last"

960gs uses “split” gutters to avoid last

👍

Provide Consistent Patterns

and take care of all the hacks…

👍

Developers Can Ignore CSS

👎

Developers Will Ignore CSS

👎

One Size Fits No One

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

👍

“Responsive” before Responsive™

Fluid Grid Math Sux

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

target / context == multiplier

width: percentage(target / context)

Fluid Grid Math Sux

.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%
}

Sass (2006) & Susy (2009)

.grid-span {
  width: span(3);
  margin-right: gutter();
  padding-left: span(1 wide);
}

👍

Any Grid System, On Demand

👎

Usually Overkill

Remove Gutters

OOCSS uses fractions to keep math simple…

Fix the Box Model

(IE got it right the first time)

Content-Box: total = width/height + borders + padding

Border-Box: total = width/height

👍

Global Box-Sizing

* {
  box-sizing: border-box;
}

👎

Fragile Box-Sizing

never inherit layout properties!

html {
  box-sizing: border-box;
}

* {
  box-sizing: inherit;
}

Avoid Tightly Coupled Elements

components respond to unexpected changes

2011: calc()

Firefox 4

Mixed-Unit Calculations

calc( 16px + 20% )

2012: Flexbox

Chrome 21

one
two
three (out of order, with extra lorem ipsum content)
four
five
six

Global Flow

flex-direction: column; | flex-wrap: wrap;

Individual Sizing

grow, shrink, basis => flex: 1 2 auto;

👍

-Grow & -Shrink Define Relationships!

👎

Nesting Matters

👎

Poor Page-Level Performance

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)

Sass Variables Scope

Based on Source File Structure

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

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

CSS Variables Inherit

Based on DOM & Cascade

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

@media (min-width: 30em) {
  :root { --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;
}

Combine with calc()

* {
  --width: calc(var(--span) / var(--columns) * 100%);
  box-sizing: border-box;
  width: var(--width, initial);
}

.calc-gutters .item {
  --span: 1;
  float: left;
  padding: var(--gutters);
}

Media Queries

:root {
  --columns: 3;
  --gutters: 0.5em;

  @media (min-width: 50em) {
    --columns: 6;
    --gutters: 1em;
  }
}

CSSSusy!

: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)
    );
}

Viewport Units

vw, vh, vmin, vmax

Full Height…

height: 100vh

Sticky-Footer…

min-height: 100vh

Breaking Out of the Container

calc( 50% - 50vw )

2017: Jet Packs*!

*Kinda

2017: CSS Grid

Firefox 52 & Chrome 57 & Safari 10

Nothing Like It

At All

The Spec is Complex

Getting Started Is Not

Truly Two-Dimensional Layouts

columns & rows! mixed units!

.container {
  display: grid;
  grid-template-columns: 300px 1fr minmax(30em, 50%) 10vw; /* mixed units! */
  grid-template-rows: 300px 300px 300px; /* repeat(3, 300px) */
  grid-gap: 10px;
}
header
main

with some content...

Grid lines 1-indexed and -1 in reverse (see dev tools) [permalink / source]

Grid-Items: By Line

.one {
  grid-column: 1 / 4;
  grid-row: 2 / span 2;
}

.two {
  grid-column: 2 / -1;
  grid-row: 1 / -2;
}

Global Flow && Sizing

With auto escape-hatch to element flow…

body {
  display: grid;
  grid-gap: 0.5em;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: minmax(14em, auto) minmax(0, 1fr);
}

Named Areas

body {
  grid-template-areas: 'header header'
                       'nav main'
                       'footer footer';
}

h1 { grid-area: header; }
nav { grid-area: nav; }
main { grid-area: main; }
footer { grid-area: footer; }

Single Source of Truth

@media (max-width: 50em) {
  body {
    grid-template: 'header'
                   'nav'
                   'main'
                   'footer';
  }
}
header
main

with some content...

Resize window to see media-query in action… [permalink / source]

% => relative to parent width

vw => relative to the viewport

fr => relative to available space

1fr == minmax(auto, 1fr)

use minmax(0, 1fr) to allow shrinking

2018: Intrinsic Web Design

Jen Simmons

Fluid & Fixed

Stages of Squishiness

  1. fixed
  2. fluid (fr)
  3. fluid-until-fixed (minmax() | flex-basis)
  4. flow (auto)

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
index value
0 57
1 38
2 77
3 67
4 66
5 56
6 52
7 98
8 79
9 8
10 21
11 84
12 4
13 16
14 72
name x value y value size == z value
item-0 23 21 24
item-1 92 84 18
item-2 6 62 22
item-3 48 89 20
item-4 13 30 21
item-5 99 3 19
item-6 36 97 18
item-7 9 47 7
item-8 42 74 16
item-9 29 50 9
item-10 68 11 9
item-11 41 85 2
item-12 80 24 5
item-13 5 89 2
item-14 90 73 19
item-15 69 91 12
item-16 49 82 2
item-17 45 19 8
item-18 42 27 4
item-19 5 7 9

Levitated Toy Factory at Beyond Tellerand

Lea Verou: Variables

video | slides

Rachel Andrew: gridbyexample.com

examples, templates, and fallbacks

CSS is Awesome

Inspired by Stacy Kvernmo [permalink / source]

Stay in touch…