Creative CSS Layout & the Flexible Web

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

css-irl.info

CSS Layout in 2022 and beyond

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

“ Intrinsic web design Jen Simmons ”

Flex or Grid?

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

centred

Flexbox

Grid 1fr auto 1fr

Flexbox

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

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

codepen.io/michellebarker/pen/qBxNWZP

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

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

codepen.io/michellebarker/pen/qBxNWZP

Aspect-ratio

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

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

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

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

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

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

⚠ NOT Progressive Enhancement

codepen.io/michellebarker/pen/bGLpzjd

codepen.io/michellebarker/pen/bGLpzjd

codepen.io/michellebarker/pen/YzeqRrP

3 2 codepen.io/michellebarker/pen/YzeqRrP

Flex or Grid?

.item { flex: 1 1 19rem; }

.item { flex: 0 1 19rem; }

.flex-grid { gap: 1.5rem; }

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

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

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

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

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

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

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

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

auto-fit auto-fill

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

Container queries

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

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

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

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

container: inline-size / component;

gap: max(1rem, 2vw);

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

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

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

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

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

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

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

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

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

Size Viewport width

utopia.fyi

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’

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

Subgrid

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

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

No subgrid? No problem!

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

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

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

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

:has() (the parent selector)

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

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

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

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

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

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

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

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

codepen.io/michellebarker/pen/xxYrWzZ

Diversity is strength

🥰 Thank you @MicheBarks / @CSSInRealLife