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

推荐订阅源

N
News and Events Feed by Topic
GbyAI
GbyAI
博客园 - Franky
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
人人都是产品经理
人人都是产品经理
Microsoft Azure Blog
Microsoft Azure Blog
The Register - Security
The Register - Security
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
InfoQ
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
有赞技术团队
有赞技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
F
Full Disclosure
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
博客园 - 【当耐特】
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Project Zero
Project Zero
量子位
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
美团技术团队
Attack and Defense Labs
Attack and Defense Labs
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Blog of Author Tim Ferriss
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Troy Hunt's Blog
Google Online Security Blog
Google Online Security Blog
罗磊的独立博客
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
Spread Privacy
Spread Privacy
S
SegmentFault 最新的问题
L
LINUX DO - 最新话题
Simon Willison's Weblog
Simon Willison's Weblog
爱范儿
爱范儿
博客园 - 聂微东
A
About on SuperTechFans
PCI Perspectives
PCI Perspectives
D
Docker

Bram.us

What’s new in Web UI (Google I/O 2026) Cranking View Transtions up to 11 (2026.05.07 @ All Day Hey!) Cranking View Transtions up to 11 (2026.04.28 @ Beyond Tellerrand) Do Websites Need to Function Exactly the Same on Every Platform? View Transitions: Use the new attr() or match-element for the view-transition-name? Introducing view-transitions-toolkit, a collection of utility functions to more easily work with View Transitions. CSS position: sticky now sticks to the nearest scroller on a per axis basis! Cranking View Transtions up to 11 (2026.03.25 @ devs.gent) Detect at-rule support in CSS with @supports at-rule(@keyword)
More Easy Light-Dark Mode Switching: light-dark() is about to support images!
Published by Bramus! · 2026-03-19 · via Bram.us

Back in 2023, I wrote about the future of CSS color switching using the then-novel light-dark() function. It was a game-changer for colors, allowing us to ditch the repetitive @media (prefers-color-scheme: ...) blocks for simple property declarations.

But there was one glaring limitation: it only works for colors. If you wanted to swap out a background image, a mask, or a logo based on the user’s color scheme, you were stuck doing things the “old” way.

Well, I have good news. The spec has been updated, and light-dark() is being extended to support images.

~

# The Missing Piece

As a recap, in CSS, you have to write something like this if you want to set background-images for light and dark mode:

:root {
  --bg-image: url(light-pattern.png);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg-image: url(dark-pattern.png);
  }
}

.element {
  background-image: var(--bg-image);
}

This code has downsides: The necessary parts can be scattered all over the place and it only checks the global color-scheme preference without respecting local color-scheme overrides done with the color-scheme CSS property.

Thanks CSS light-dark() we can keep our code closely together, and can respond to the local used color-scheme value. In it’s updated form – in which light-dark() now also supports <image> values – that whole block can be collapsed into a single rule, and we can make it respect local color-scheme overrides:

.element {
  color-scheme: dark;
  background-image: light-dark(url(light-pattern.png), url(dark-pattern.png));
}

Sweet!

Note that you must pass in either two <color> values or two <image> values as arguments to light-dark() … you can’t mix the types — see further down for an explanation why that is.

~

# Browser Support

💡 Although this post was originally published in March 2026, the section below is constantly being updated. Last update: May 26, 2026.

It’s early days, but the engines are already moving:

Chromium (Blink)

✅ Supported in Chrome 150. Chrome 150 is expected to go stable on Jun 17, 2026

Firefox (Gecko)

✅ Supported in Firefox 150

Safari (WebKit)

❌ No support

Subscribe to WebKit Bug #309689 for updates.

~

# Feature Detection

If you want to start experimenting today while providing a fallback, you can use @supports. To detect support for images specifically, you can test it using linear-gradient() (which is treated as an <image> in CSS) or — another new addition — the keyword none:

@supports (background-image: light-dark(none, none)) {
  /* Modern image-switching logic here */
}

You can see the code in action this CodePen:

See the Pen CSS light-dark(<image>, <image>) Support test by Bramus (@bramus) on CodePen.

~

# What about non-<color> and non-<image> values?

Supporting non-<color> and non-<image> values still is an unanswered question (that probably won’t get solved). As explained in my original coverage, CSS can’t just simply accept light-dark() anywhere because the parser needs to know the value type of what it is parsing ahead of time.

Internally, light-dark() is about to be defined as having two internal variants – one that accepts <color>s and one that accepts <image>s:

light-dark() =  <light-dark-color> | <light-dark-image>
<light-dark-color> = light-dark(<color>, <color>)
<light-dark-image> = light-dark(<image>, <image>)

Each variant has limitations on where it can be used: the version that does colors is only accepted where <color>s are allowed, and the version that does images is only accepted where <image>s are allowed.

<color> = <color-base> | currentColor | <system-color> | 
          <contrast-color()> | <device-cmyk()> | <light-dark-color>
<image> = <url> | <image()> | <image-set()> | <cross-fade()> | 
          <element()> | <gradient> | <light-dark-image>

If more types of values needed to be supported, that would required many more internal variants.

This split into two variants allows the CSS parser to discard invalid declarations at parse time. That, in turn, explains why you can’t mix the types in the arguments. Say CSS were to accept a mix of <color> and <image>, then you would be able declare something like background: red light-dark(blue, url(dark.png));. With a dark color-scheme that declaration would end up being OK, but in a light color-scheme you’d end up with background: red blue which is invalid.

Looking ahead: @function + color-scheme() to the rescue!

In the future there will be an way to have non-<color> and non-<image> color-scheme-dependent values in the future: using a CSS Custom Function and color-scheme(). Go check out my previous post on implementing a custom --light-dark() function that works with any type of value for the details. It’s just 3 lines of code, which I’ve included here as well:

@function --light-dark(--l, --d) {
  result: if(color-scheme(dark): var(--d); else: var(--l));
}

To feature detect support for @function, check out @supports at-rule(). There currently is no easy way to detect support for color-scheme(), unless you want to jump through some hoops.

~

# Spread the word

Feel free to reshare one of the following posts on social media to help spread the word:

~

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)