A presentation at Smashing Meets – Happy Holidays Edition in December 2020 in by Michelle Barker
Custom Properties The Secret Ingredients for CSS Magic 🎩🐇
:root { —primaryColor: deeppink; }
:root { —primaryColor: deeppink; } .box { background-color: var(—primaryColor); }
:root { —primaryColor: deeppink; } .box { background-color: var(—primaryColor, darkorchid); }
/* :root { —primaryColor: deeppink; } */ .box { background-color: var(—primaryColor, darkorchid); }
IE11 😢 .box { background-color: deeppink; background-color: var(—bg, darkorchid); }
IE11 😢 .box { /* background-color: deeppink; */ background-color: var(—bg, darkorchid); } The square is here, you just can’t see it
Nice lovely browser .box { background-color: deeppink; background-color: var(—bg, 300); } Sorry, it’s still invisible
Sass variable $bgColor: deeppink; !== —primaryColor: deeppink; Custom property
Repeating values Repeating values Repeating values Repeating values Repeating values Repeating values Repeating values
.box { —size: min(90vw, 40rem); } width: var(—size); height: var(—size);
.some-element { padding: 12rem 1rem 1rem; } .another-element { padding: 0 1rem 1rem; }
.some-element { padding: 12rem 1rem 1rem; } .another-element { padding: 0 1rem 1rem; } @media (min-width: 50em) { .some-element { padding: 12rem 3rem 3rem; } } .another-element { padding: 0 3rem 3rem; }
.some-element { padding: 12rem var(—pad) var(—pad); } .another-element { padding: 0 var(—pad) var(—pad); }
:root { —pad: 1rem; } @media (min-width: 50em) { :root { —pad: 3rem; } }
.element { —color: 150, 0, 190; } background: linear-gradient( rgba(var(—color), 0.2), rgba(var(—color), 1));
:root { —clip: polygon(80% 0, 100% 0, 100% 100%, 20% 100%); } .element { -webkit-clip-path: var(—clip); clip-path: var(—clip); }
Global vs local scoping
Dark mode
:root { —primary: deepPink; —headerBg: #1d1d26; —textColor: #0e0f0f; —textColorInverse: #fcfdff; —bg: #fcfdff; —bgTint: #dfeded; —bgGrey: #e6e8e8; —white: #fcfdff; }
@media (prefers-color-scheme: dark) { :root { —bg: #161618; —bgTint: #27272c; —bgGrey: #27272c; —textColor: #dbd7db; —textColorInverse: #0e0f0f; } }
Demo time!
Polyfills: ❌ postcss-custom-properties ✅ ie11CustomProperties
Vertical rhythm
—vr: 2rem
var(—vr)
calc(2 * var(—vr))
:root { —vr: 1rem; } @media (min-width: 50em) { :root { —vr: 2rem; } }
—vr: 1rem; —vr: 2rem;
:root { —vr: 1rem; —2vr: calc(2 * var(—vr)); } @media (min-width: 50em) { :root { —vr: 2rem; } }
Color
Hue Saturation Lightness hsl(3deg, 89%, 61%)
Hue Saturation Lightness hsl(var(—hue), 89%, 61%)
.color-pair { —hue: 3deg; —hue2: calc(var(—hue) + 180deg); }
—hue: 3deg; —hue2: calc(var(—hue) + 180deg);
.color-pair—red { —hue: 3deg; } hsl(var(—hue), 89%, 61%); hsl(var(—hue2), 89%, 61%); codepen.io/michellebarker/pen/vqgaLL
.color-pair—purple { —hue: 276deg; } hsl(var(—hue), 89%, 61%); hsl(var(—hue2), 89%, 61%); codepen.io/michellebarker/pen/vqgaLL
.color-pair—yellow { —hue: 65deg; } hsl(var(—hue), 89%, 61%); hsl(var(—hue2), 89%, 61%); codepen.io/michellebarker/pen/vqgaLL
.element { —segment: 30deg; }
.element { —segment: 30deg; } calc(var(—segment) * 2);
.element { —segment: 30deg; } calc(var(—segment) * 3);
Relative values
codepen.io/michellebarker/pen/yLLGVMQ
Path 1 Path 2 codepen.io/michellebarker/pen/yLLGVMQ
calc(80% - 0.5rem) calc(80% + 0.5rem) codepen.io/michellebarker/pen/yLLGVMQ
calc(20% - 0.5rem) calc(20% + 0.5rem) codepen.io/michellebarker/pen/yLLGVMQ
.element { —bottom: 20%; —top: 80%; —offset: 0.5rem; } codepen.io/michellebarker/pen/yLLGVMQ
.element { —bottom: 20%; —top: 80%; —offset: 0.5rem; } calc(var(—top) - var(—offset)) calc(var(—top) + var(—offset)) codepen.io/michellebarker/pen/yLLGVMQ
.element { —bottom: 20%; —top: 80%; —offset: 0.5rem; } calc(var(—bottom) - var(—offset)) calc(var(—bottom) + var(—offset)) codepen.io/michellebarker/pen/yLLGVMQ
Local scoping
.grid { —cols: 8; } grid-template-columns: repeat(var(—cols), minmax(0, 1fr)); … @media (min-width: 60em) { .grid { —cols: 12; } }
@supports (—cols: 8) { .grid { —cols: 8; } } /* More code here… */
S t a g g e r e d Animations
.some-element:nth-child(2) { —i: 2; } .some-element:nth-child(3) { —i: 3; }
.some-element { —delay: calc(var(—i, 1) * 400ms); }
.some-element { —delay: calc(var(—i, 1) * 400ms); animation: appear 1000ms var(—delay) forwards; }
Progress indicators
li::before { —stop: calc(100% / var(—length) * var(—i)); } background: linear-gradient(to right, var(—c1) var(—stop), var(—c2) var(—stop));
splitting.js.org
Motion Path
⚠ Motion Path
.element { offset-path: path(‘M.4 84.1s127.4 188 267.7 0 247.3 0 247.3 0’); offset-distance: 0; }
.element { offset-path: path(‘M.4 84.1s127.4 188 267.7 0 247.3 0 247.3 0’); offset-distance: 0; animation: move 2000ms infinite alternate; } @keyframes move { to { offset-distance: 100%; } }
codepen.io/michellebarker/pen/wvMvRLy
.element { offset-distance: calc(var(—i, 1) * 4rem); } codepen.io/michellebarker/pen/PoZoVPE
.char { offset-distance: calc(var(—i, 1) * 2rem); } codepen.io/michellebarker/pen/abdbXyZ
.char { offset-distance: calc(var(—i, 1) * var(—offset)); } codepen.io/michellebarker/pen/abdbXyZ
codepen.io/michellebarker/pen/jOWOdxj
—offset: calc(100% / (var(—char-total) + 1)); codepen.io/michellebarker/pen/jOWOdxj
offset-distance: calc(var(—offset) * var(—char-index)); codepen.io/michellebarker/pen/jOWOdxj
.char { —position: calc(var(—char-index) * 1em); } offset-distance: var(—position); animation: move 1500ms infinite alternate forwards; @keyframes move { to { offset-distance: calc(var(—position) + 12rem); } }
codepen.io/michellebarker/pen/abOKPyg
—delay: calc(var(—char-index) * 30ms); codepen.io/michellebarker/pen/abOKPyg
codepen.io/michellebarker/pen/XWJyydY
codepen.io/michellebarker/pen/VwYOvJG
.item { —d: 1000ms; —i: calc(var(—item-total) - var(—item-index)); —x: calc((var(—item-index) - var(—i)) * 4deg); —tPerSegment: calc(var(—d) / var(—item-total)); —itemDuration: calc(var(—tPerSegment) * var(—item-index)); —itemDuration2: calc(var(—tPerSegment) * var(—i)); —c: calc(1 / var(—item-total) * 50); —h: calc(var(—item-index) * 15); —color: hsl(var(—h), 50%, 50%); —offset: calc(var(—item-index) * (var(—c) * 1%) + 1.65rem); —offset2: calc(var(—i) * (var(—c) * 1%)); —endPos: calc(var(—item-total) * (var(—c) * 1%)); } codepen.io/michellebarker/pen/VwYOvJG
codepen.io/michellebarker/pen/QWbGvWj
codepen.io/michellebarker/pen/abdKLLz
✨ Houdini ✨
CSS.registerProperty({ name: ‘—angle’, syntax: ‘<angle>’, inherits: true, initialValue: ‘40deg’, })
transition: —angle 200ms;
@property —angle { syntax: ‘<angle>’; inherits: true; initial-value: 40deg; }
codepen.io/michellebarker/pen/abNZjLB
chars.forEach((el, i) => { el.style.setProperty(‘—s’, getRandom[i]) }) codepen.io/michellebarker/pen/abNZjLB
A user’s guide to CSS variables by Lea Verou bit.ly/3fSZCOS Calculating Color: Dynamic Color Theming with Pure CSS by Una Kravets bit.ly/3akbTKP CSS { In Real Life } css-irl.info
@MicheBarks @CSSInRealLife