7 CSS One-Liners That Replace JavaScript in 2026

CSS one-liners that replace JavaScript in 2026 — a giant gradient number 7 with the headline "CSS One-Liners That Replace JavaScript" and the tagline "Fresh for 2026, all demos live"

Web Design / CSS

Auto-growing textareas, balanced headlines, stagger animations, auto-contrast text: seven little CSS one-liners that finally went cross-browser in 2026. Steal them. You’ll feel lighter.

TL;DR: seven lines, zero JavaScript:

  • field-sizing: content Chrome 123 · Safari 26.2 · Firefox 152
  • text-wrap: balance Baseline since 2024
  • sibling-index() Firefox 154 · Safari unverified
  • contrast-color() Chrome 147 · Safari verify
  • text-box: trim-both Firefox 154
  • scrollbar-gutter: stable 93.74% global
  • :user-invalid Baseline May 2026

Somewhere in your codebase there’s a JavaScript dependency doing a job CSS learned to do this year. Auto-growing textareas. Staggered animations. Text that picks its own contrast color. One line each, no build step. And every demo on this page is live, so you can poke at them right now.

We noticed it the day we deleted autosize from a client’s contact form and the form grew exactly the same. Twelve kilobytes of library, gone, replaced by a single property the browser already shipped. That moment felt a little illegal, honestly. This list is the seven deletions worth making after it.


01field-sizing: content: the Auto-Growing Textarea

Every comment box, contact form, and support ticket field used to need a script. autosize.js, a rows-counting resize handler, or some hand-rolled oninput that guessed how many rows your text would wrap to. All of it, just to make the box tall enough. You know the one. Half your form code, and it still never felt quite right.

The browser can count its own lines now. Let it.

textarea {
  field-sizing: content;
}

Live Demo

One line. That’s the whole tutorial. Go on, type in the box above, watch it grow.

Pair it with min-height and max-height so it doesn’t collapse to nothing or swallow the page. Cross-engine since Chrome 123 (March 2024), Safari 26.2 (December 2025), and Firefox 152 (June 2026). If your bundler ships 12 KB to grow a textarea, that’s not engineering. That’s habit. And habits are the cheapest thing to break.


02text-wrap: balance: Headlines That Stop Looking Drunk

You’ve seen the headline with one sad little word dangling on the last line all by itself. Looks a bit drunk, right? The old fix was balance-text.js, a script that measured your heading and jammed in <br> tags until the breaks looked even. It ran after every resize. It fought your responsive layout. And the second you edited the copy, the breaks were wrong all over again.

Turns out the browser just needed to be asked nicely.

h1, h2, .card-title {
  text-wrap: balance;
}

Live Demo

Performance-obsessed websites that refuse to waste a single line

balance

Performance-obsessed websites that refuse to waste a single line

default

Top one’s balanced. Bottom one’s the default rag. I capped the demo at a narrow column so the difference is obvious; at full page width a balanced headline and an unbalanced one can look almost identical, which is kind of the point of the whole feature. Baseline since 2024 across every engine, so there’s no reason left to ship the script. It’s one of those rare “works everywhere, today” wins.

One friendly warning, because it saves people real pain: this is for headings. Don’t slap it on body text. The browser has to lay the paragraph out twice to balance it, and on long text that’s measurable. For running paragraphs there’s a gentler cousin, text-wrap: pretty, which stops that last lonely word. Firefox still doesn’t ship pretty, so treat it as a free upgrade, not a dependency.


03sibling-index(): Stagger Without the –i Hack

Staggered card entrances used to need a --i custom property set by JavaScript, a loop that counted each element and wrote its index back into a variable. You’d see style="--i: 3" sprayed across the DOM like confetti. Fine, it worked. But it was a whole lot of plumbing for a delay.

CSS can count its own siblings now. Which is just delightful.

.stagger-item {
  animation-delay: calc((sibling-index() - 1) * 90ms);
}

Live Demo

Each tile’s delay is computed by the browser, not a loop. The - 1 keeps the first item instant. Firefox 154 (August 18, 2026) joined Chrome on this one. Two items on this list shipped that same day, which is why this post exists at all.

The Safari caveat, said straight. We don’t know exactly when sibling-index() lands in Safari. We ship it anyway, because the fallback is invisible: an unsupported browser just runs every animation at the same time. No stagger, but nothing breaks. Honestly, we’d rather have a slightly flat animation on one browser than a dependency on all of them.

Want more CSS animation along the same lines? We wrote up four animated card effects with zero JavaScript.


04contrast-color(): Text That Picks Black or White by Itself

Every button built on a user-chosen color used to need a luminance check, JavaScript that converted the background to relative luminance, compared it against a threshold, and returned black or white. It was five lines of code you copy-pasted forever and never quite trusted. Deep down you always suspected your math was off on that one weird green.

Let the browser do the squinting.

.swatch {
  color: #f4f4ff;                                    /* fallback first */
}
@supports (color: contrast-color(red)) {
  .swatch { color: contrast-color(var(--swatch-bg)); } /* then the real thing */
}

Live Demo

Label
Label
Label

Three backgrounds, and each label figures out its own color. Yellow gets dark text, purple gets light, cyan gets dark. The fallback pattern matters here: declare a plain color first, then let supporting browsers override it. Chrome 147 (April 2026) shipped it, and it’s an Interop 2026 focus area. So the rest of the engines are actively chasing it. Good.


05text-box-trim: Kill the Mystery Space Above Headlines

Every designer has fought the phantom gap. Your heading sits 6 pixels lower than it should because the font’s line box reserves space above the cap height. The fix was always a magic-number negative margin, a number you tweaked by eye, per font, and watched break the moment someone changed the typeface. Six pixels. You probably spent an hour on it.

