What are you trying? Are you happy with it?
(as a point of reference)
Your mileage will vary
Doesn’t mean we all need to
I think they are all pretty neat and I see the point…
— Chris Coyier
But I’m a bunch of years into this and still generally… write the selector I need and then style with that.
— Chris Coyier
Conventions won’t save us
Conventions can develop over time
CSS Systems, 2008
YUI, Blueprint, 960gs, etc…
<div class="
column col6of12 last
" >
(this was before RWD & Media Queries)
(which may provide sizing)
(the variable axis for blocks)
Object Oriented CSS, 2009
A CSS “object” is a repeating visual pattern, that can be abstracted into an independent snippet of HTML, CSS, and possibly JavaScript.
— Nicole Sullivan, OOCSS
Avoid even unique component styles
(Unique components, without unique CSS)
width
height
SMACSS, BEM, ITCSS, CUBE, etc…
article
& section
Elements
Building with accessible semantics from the get-go can give you expressive, meaningful style hooks for free.
— Ben Myers, Style with Stateful, Semantic Selectors
/* expressive semantics */
form:has(:invalid) [type="submit"] { … }
/* some name we came up with? */
.form__btn--submit--invalid { … }
a[href*="://"] { /* external links */ }
a[href^="https:"] { /* secure links */ }
a[href$=".pdf"] { /* pdf links */ }
button[aria-pressed=true] { /* pressed buttons */ }
img:not([alt]) { /* images without alt text */ }
.flow > * + * {
margin-block-start: var(--flow-space, 1em);
}
No “intervention by the author”
* { /* universal */ }
p { /* type */ }
.summary { /* attribute */ }
#call-to-action { /* id */ }
h2:has(> button[aria-expanded="false"]) + div {
display: none;
}
div
that comes after an h2
button
child, that is not expanded)Especially “At Scale”
/* …default table styles… */
table[rules=cols i] > tfoot > tr > td,
table[rules=cols i] > tfoot > tr > th,
table[rules=all i] > tfoot > tr > td,
table[rules=all i] > tfoot > tr > th {
border-color: black;
}
[hidden] { display: none; }
display:none
on the hidden
attribute*
type
s.class
es & [attributes]
#ID
s.block .element.modifier { /* 3 */ }
.block__element--modifier { /* 1 */ }
.🤬-bootstrap {
font-weight: bold !important;
}
.card.info { border-color: teal; } /* ✅ */
.card--warning { border-color: orange; } /* ❌ */
.card { border-color: gray; }
(still meaningful and expressive)
Inverted Triangle CSS, 2014
From p {}
through .text-center {}
@layer settings { … }
@layer tools { … }
@layer generic { … }
@layer elements { … }
@layer objects { … }
@layer components { … }
@layer overrides { … }
Only compared inside a layer
/* establish layer order */
@layer one, two, three;
/* add code to layers as needed */
@import url(two.css) layer(two);
@layer three { … }
@layer one { … }
@layer two { … }
@layer components {
@layer state { … }
}
/* access nested layers */
@layer components.state { … }
/* system.css */
@layer theme { … }
@layer components { … }
@import url(system.css) layer(system);
@layer system.theme { … }
@layer system.components { … }
@import url(system.css) layer(system);
@layer system.theme { … }
@layer system.components { … }
@layer system.custom { … }
@import url(bootstrap.css) layer(bootstrap.theirs);
@layer bootstrap.ours {
/* anything here will override bootstrap */
}
@layer components {
@layer defaults, themes, state;
}
my recommendations
/* add as the first styles */
@layer reset, framework, components, utilities;
<style>/* keep this before linked styles */
@layer reset, framework, components, utilities;
</style>
<link rel="stylesheet" href="…">
<link rel="stylesheet" href="…">
<style>
@layer reset, framework, components, utilities;
@import url(…) layer(reset);
@import url(…) layer(framework);
</style>
*Including inter-org dependencies
@import url(bootstrap.css) layer(bootstrap.vendor);
@layer bootstrap.overrides {
/* anything here will override bootstrap */
}
<template>…</template>
<style>
@layer components {
/* … */
}
</style>
*the styles will be hidden from older browsers
<feature>
With <tool>
??
Can it handle color
s and length
s?
(otherwise ‘tools’ become obstacles)
<div class="Bgc(#0280ae.5) C(#fff) P(20px)">...</div>
<body class="bg-green black-70 pa4">
<h1 class="f1">...</h1>
</body>
<div class="md:flex">
<div class="md:flex-shrink-0">
<img class="rounded-lg md:w-56" src="..." alt="">
</div>
<div class="mt-4 md:mt-0 md:ml-6">
<div class="uppercase tracking-wide text-sm text-indigo-600 font-bold">...</div>
</div>
</div>
¯\_
(ツ)
_/¯
When you… reduce the amount of time you spend writing and editing CSS… you must instead spend more time changing HTML classes…
— Nicolas Gallagher
.btn {
@apply font-bold py-2 px-4 rounded;
}
.btn-blue {
@apply bg-blue-500 text-white;
}
.btn-blue:hover {
@apply bg-blue-600;
}
Websites
don’t need tocannot possibly look the same in every browser.
— The web, paraphrased
The fact we can control a paper page is really a limitation of that medium.
— John Allsopp, A Dao of Web Design
Define some constraints. Let the language work out the details.
— Keith J Grant
CSS Systems, OOCSS, ITCSS, CUBE…
Use custom elements, attributes, ids, pseudos…
.card.big { /* classes */ }
.card--big { /* BEM */ }
/* Custom element with attributes */
my-card[data-size="big"] { /* … */ }
(with or without @layer
)
Styles should be reusable…
/* .page header { … } */
.page__header { … }
header.masthead { … }
/* Runs the risk of becoming out of date; not very maintainable. */
.blue { color: blue; }
/* Depends on location in order to be rendered properly. */
.header span { color: blue; }
/* Too specific; limits our ability to reuse. */
.header-color { color: blue; }
/* Nicely abstracted, very portable, doesn’t risk becoming out of date. */
.highlight-color { color: blue; }
a { text-decoration: underline; }
nav a { text-decoration: none; }
a { text-decoration: var(--link-decoration, underline); }
nav { --link-decoration: none; }
a:not([data-link]) {
text-decoration: var(--link-decoration, underline);
}
nav {
--link-decoration: none;
}
:not()
to exclude selectors.wrapper {
margin-inline: auto;
padding-inline: 1rem;
max-width: 60rem;
}
[hidden] { display: none !important; }
[visually-hidden]:not(:focus-within) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
.bg-primary { background: #ff00ff; }
.bg-secondary { background: #ffbf81; }
[data-bg=primary] { background: #ff00ff; }
[data-bg=secondary] { background: #ffbf81; }
[data-bg] { background: var(--canvas-color); }
[data-bg=primary] { --canvas-color: #ff00ff; }
[data-bg=secondary] { --canvas-color: #ffbf81; }
[style*='--canvas-color:'] {
background: var(--canvas-color);
}
CSS is unlike anything else… designed for the realities of a flexible, multilingual, multi-device web.
— Rachel Andrew