Custom Property Patterns: Fallback Chains and the Invalid-Value Trap
CSS variables can chain fallbacks, expose component APIs and scope themes - and they fail in a uniquely confusing way that every serious user needs to understand once.
Software Engineer
I build web applications and share what I learn along the way.
Step-by-step programming tutorials on PHP, JavaScript, Laravel, WordPress and more.
CSS variables can chain fallbacks, expose component APIs and scope themes - and they fail in a uniquely confusing way that every serious user needs to understand once.
margin-left breaks the moment your site meets Arabic or Hebrew. Logical properties describe direction-relative intent - and they are more ergonomic even if you never localize.
padding-top: 56.25% wrapped in a positioned div was how we faked 16:9 boxes for fifteen years. One property replaces the whole contraption - and prevents layout shift while it's at it.
The browser parses nested CSS without any build step. The syntax is almost Sass - the differences, the & rules, and the over-nesting trap are what matter.
:is() collapses repetitive selector lists, :where() does it with zero specificity - which turns out to be the secret to CSS that is easy to override.
Floating point cannot represent most decimal fractions, and prices are decimal fractions. Work in integer cents, round deliberately, and let Intl handle the display.
CSV exports, JSON backups, generated reports - the browser can create files and hand them to the user without the server ever touching the data.
Plain sort puts item10 before item2 because strings compare character by character. Intl.Collator fixes it, handles accents and case, and is faster than localeCompare in loops.
The replacer filters and redacts on the way out, the reviver rebuilds Dates on the way in, and toJSON lets objects decide their own serialization. All native, all ignored.
dataset gives JavaScript typed-ish access to data attributes, CSS can select on them and even display them with attr() - one mechanism, three languages, zero coupling.
Promise.all fails everything when one request dies - usually not what a dashboard wants. The other three combinators cover the cases all() gets wrong.
Python has range(), PHP has range() - JavaScript has a weird-looking idiom that does the same and more, once you understand why the mapping callback is built in.