Creative CSS Layout & the Flexible Web

A presentation at CSS Day in June 2022 in Amsterdam, Netherlands by Michelle Barker

Slide 1

Slide 1

Creative CSS Layout & the Flexible Web

Slide 2

Slide 2

About me • Senior Front End Developer at Ada Mode • Writer for Smashing Magazine, Codrops and CSS Tricks • CSS tinkerer

Slide 3

Slide 3

css-irl.info

Slide 4

Slide 4

Slide 5

Slide 5

CSS Layout in 2022 and beyond

Slide 6

Slide 6

Multi-column Flexbox Custom properties Container queries aspect-ratio min() / max() / clamp() Grid :has() Logical properties Viewport units Subgrid Writing modes

Slide 7

Slide 7

“ Intrinsic web design Jen Simmons ”

Slide 8

Slide 8

Flex or Grid?

Slide 9

Slide 9

Flexbox One dimension Flexible layout Two dimensions Strict alignment Gap support Layout based on content Layout based on context Grid

Slide 10

Slide 10

Slide 11

Slide 11

Slide 12

Slide 12

Slide 13

Slide 13

centred

Slide 14

Slide 14

Flexbox

Slide 15

Slide 15

Grid 1fr auto 1fr

Slide 16

Slide 16

Flexbox

Slide 17

Slide 17

https://codepen.io/michellebarker/pen/mdXPYLo

Slide 18

Slide 18

https://codepen.io/michellebarker/pen/mdXPYLo

Slide 19

Slide 19

Slide 20

Slide 20

Slide 21

Slide 21

codepen.io/michellebarker/pen/qBxNWZP

Slide 22

Slide 22

grid-template-columns: 1fr repeat(10, minmax(0, 6rem)) 1fr; codepen.io/michellebarker/pen/qBxNWZP

Slide 23

Slide 23

grid-template-columns: 1fr repeat(10, minmax(0, 6rem)) 1fr; codepen.io/michellebarker/pen/qBxNWZP

Slide 24

Slide 24

codepen.io/michellebarker/pen/qBxNWZP

Slide 25

Slide 25

Aspect-ratio

Slide 26

Slide 26

Before ☹ .aspect-box { position: relative; } .aspect-box::before { display: block; content: ”; width: 100%; padding-bottom: calc(100% / (var(—-aspect-ratio, 3 / 2))); } .aspect-box > :first-child { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } After ☺ .aspect-box { aspect-ratio: 3 / 2; }

Slide 27

Slide 27

.item { aspect-ratio: 1; } codepen.io/michellebarker/pen/bGLpOZz

Slide 28

Slide 28

img { display: block; width: 100%; height: 100%; object-fit: cover; } codepen.io/michellebarker/pen/bGLpOZz

Slide 29

Slide 29

img { display: block; width: 100%; height: 100%; object-fit: contain; } codepen.io/michellebarker/pen/QWQqggO

Slide 30

Slide 30

No aspect ratio? No problem! codepen.io/michellebarker/pen/bGLpOZz

Slide 31

Slide 31

Slide 32

Slide 32

.item { max-height: 20rem; } @supports (aspect-ratio: 1) { .item { aspect-ratio: 1; max-height: none; } }

Slide 33

Slide 33

⚠ NOT Progressive Enhancement

Slide 34

Slide 34

codepen.io/michellebarker/pen/bGLpzjd

Slide 35

Slide 35

codepen.io/michellebarker/pen/bGLpzjd

Slide 36

Slide 36

codepen.io/michellebarker/pen/YzeqRrP

Slide 37

Slide 37

3 2 codepen.io/michellebarker/pen/YzeqRrP

Slide 38

Slide 38

Flex or Grid?

Slide 39

Slide 39

.item { flex: 1 1 19rem; }

Slide 40

Slide 40

.item { flex: 0 1 19rem; }

Slide 41

Slide 41

.flex-grid { gap: 1.5rem; }

Slide 42

Slide 42

Slide 43

Slide 43

.grid { grid-template-columns: repeat(6, minmax(0, 1fr)); } .item { grid-column: span 2; }

Slide 44

Slide 44

.item:last-child:nth-child(3n + 1) { grid-column: span 6; }

Slide 45

Slide 45

.item:last-child:nth-child(3n + 2) { grid-column: 4 / span 2; } .item:nth-last-child(2):nth-child(3n + 1) { grid-column: 2 / span 2; }

Slide 46

Slide 46

Slide 47

Slide 47

.grid { display: grid; gap: var(—pad-sm); grid-template-columns: repeat( auto-fit, minmax(min(19rem, 100%), 1fr) ); }

Slide 48

Slide 48

.grid { display: grid; gap: var(—pad-sm); grid-template-columns: repeat( auto-fit, minmax(19rem, 1fr) ); }

Slide 49

Slide 49

.grid { display: grid; gap: var(—pad-sm); grid-template-columns: repeat( auto-fit, minmax(min(19rem, 100%), 1fr) ); } Minimum size

Slide 50

Slide 50

.grid { display: grid; gap: var(—pad-sm); grid-template-columns: repeat( auto-fit, minmax(min(19rem, 100%), 1fr) ); } Maximum size

Slide 51

Slide 51

.grid { display: grid; gap: var(—pad-sm); grid-template-columns: repeat( auto-fill, minmax(min(19rem, 100%), 1fr) ); }

Slide 52

Slide 52

auto-fit auto-fill

Slide 53

Slide 53

.grid { display: grid; gap: var(—pad-sm); grid-template-columns: repeat( auto-fit, minmax(min(19rem, 100%), 1fr) ); }