The browser can trim its own line box now. Six pixels, gone, no voodoo.

.trimmed-heading {
  text-box: trim-both cap alphabetic;
}

Live Demo

Headline

default

Headline

trim-both

Same headline, same padding. The right box trims the reserved space down to the actual cap height, so the text sits flush against the top of its block. Firefox 154 (August 18, 2026) completed cross-engine support for this one. The same release that finished sibling-index(). Busy month for Firefox.

If you’re chasing typography control in pure CSS, we did a whole deep build on it: a vintage newspaper theme with nothing but CSS.


06scrollbar-gutter: stable: the Layout-Shift Fix Nobody Uses

You know the jump. A page loads without a scrollbar, you navigate, and suddenly the whole layout shoves 15 pixels left because the bar just appeared. It’s the most jarring little hiccup on the web, and nobody can ever reproduce it in a demo until it happens in front of a client.

The old fixes were overflow-y: scroll (which draws a scrollbar even when nothing scrolls) or a JavaScript probe that measured the bar’s width. One property reserves the gutter for you instead.

.scroll-pane {
  scrollbar-gutter: stable;
}

Live Demo


CENTERED

Short.Plus a whole lot more text so the scrollbar is forced to appear even on a wide desktop screen. Line two. Line three. Line four. Line five. Line six. Line seven. Line eight. Line nine. Line ten. Line eleven. Line twelve. Line thirteen. Line fourteen. Line fifteen. Line sixteen. Line seventeen. Line eighteen. Line nineteen. Line twenty. Line twenty-one. Line twenty-two. Line twenty-three. Line twenty-four.

default

CENTERED

Short.Plus a whole lot more text so the scrollbar is forced to appear even on a wide desktop screen. Line two. Line three. Line four. Line five. Line six. Line seven. Line eight. Line nine. Line ten. Line eleven. Line twelve. Line thirteen. Line fourteen. Line fifteen. Line sixteen. Line seventeen. Line eighteen. Line nineteen. Line twenty. Line twenty-one. Line twenty-two. Line twenty-three. Line twenty-four.

scrollbar-gutter: stable

Click the button. Both boxes get the same extra content, and both grow a scrollbar. The left box has to steal space from its own content to make room for it, so the centered badge and every line shove sideways. The right box reserved that gutter from the start, so its content never moves a pixel. That’s the whole trick. Chrome 94+, Firefox 97+, Safari 18.2+, 93.74% of the world’s browsers. And it’s been sitting there waiting for years. Nobody reaches for it because nobody gets told about it. Now you’re told. Go fix that layout shift you’ve been ignoring.


07:user-valid / :user-invalid: Validation That Waits for the User

Standard :invalid is a bit rude. It marks a field red the instant the page loads, before your visitor has typed a single character. Imagine a form that yells at you the second you arrive. That’s what every site with a “required email” field used to do.

So everyone wrote the same “dirty state” JavaScript, a blur listener that flips a class after the user has actually touched the field. This replaces all of that.

input:user-invalid {
  border-color: #ff2fb9;
}

Live Demo

Loads calm. Only judges the email after you’ve touched the field and left it wrong. Try the demo: type a nonsense email, click away, then watch it blush. :user-invalid reached Baseline Widely Available in May 2026, which means the three engines all agree and it’s safe to build on. Delete the dirty-state listener. Your forms get kinder for free.


The Support Cheat Sheet

One-linerChromeFirefoxSafariStatus
field-sizing: content12315226.2Cross-engine since June 2026
text-wrap: balance✓✓✓Baseline since 2024
sibling-index()✓154NoProgressive enhancement; Safari unverified
contrast-color()147NoNoInterop 2026 focus area; ship a fallback
text-box: trim-both✓154✓Cross-engine since Aug 2026
scrollbar-gutter: stable949718.293.74% global
:user-invalid✓✓✓Baseline Widely Available, May 2026

Versions are current as of August 30, 2026. The two ⚠️ cells, Safari for sibling-index() and contrast-color(), are the ones to re-check on caniuse before you treat them as guaranteed. That’s the only homework in this whole post, promise.


Frequently asked questions

Can CSS replace JavaScript?

For layout, animation, and presentation, increasingly yes. Each of the seven one-liners here kills a small script that was only ever a workaround for something the browser now does natively. CSS still can’t replace logic, state, or business rules. The right question isn’t “can CSS replace JS” but “which of my dependencies are just papering over a gap that closed this year.”

What does field-sizing: content do?

It makes a form field size itself to its contents. On a textarea, the box grows as the user types, instead of relying on a JavaScript library like autosize.js to count rows and set height. Pair it with min-height and max-height so the field has sane bounds.

Do these CSS one-liners work in all browsers?

Mostly, and the gaps are designed for. text-wrap: balance, scrollbar-gutter, and :user-invalid are all cross-engine today. field-sizing, text-box-trim, and sibling-index() went cross-engine in 2026. contrast-color() is Chrome-only for now but ships a clean fallback. Check the support table above for the exact versions.

What is text-wrap: balance for?

It evens out the line lengths in a short block of text, usually a heading, so you don’t get a single orphaned word dangling on the last line. It replaces JavaScript libraries like balance-text.js. Use it on headings and titles, not body text, since balancing long paragraphs costs a second layout pass.

Steal the stylesheet. All seven one-liners live in one commented file you can drop into your project and delete a dependency at a time. And if you’re hungry for more no-JavaScript tricks, we’ve collected a few here: five CSS menu tricks that need zero JS. Go break a dependency today.

Leave a Comment

Your email address will not be published. Required fields are marked *