That’s not how I wrote CSS 3 years ago

A presentation at CSS Day in June 2023 in Amsterdam, Netherlands by Manuel Matuzovic

Slide 1

Slide 1

That’s not how I wrote CSS 3 years ago Manuel Matuzović, CSS Day 2023

Slide 2

Slide 2

Hi, I’m Manuel! 👊 matuzo.at manuel@matuzo.at front-end.social/@matuzo htmhell.dev

Slide 3

Slide 3

Slide 4

Slide 4

1 2 3 4 5 div { position: absolute; inset: 0; } 6 7 8 9 10 11 12 13 14 15 inset shorthand property

Slide 5

Slide 5

1 2 input:where([type=”text”], [type=”email”]) { 3 4 } 5 6 7 a:is(:link, :visited) { 8 9 10 } 11 12 13 14 15 :where() and :is() pseudo-classes

Slide 6

Slide 6

1 2 3 4 5 6 7 8 9 10 11 12 @layer base { } @layer components { } @layer utility { } 13 14 15 cascade layers

Slide 7

Slide 7

1 body { 2 background-color: #123456; 3 background-color: rgb(18 52 86); 4 background-color: hsl(210deg 65.38% 20.39%); 5 background-color: hwb(210deg 7.06% 66.27%); 6 background-color: lch(21 24.7 264.72); 7 background-color: lab(21 -2.27 -24.59); 8 background-color: oklch(0.32 0.07 251.18); 9 background-color: oklab(0.32 -0.02 -0.07); 10 } 11 12 13 14 15 ff di erent colour notions, from HEX to oklab()

Slide 8

Slide 8

???

Slide 9

Slide 9

Slide 10

Slide 10

#100DaysOfMoreOrLess ModernCSS

Slide 11

Slide 11

Slide 12

Slide 12

Slide 13

Slide 13

Slide 14

Slide 14

Slide 15

Slide 15

Slide 16

Slide 16

Slide 17

Slide 17

E M BOB

Slide 18

Slide 18

HUG O

Slide 19

Slide 19

DRE AM CAS T❤

Slide 20

Slide 20

Slide 21

Slide 21

HE D AD A R SH K OT M AN T E S H I T H C R A N A ME NAT URA L BO KIL R N LER

Slide 22

Slide 22

[—>MTM<—] Mange Ta Merde

Slide 23

Slide 23

Slide 24

Slide 24

Slide 25

Slide 25

1 2

<body bgcolor=”#000000” text=”#ffffff” link=”#000000” alink=”000000” vlink=”#000000”> 3 <center> 4 <h1> 5 <font color=”#ff0000”>M</font> 6 <font color=”#ff0000”>A</font> 7 <font color=”#ff0000”>N</font> 8 <font color=”#ff0000”>G</font> 9 <font color=“#ff0000”>E</font> 10 <font color=”#ff0000”>T</font> 11 <font color=”#ff0000”>A</font> 12 </h1> 13 </center> 14 </body> 15 tt presentational a ributes and elements

Slide 26

Slide 26

1

<center> 2 <br /><br /> 3 <table width=”500” border=”2”> 4 5 6 <tbody> <tr> <td align=”center”> 7 <marquee> 8 KLICKE HIER UM… 9 10 11 12 13 14 </marquee> </td> </tr> </tbody> </table> </center> 15 center element, table layouts, and marquee 🔥

Slide 27

Slide 27

1 #header #left .blue { 2 3 4 5 6 color: red; } ul li li ol li { font-weight: bold; 7 8 } 9 10 li { 11 12 13 font-weight: normal !important; } 14 15 complex selectors and properties with high specificity

Slide 28

Slide 28

Slide 29

Slide 29

Slide 30

Slide 30

1 #header #left .blue { 2 3 color: red; ul li li ol li { font-weight: bold; color: green; } 20 21 body li { font-weight: normal !important; 23 li { 10 11 #header #left .blue { 22 } 8 9 17 19 6 7 @media (max-width: 1024px) { 18 } 4 5 16 font-weight: normal !important; } 24 } 25 26 12 27 13 28 14 29 15 30 complex selectors and properties with high specificity } repetition of complex selectors and high specificity

Slide 31

Slide 31

1 .col-start__logo—highlight { 2 3 color: red; 16 17 .sub-list_sub-item { 20 6 font-weight: bold; 21 } .sub-list_sub-item { 22 } font-weight: normal; 23 8 li { 10 11 color: green; 19 5 9 .col-start__logo—highlight { 18 } 4 7 @media (max-width: 1024px) { font-weight: normal; } 24 } 25 26 12 27 13 28 14 29 15 30 BEM syntax and low specificity selectors } repetition of low specificity selectors

Slide 32

Slide 32

1 .col-start { 2 $color: red; 3 4 &__logo { 5 &—highlight { 6 color: $color 7 } 8 } 9 10 ul { 11 @include reset-list; 12 13 } } 14 15 Sass syntax

Slide 33

Slide 33

Slide 34

Slide 34

Slide 35

Slide 35

Slide 36

Slide 36

Slide 37

Slide 37

Slide 38

Slide 38

Slide 39

Slide 39

Custom Properties

Slide 40

Slide 40

1 :root { 2 —color-a: hsl(210 65% 20%); 3 —color-b: hsl(166 65% 20%); 4 } 5 6 body { 7 color: var(—color-a); 8 border-color: var(—color-b); 9 } 10 11 12 13 14 15 simple usage of custom properties

Slide 41

Slide 41

1 :root { 2 —color-a-h: 210; 3 —color-a-s: 65%; 4 —color-a-l: 20%; 5 6 —color-a: hsl(var(—color-a-h) 7 var(—color-a-s) 8 var(—color-a-l)); 9 10 —color-b: hsl(166 var(—color-a-s) var(—color-a-l)); } 11 12 body { 13 color: var(—color-a); 14 border-color: var(—color-b); 15 } reusing colour parameters

Slide 42

Slide 42

😻 1 :root { 2 —color-a: #123456; 3 —color-b: hsl(from var(—color-a) 166 s l); 4 } 5 6 body { 7 color: var(—color-a); 8 border-color: var(—color-b); 9 } 10 11 12 13 14 15 relative colour syntax

Slide 43

Slide 43

Slide 44

Slide 44

Slide 45

Slide 45

1 ul { 2 display: flex; 3 flex-direction: column; 4 } 5 6 @media (min-width: 768px) { 7 ul { 8 flex-direction: row; 9 10 } } 11 12 13 14 15 duplicate declaration of the flex-direction property

Slide 46

Slide 46

1 ul { 2 —flex-direction: column; 3 4 display: flex; 5 flex-direction: var(—flex-direction); 6 } 7 8 @media (min-width: 768px) { 9 ul { 10 —flex-direction: row; 11 12 } } 13 14 15 single declaration of the flex-direction property

Slide 47

Slide 47

1 ul { 2 display: flex; 3 flex-direction: var(—flex-direction, column); 4 } 5 6 @media (min-width: 768px) { 7 ul { 8 —flex-direction: row; 9 10 } } 11 12 13 14 15 single declaration of the flex-direction property.

Slide 48

Slide 48

1 2 3 4 <wm-card> <h3 slot=”heading”> Parkpickerl im grünen Prater </h3> 5 6 7

<div slot=”content”> <p> 8 Seit 4. Juli gelten im Prater die 9 flächendeckende Kurzparkzone und 10 das Parkpickerl für 11 Bezirks-Bewohner*innen. 12 </p> 13 </div> 14 15 <img src=”/images/parkpickerl.jpg” 16 slot=”media” alt=”” 17 width=”350” height=”197”> 18 </wm-card> markup of a card component

Slide 49

Slide 49

Slide 50

Slide 50

1 wm-card { 2 —_color: darkorchid; 3 4 —card-background: hsl(from var(—_color) h s 99%); 5 —card-border: 1px solid var(—_color); 6 —card-shadow: none; 7 —card-spacing-large: 1rem; 8 } 9 10 11 12 13 14 15 tweaking “public” properties of the card component

Slide 51

Slide 51

Slide 52

Slide 52

1 2 3 <wm-card style=”—card-shadow: none”> … </wm-card> 4 5 6 7 8 9 10 11 12 13 14 15 tt card web component variation and style a ribute

Slide 53

Slide 53

tt tt h ps://almanac.h parchive.org/en/2022/css

Slide 54

Slide 54

1 <wm-card style=” —_color: darkorchid; 2 —card-bg: hsl(from var(—_color) h s 99%); 3 —card-border: 1px solid var(—_color); 4 —-card-shadow: none; 5 6 7 —card-spacing-large: 1rem;”> </wm-card> 8 9 10 11 12 13 14 15 tt multiple custom properties defined via the style a ribute

Slide 55

Slide 55

1 <wm-card class=”cssday” 16 2 … 17 —_color: darkorchid; 3 </wm-card> 18 —card-bg: hsl(from var(—_color) h s 99%); 4 19 —card-border: 1px solid var(—_color); 5 20 —card-shadow: none; 6 21 —card-spacing-large: 1rem; 7 22 8 23 9 24 10 25 11 26 12 27 13 28 14 29 15 30 .cssday { }

Slide 56

Slide 56

1 <wm-card style=”—card-style: cssday”> 2 3 … </wm-card> 4 5

<style> 6 @container style(—card-style: cssday) { .card { 7 8 —_color: darkorchid; 9 —card-background: hsl(from var(—_color) h s 95%); 10 —card-border: 4px solid var(—_color); 11 —card-shadow: none; 12 —card-spacing-large: 1rem; } 13 14 } 15 </style>

using a container style query to apply multiple properties at once

Slide 57

Slide 57

🐢 1 2 3 4

<div class=”blockquote”> <blockquote> Underline your fucking links you sociopaths. </blockquote> 5 6 7 <p><em>Heydon Pickering</em></p> </div> 8 9 10 11 12 13 14 15 simple blockquote component

Slide 58

Slide 58

Slide 59

Slide 59

1 2 3 4

<div class=”blockquote” style=”—quote-type: highlight”> <blockquote> Underline your fucking links you sociopaths. </blockquote> 5 6 7 <p><em>Heydon Pickering</em></p> </div> 8 9 10 11 12 13 14 15 variation of the blockquote component

Slide 60

Slide 60

1 @container style(—quote-type: highlight) { 2 blockquote { 3 —font-size: 4rem; 4 } 5 6 blockquote::after { 7 display: none; 8 } 9 10 11 … } 12 13 14 15 style query for the blockquote component

Slide 61

Slide 61

Slide 62

Slide 62

Slide 63

Slide 63

1

<article style=”—quote-type: highlight”> 2 … 3 <div class=”blockquote”> 4 <blockquote> 5 Underline your fucking links you sociopaths. 6 </blockquote> 7 8 9 10 11 <p><em>Heydon Pickering</em></p> </div> … </article> 12 13 14 15 children inheriting style config from parent article

Slide 64

Slide 64

Slide 65

Slide 65

Slide 66

Slide 66

1 :root { 2 3 —theme: light; } 4 5 .site-header { 6 7 —nav-style: main; } 8 9 .intro { 10 11 —paragraph-style: initial-letter; } 12 13 .selected-posts { 14 15 —card-style: large; } applying global, per page, and per section styles in CSS

Slide 67

Slide 67

Slide 68

Slide 68

Slide 69

Slide 69

1 .card { 16 2 —_card-columns: 6rem 1fr; 17 3 —_card-gap: 0 1.2rem; 18 5 display: grid; 20 6 gap: var(—_card-gap); 21 7 grid-template-columns: 22 8 var(—_card-columns); } .content { —_card-content: block; } } 25 .card .content { 12 —_card-content: none; 26 27 28 13 14 15 —_card-columns: 10rem 1fr; 23 24 } 10 11 .card { 19 4 9 @container (min-width: 64em) { display: var(—_card-content); } card default styles 29 30 card on viewports larger than 64em

Slide 70

Slide 70

Default 64em and more

Slide 71

Slide 71

1 .card { 16 2 —_card-columns: 6rem 1fr; 17 3 —_card-gap: 0 1.2rem; 18 4 .content { 20 6 gap: var(—_card-gap); 21 7 grid-template-columns: 22 9 } } 25 .card .content { 12 —_card-content: none; 26 @container (min-width: 64em) { .card { 27 —card-style: large; 28 13 14 15 23 —_card-content: block; 24 } 10 11 —_card-columns: 10rem 1fr; } display: grid; var(—_card-columns); .card { 19 5 8 @container style(—card-style: large) { display: var(—_card-content); } card default styles } 29 30 } style query + card on viewports larger than 64em

Slide 72

Slide 72

1 .card-large { 2 3 —card-style: large; } 4 5 6 7 8 9 10 11 12 13 14 15 large card styling

Slide 73

Slide 73

1 const card = document.querySelector(‘.card’) 2 3 // Get custom property value 4 card.style.getPropertyValue(‘—card-style’) 5 6 // Set custom property value 7 card.style.setProperty(‘—card-style’, ‘large’) 8 9 10 11 12 13 14 15 tt tt ge ing and se ing custom properties in JavaScript

Slide 74

Slide 74

Cascade Layers

Slide 75

Slide 75

“Layers help us reclaim declarative control of the intent behind our CSS without removing helpful information about the specificity of selectors. We’re managing the cascade instead of removing it.” Miriam Suzanne

Slide 76

Slide 76

“Selectors are there for a reason, and we should take advantage of their full potential. Instead, we’ve been restricting what selectors are allowed and enforcing more and more limited conventions in an a empt to somehow avoid the cascade .… tt Miriam Suzanne

Slide 77

Slide 77

…but the cascade is unavoidable; it’s the core of the language. There will always be selector conflicts, and there will always be an algorithm to resolve those conflicts. All we’ve been doing is denying ourselves access to one of the coolest features on the web platform.” Miriam Suzanne

Slide 78

Slide 78

1 .contact [type=”submit”]:focus-visible { 2 3 } 4 5 6 .contact–submit__focus { 7 8 9 10 11 12 13 14 15 }

Slide 79

Slide 79

1 @layer base { 2 3 p { margin-block-start: 0; } } 4 5 @layer components { 6 .card__content { 7 margin-block-start: 1rem; 8 9 } } 10 11 @layer utility { .u-mbs0 { 12 margin-block-start: 0; 13 } 14 15 } cascade layers

Slide 80

Slide 80

1 @layer base { 2 html.js.js.js input[type=”text”]#yolo#yolo { 3 border: 2px solid blue; 4 5 } } 6 7 @layer components { input { 8 border-color: green; 9 } 10 11 } 12 13 /* Result: border-color: green; */ 14 15 a layer defined later in the document overrides a layer defined earlier

Slide 81

Slide 81

1 @layer components { 2 .card { 3 border: 20px solid var(—border-color, currentColor); 4 } 5 6 .card:has(img[loading=”lazy”]) { 7 —border-color: red; 8 } 9 10 .card—large:has(img) { 11 —border-color: blue; 12 13 } } 14 15 /* Result: border-color: red; */ the specificity of the selector in line 5 is higher than in line 9

Slide 82

Slide 82

1 @layer components { 2 .card { 3 border: 20px solid var(—border-color, currentColor); 4 } 5 6 .card:has(img[loading=”lazy”]) { 7 —border-color: red; 8 } 9 10 .card—large:has(img[loading=”lazy”]) { 11 —border-color: blue; 12 13 } } 14 15 /* Result: border-color: blue; */ the specificity of the selector in line 5 is higher than in line 9

Slide 83

Slide 83

1 @layer components { 2 .card { 3 border: 20px solid var(—border-color, currentColor); 4 } 5 6 .card:has(img[loading=”lazy”]) { 7 —border-color: red; 8 } 9 10 .card—large:has(img) { 11 —border-color: blue !important; 12 13 } } 14 15 /* Result: border-color: blue; */ the specificity of the selector in line 5 is higher than in line 9

Slide 84

Slide 84

1 @layer components { 2 .card { 3 border: 20px solid var(—border-color, currentColor); 4 } 5 6 .card:where(:has(img[loading=”lazy”])) { 7 —border-color: red; 8 } 9 10 .card—large:has(img) { 11 —border-color: blue; 12 13 } } 14 15 /* Result: border-color: blue; */ the specificity of the selector in line 5 is higher than in line 9

Slide 85

Slide 85

1 @layer components { 2 @layer default { 3 .card { 4 border: 20px solid var(—border-color, currentColor); 5 } 6 7 .card:has(img[loading=”lazy”]) { 8 —border-color: red; 9 } 10 } 11 12 .card—large:has(img) { 13 —border-color: blue; 14 15 } } base styles in a nested default layer, variations unlayered

Slide 86

Slide 86

1 @layer components { 2 @layer default { 3 .card img { 4 border: 20px solid var(—border-color, currentColor); 5 } 6 7 .card:has(img[loading=”lazy”]) { —border-color: red; } 8 } 9 10 @layer large { 11 .card—large:has(img) { 12 —border-color: blue; 13 } 14 15 } } base styles in a nested default layer, variations in dedicated layers

Slide 87

Slide 87

•I don’t need Sass anymore •I went from BEM (Block Element Modifier) to BAPI (Block & API) •I spend more time in CSS because I write less classes •I embrace the cascade •Custom Properties – Declarations - Config

Slide 88

Slide 88

Slide 89

Slide 89

JavaScript

Slide 90

Slide 90

Slide 91

Slide 91

1 let vh = window.innerHeight * 0.01 2 document.documentElement.style.setProperty(‘—vh’, ${vh}px) 3 4 5 6 7

<html style=”—vh:11.7px;” lang=”en”> <head> <style> body { 8 9 10 11 12 height: calc(var(—vh, 1vh) * 100); } </style> </head> </html> 13 14 15 JS hack for dynamic viewport height in CSS

Slide 92

Slide 92

1 body { 2 3 height: 100dvh; } 4 5 6 7 8 9 10 11 12 13 14 15 dynamic viewport height in CSS

Slide 93

Slide 93

Slide 94

Slide 94

Video

Slide 95

Slide 95

1 html { 2 3 scrollbar-gutter: stable; } 4 5 6 7 8 9 10 11 12 13 14 15 tt stable scrollbar gu er in CSS

Slide 96

Slide 96

Slide 97

Slide 97

Slide 98

Slide 98

Slide 99

Slide 99

1 ol { 2 display: grid; 3 gap: 1rem; 4 grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); 5 grid-template-rows: masonry; 6 masonry-auto-flow: next; 7 } 8 9 10 11 12 13 14 15 masonry layout in native CSS without JavaScript

Slide 100

Slide 100

Slide 101

Slide 101

Slide 102

Slide 102

1 html:has(dialog[open]) { 2 3 overflow: clip; } 4 5 6 7 8 9 10 11 12 13 14 15 prevent scrolling when there’s an open dialog on the page

Slide 103

Slide 103

Slide 104

Slide 104

Slide 105

Slide 105

Slide 106

Slide 106

1 li:hover { 2 3 scale: 1.5 1.3; } 4 5 li:has(+ li:hover), li:hover + li { 6 7 scale: 1.4 1.2; } 8 9 li:has(+ li + li:hover), li:hover + li + li { 10 11 scale: 1.3 1.1; } 12 13 li:has(+ li + li + li:hover), li:hover + li + li + li { 14 15 scale: 1.1 1; } previous element selector using :has()

Slide 107

Slide 107

Slide 108

Slide 108

Slide 109

Slide 109

u k Th an yo ❤