Slide 54

Slide 54

Container queries

Slide 55

Slide 55

Slide 56

Slide 56

Slide 57

Slide 57

main, aside { container: inline-size / layout; } .grid { display: grid; gap: var(—pad); } @container layout (inline-size > 25em) { .grid { grid-template-columns: repeat(2, 1fr); } } @container layout (inline-size > 65em) { .grid { grid-template-columns: repeat(4, 1fr); } }

Slide 58

Slide 58

main, aside { container: inline-size / layout; } .grid { display: grid; gap: var(—pad); } @container layout (inline-size > 25em) { .grid { grid-template-columns: repeat(2, 1fr); } } @container layout (inline-size > 65em) { .grid { grid-template-columns: repeat(4, 1fr); } }

Slide 59

Slide 59

main, aside { container: inline-size / layout; } .grid { display: grid; gap: var(—pad); } @container layout (inline-size > 25em) { .grid { grid-template-columns: repeat(2, 1fr); } } @container layout (inline-size > 65em) { .grid { grid-template-columns: repeat(4, 1fr); } }

Slide 60

Slide 60

https://codepen.io/michellebarker/pen/OJQpVKE

Slide 61

Slide 61

Slide 62

Slide 62

Slide 63

Slide 63

Slide 64

Slide 64

Slide 65

Slide 65

container: inline-size / component;

Slide 66

Slide 66

Slide 67

Slide 67

Slide 68

Slide 68

gap: max(1rem, 2vw);

Slide 69

Slide 69

min, max and clamp min(1rem, 2vw)

Slide 70

Slide 70

min, max and clamp clamp(1rem, 2vw, 3rem)

Slide 71

Slide 71

:root { —pad: clamp(1rem, 2vw, 3rem); —pad-lg: calc(var(—pad) * 2); —pad-sm: calc(var(—pad) / 2); —pad-xs: calc(var(—pad) / 4); }

Slide 72

Slide 72

.wrapper * + * { margin-top: var(—pad); }

Slide 73

Slide 73

.wrapper * + * { margin-block-start: var(—pad); }

Slide 74

Slide 74

.wrapper :is(h1, h2, h3) + * { margin-block-start: var(—pad-sm); }

Slide 75

Slide 75

—pad: clamp(1rem, 2vw, 3rem);

Slide 76

Slide 76

—pad: clamp(1rem, 2vw, 3rem);

Slide 77

Slide 77

—pad: clamp(1rem, 2vw, 3rem);

Slide 78

Slide 78

Size Viewport width

Slide 79

Slide 79

utopia.fyi

Slide 80

Slide 80

Slide 81

Slide 81

Container-relative units cqw query container width cqh query container height cqi query container inline size cqb query container block size cqmin smallest of ‘cqi’ or ‘cqb’ cqmax largest of ‘cqi’ or ‘cqb’

Slide 82

Slide 82

.card h3 { font-size: clamp(1.2rem, 5cqi + 1rem, 3rem); }

Slide 83

Slide 83

Subgrid

Slide 84

Slide 84

Slide 85

Slide 85

.card { grid-row: span 3; display: grid; gap: 0; grid-template-rows: subgrid; }

Slide 86

Slide 86

.card { grid-row: span 3; display: grid; gap: 0; grid-template-rows: subgrid; }

Slide 87

Slide 87

No subgrid? No problem!

Slide 88

Slide 88

Slide 89

Slide 89

.card { /* Code for browsers without subgrid / } @supports (grid-template-columns: subgrid) { .card { grid-template-rows: subgrid; / Code for browsers that support subgrid */ } }

Slide 90

Slide 90

Slide 91

Slide 91

Slide 92

Slide 92

Slide 93

Slide 93

Slide 94

Slide 94

figure { display: grid; grid-template-columns: subgrid; grid-template-rows: subgrid; }

Slide 95

Slide 95

img { grid-row: 1 / span 3; }

Slide 96

Slide 96

figcaption { grid-column: 4 / span 2; grid-row: 2; }

Slide 97

Slide 97

:has() (the parent selector)

Slide 98

Slide 98

.grid blockquote { grid-column: 2 / span 4; grid-row: 2 / span 2; text-align: center; }

Slide 99

Slide 99

.grid:has(img) img { grid-row: 1 / span 2; grid-column: 1 / span 3; } .grid:has(img) blockquote { grid-row: 2 / span 2; grid-column: 3 / span 4; text-align: left; }

Slide 100

Slide 100

.grid { display: grid; grid-template: 1fr / repeat(var(—cols, 3), 1fr); grid-auto-rows: 1fr; }

Slide 101

Slide 101

.grid { display: grid; grid-template: 1fr / repeat(var(—cols, 3), 1fr); grid-auto-rows: 1fr; }

Slide 102

Slide 102

.grid { display: grid; grid-template: 1fr / repeat(var(—cols, 3), 1fr); grid-auto-rows: 1fr; }

Slide 103

Slide 103

.grid { display: grid; grid-template: 1fr / repeat(var(—cols, 3), 1fr); grid-auto-rows: 1fr; }

Slide 104

Slide 104

.grid:has(:last-child:nth-child(even)) { —cols: 2; }

Slide 105

Slide 105

.grid:has(:last-child:nth-child(5)) { —cols: 2; } .grid:has(:last-child:nth-child(5)) .item:first-child { grid-column: span 2; }

Slide 106

Slide 106

codepen.io/michellebarker/pen/xxYrWzZ

Slide 107

Slide 107

Diversity is strength

Slide 108

Slide 108

🥰 Thank you @MicheBarks / @CSSInRealLife