CSS Tricks, Nine Years Later
In March 2017 I wrote a short post called CSS Tricks That Makes Web
Designing Easy. Four practical bits I was excited about at the time:
custom properties, gradient overlays on images, object-fit: cover, and
flexbox for card grids.
Nine years later the baseline has shifted. Three of those “tricks” are now just how you write CSS. The fourth — flexbox for grids — has a better tool now. This is the same article, rewritten with what I’d actually reach for in 2026.
1. Custom properties
Then: CSS variables were a fresh win — define colors and spacing
once on :root, reference them with var().
:root {
--primary: #ff5722;
--gap: 16px;
}
Now: That still works, but variables compose with color-mix(),
OKLCH, and @property for typed values you can actually animate.
:root {
--primary: oklch(70% 0.18 30);
--primary-soft: color-mix(in oklch, var(--primary) 30%, transparent);
}
@property --hue {
syntax: '<number>';
inherits: true;
initial-value: 30;
}
Variables aren’t a trick anymore — they’re the substrate everything else runs on.
2. Image overlays
Then: Layer a translucent linear-gradient over a background image
to keep text readable.
.hero {
background:
linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)),
url('hero.jpg') center / cover;
}
Now: Same idea, but backdrop-filter and mix-blend-mode give you
overlays that respond to the image underneath instead of flat-darkening
it.
.hero {
position: relative;
background: url('hero.jpg') center / cover;
}
.hero::after {
content: '';
position: absolute;
inset: 0;
backdrop-filter: brightness(0.6) saturate(1.1);
}
Looks better on bright photos and you don’t lose color depth in the shadows.
3. Object-fit on images
Then: object-fit: cover on an <img> so it crops proportionally
inside fixed dimensions, the way background images do.
img {
width: 100%;
height: 200px;
object-fit: cover;
}
Now: Same property — still load-bearing — but paired with
aspect-ratio you stop hardcoding heights entirely.
img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
The image reserves its space before it loads, the container scales fluidly, and cumulative layout shift goes to zero.
4. Card grids
Then: Flexbox with flex-wrap and percentage widths for a
responsive card layout.
.cards {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 calc(33.333% - 16px);
}
Now: CSS Grid does this in one line and handles uneven counts cleanly. Subgrid lets children align across cards.
.cards {
display: grid;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3;
}
auto-fit + minmax() replaces most media queries you used to write
for card layouts.
What didn’t exist in 2017
The previous four were updates. These four are genuinely new — none of them were usable when I wrote the original.
Container queries. Components respond to their container, not the viewport. A sidebar card and a hero card can use the same component and render differently because the container width differs.
.card {
container-type: inline-size;
}
@container (min-width: 400px) {
.card-body {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
Fluid type with clamp(). One line that scales smoothly between a
min and max without a single media query.
h1 {
font-size: clamp(28px, 5vw, 48px);
}
The :has() selector. “Style the parent based on its children” —
the thing CSS couldn’t do for two decades.
.card:has(img) {
padding: 0;
}
.form:has(input:invalid) {
border-color: red;
}
Logical properties. margin-inline, padding-block,
inset-inline-start. They map to text-flow direction instead of
physical sides, so one stylesheet works for LTR and RTL without
overrides.
.card {
padding-block: 16px;
padding-inline: 24px;
margin-inline-start: auto;
}
The biggest takeaway from rereading the 2017 version is how much of
what used to be a trick is now boring. Variables are the default.
object-fit is the default. Gradient overlays are still useful but
live in a richer toolbox now.
The work has moved up the stack. The interesting CSS questions in 2026 aren’t how do I center a div — they’re how does this component behave when its container changes shape, when the user prefers reduced motion, when the layout has to render across left-to-right and right-to-left scripts without rework. The primitives are finally good enough that those are the real questions.