As users, we all have different preferences for the applications we use. Usually, these preferences are set on our device to be applied to all applications. In the past, websites would have little to no idea about the preferences set by users. Developers would set features and themes based on what they believed were the most popular, inadvertently causing accessibility conflicts.
For example, many developers and gamers prefer dark themes. But assuming that all developers and gamers prefer a dark theme and setting your website to a dark theme would be unpleasant for developers and gamers who prefer a light theme.
Ideally, you would design your application so that features align with whatever preferences each user has set. New CSS features are allowing developers to optimize their websites to fit user preferences.
In this article, we will talk about two new CSS features for optimizing according to users’ preferences. The first is prefers-reduced-transparency
, which reduces translucency, and the second is light-dark()
, which sets a light or dark theme. We will also look at live demos of these features.
prefers-reduced-transparency
media queryThe CSS prefers-reduced-transparency
media query allows you to optimize your elements to use less or no transparency by detecting whether a user has set a reduced transparency preference on their device settings:
/* syntax */ .transparent-element { opacity: 0.6; } @media (prefers-reduced-transparency) { /* reduce elements transparency */ .transparent-element { opacity: 1; } }
transparent-element
only becomes opaque when the user has the reduced transparency feature turned on. You can turn yours on if you’re using the following operating symptoms:
Before we jump into more examples of using the prefers-reduced-transparency
feature, let’s look at why people use it and why you (as a developer) should care about it.
prefers-reduced-transparency
?As a web developer, your goal is usually to make a UI consistent for all users and to make your website fully accessible.
If your website’s UI is made up of transparent text or images but there are users who do not prefer transparent objects, there is a possibility that those users may struggle with your website and exit it entirely. This can be due to several reasons:
Additionally, there are some users who simply prefer a solid, straightforward UI.
prefers-reduced-transparency
At the time of writing, prefers-reduced-transparency
is still experimental and not supported in most modern browsers. So you want to make sure it works as expected in your support browser before moving to production.
You can test the example below using Chrome 118 and above. You can also use Firefox, but you will need to set layout.css.prefers-reduced-transparency.enabled
to true
. To do that, open a new tab and type in about:config
. Then, search for layout.css.prefers-reduced-transparency.enabled
and toggle the Boolean to true
.
In our earlier example, we basically made a transparent element non-transparent by simply adding a media rule. Now, we will take it a step further and use a day-to-day example:
See the Pen
prefers reduced transparency by Elijah Trillionz (@Elijah-Trillionz-the-sans)
on CodePen.
Now, if you head to your device preferences and turn on the reduced transparency, you’ll notice that the card
elements become fully opaque.
When you hover over each card
, the element only scales up and down. In other use cases, you may need to specify a completely different hover declaration to differentiate between the hovered element and the others. This is an example in a header nav:
.nav li { opacity: 0.7; } .nav li:hover { opacity: 1; } @media (prefers-reduced-transparency) { .nav li { opacity: 1; } .nav li:hover { text-decoration: underline; } }
Addressing each transparent element in the media rule and reducing the transparency for each element can be a pain. So a clean and simple way to adjust the transparency of each applicable element would be to use CSS variables wherever possible. For example:
/* using CSS variables */ :root { --primary-color: #3caf507d; --opacity: 0.7; } .transparent-element { opacity: var(--opacity); } .transparent-background { background-color: var(--primary-color); } @media (prefers-reduced-transparency) { :root { --primary-color: #3caf50; --opacity: 1; } }
So far, the examples we’ve seen have to deal with reducing the transparency for users who prefer that. But it is also possible to build your website so that it supports opaque elements by default, while providing users the option to have transparent elements.
To do that, we would need to assign a value to prefers-reduced-transparency
. There are two values that can be assigned to prefers-reduced-transparency
:
no-preference
, which indicates that the reduced transparency is not turned on on the user’s devicereduce
, which indicates that the reduced transparency preference is turned on by the user
/* syntax */ .opaque-element { opacity: 1; } @media (prefers-reduced-transparency:no-preference) { /* add transparency to elements */ .opaque-element { opacity: 0.6; } }
Here is a demo of our testimonial example:
See the Pen
prefers transparency by Elijah Trillionz (@Elijah-Trillionz-the-sans)
on CodePen.
Now you have to be careful how you set the transparency of your app. From all the examples you’ve seen, you’ll notice that the default behavior needed for the app is always set before optimizing to fit users’ preference.
If your app favors transparent elements by default, you should set that first and then use the prefers-reduced-transparency
to adjust to less transparency.
This is important because not maintaining this consistency could cause your app to have an inconsistent UI where elements that were intended to be transparent wind up being opaque for browsers that don’t yet support prefers-reduced-transparency
:
.transparent-element { opacity: 1; } @media (prefers-reduced-transparency:no-preference) { .transparent-element { opacity: 0.6; } }
The default should always be set first before any optimizations.
light-dark()
functionlight-dark()
is a CSS function that enables setting two colors for a property in which one of the colors will be used depending on the theme set by the user on their device.
I mentioned at the beginning of this article that most developers prefer a dark theme compared to a light theme. In the past, optimizing your app to fit the user’s theme preference was done globally using prefers-color-scheme
, but with the light-dark()
function, you can address each theme from a CSS property:
:root { color-scheme: light dark; } body { background: light-dark(#f4f4f4, #0b1121); }
Here if our testimonial example from before with the light-dark()
function implemented:
See the Pen
light-dark by Elijah Trillionz (@Elijah-Trillionz-the-sans)
on CodePen.
To use the light-dark()
function, color-scheme
must be set to light dark
. Being at the :root
would make it globally accessible.
N.B., make sure you’re using Firefox because, at the time of this writing, the
light-dark()
function is only supported in Firefox.
The name of this function indicates that the first color passed into the function is when the device is on a light theme, and the second is when it’s on a dark theme. For example, I could set my website’s header to be dark blue when on a dark theme and light blue when on a light theme, so I’d have this:
header { background: light-dark(lightblue, darkblue); }
light-dark()
makes it easier to handle each property without having to make a declaration over again. With this function, you can build support for light and dark themes at the same time rather than consecutively.
In this article, we first looked at the prefers-reduced-transparency
media feature, which is a useful feature for improving your website’s accessibility to users who prefer less transparency.
We also explored the light-dark()
function, which improves your website’s versatility by providing theme options for all users. It is a great feature that you can start exploring, but it isn’t recommended you start relying on it now, because it’s still new and has little browser support.
Thanks for reading!
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.