惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
Recent Announcements
Recent Announcements
GbyAI
GbyAI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Microsoft Azure Blog
Microsoft Azure Blog
N
Netflix TechBlog - Medium
人人都是产品经理
人人都是产品经理
MongoDB | Blog
MongoDB | Blog
D
DataBreaches.Net
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
WordPress大学
WordPress大学
U
Unit 42
腾讯CDC
D
Docker
The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
Vercel News
Vercel News
I
InfoQ
Jina AI
Jina AI
爱范儿
爱范儿
宝玉的分享
宝玉的分享
博客园 - Franky
G
Google Developers Blog
P
Proofpoint News Feed

Starred Articles

Why some people mow a lawn better than others Improvements to Web for AI Should Benefit All Users chriscoyier.net When Sites Need to Walk Away AI & Alignment New to the web platform in April  |  Blog  |  web.dev Delivering a dynamic hexagonal world map in just 10kb | Calibre My house alerts me when my cat climbs into the ceiling Eames Pavilion System Squarespace & Web Standards: How We Helped Bring HTML Video & Audio Lazy Loading to Today’s Browsers | Scott Jehl, Web Designer/Developer The Web is a Guitar Amp Now (Literally) Claude is an Electron App Making keyboard navigation effortless Miscalibrated I used Claude Code and GSD to build the accessibility tool I’ve always wanted - blakewatson.com Sizing chaos The Good & Not Good Scroll indicators on tables with background colours using animation-timeline Webspace Invaders Fresh Hot CSS: Trig Functions The Year Of The Linux Desktop (for fitness games) Almost Plain Text, Nicely Done – Email is good. Uncrate's 100-ish favorite things on Amazon VS Code – highlight just the active indent guide How musicals use motifs to tell stories Good Tidings! Review: MoErgo Go60, a split ergonomic and fully programmable keyboard The line and the stream. — Ethan Marcotte Testing HTML Light DOM Web Components: Easier Than Expected! Steam Machine
Enhancing Web Components Safely with Self-Destructing CSS...
2025-11-17 · via Starred Articles

By Scott Jehl

A month ago, I wrote about a defensive CSS convention I've been calling Self-Destructing CSS. As CSS patterns go these days this one is delightfully low-tech, but in my work I've seen it have an outsized impact in ensuring usable experiences for increasingly-heavy websites when network or device conditions aren't ideal.

This notion of delivering "optimistically" while planning for failure is something I've written about before, but the set-it-and-forget-it nature of this latest stab at it makes it my favorite yet. And funny enough, while it's just another take on careful Progressive Enhancement, this one actually feels more like "graceful degradation" to me! Hmm. I won't dwell on that one.

Anyway, last week, Brian Kardell pointed out to me over on Bluesky that the problem Self-Destructing CSS addresses reminded him of one that commonly occurs with Web Components, when developers hide custom elements until they are "defined" by their JavaScript. That's an anti-pattern I covered in my Web Components course, and it's common because it aims to work around a very real issue: often, we don't want our users to see a component until it's "ready."

That (anti)-pattern looks like this:

:not(:defined) {
  visibility: hidden;
}

Let's break that down. CSS gives us the pseudo-state :defined which will match any custom element once it is defined by JavaScript. For example, if you have an element <my-element> in your HTML, it starts out essentially a div with a more descriptive name. That "~div" could be useful on its own, but typically developers will define its custom behavior using the customElements APIs now built into browsers (effectively turning it into a "web component," if you please). That element definition looks like this:

customElements.define('my-element', class extends HTMLElement {
  /*...lifecycle additions can go here */
});

Once defined, my-element will be selectable in CSS via :defined, along with all of the other "defined" HTML elements. To be clear, that includes every built-in element defined by the browser, so that :defined selector alone isn't terribly useful on its own, and might do better paired with an element selector instead. That said, if we're trying to style all undefined custom elements to hide them before they're defined, then a selector that matches the opposite of :defined is pretty handy. That's how folks arrived at hiding content with :not(:defined) { visibility: hidden; }.

Unfortunately, while this pattern is clever, it's also risky: if JS fails to run or load in any reasonable amount of time, those elements will remain hidden. I've seen this pattern cause content to be invisible for long periods while popular budget-tier devices struggle to churn through massive JavaScript bundles, even if they're on a fast network.

After a brief delay, hiding content entirely just isn't worth whatever effect you're hoping to achieve.

Improving :not(:defined) with Self-Destructing CSS

As I commented in this HTML standard issue about it, this situation is a great use case for self-destructing CSS.

So moving forward, if you need to hide un-enhanced Custom Elements, I suggest you do not do this:

:not(:defined) {
  visibility: hidden;
}

And instead, do this!

@keyframes hideBriefly {
  0%, 100% { visibility: hidden; } 
}
:not(:defined) { animation: hideBriefly 2s; }

Here, just as before, as soon as your element gets defined, the hiding will instantly and automatically unapply. But it will also unapply itself after two seconds no matter what, should the JavaScript take that long to do its thing, or fail to run at all. That last part is critical, because in our medium, we can't expect things to just work like they do on our machine. In fact, they usually don't.

Anyway, that's Self-Destructing CSS for web components. Go play some defense out there on behalf of your users! Oh, and if you want to take this the extra mile, make sure that your initially-delivered HTML is useful/meaningful/functional before the JavaScript loads. Otherwise, you might as well just hide it without a fallback, I guess!