# data[].attributes.body
CSS Tricks: Absolute position

MDN: transition property

MDN: :checked pseudo-class

MDN: ::before pseudo-element

# data[].attributes.body
In this tutorial Ananya shows how to create a dark mode toggle using:

CSS Variables to control colours globally

Data attributes and attribute selectors to override the CSS

Element.setAttribute() to toggle the data attributes

Window.localStorage to save the user's dark mode preference locally

# data[].attributes.attachment_link.description
Dark Mode: Tutorial walk-through. GitHub Gist: instantly share code, notes, and snippets.

# data[].attributes.body
Create A Dark/Light Mode Switch with CSS Variables

by Ananya Neogi

# data[].attributes.attachment_link.readable_text
Giving your users a way to customise the interface to their preference is a huge win for user experience. Here we are going to provide the user with a simple switch to toggle between dark mode and light mode and we will also try to remember their preference for future visits.

If you don't have a website of your own to which you wish to add this functionality, use this demo website to follow along.

We will be adding CSS custom properties also known as CSS variables, which we can reference and modify throughout the document. If you wish to read more about custom properties you can read on MDN.
Here's the tldr; version -

Custom properties (sometimes referred to as CSS variables or cascading variables) are entities defined by CSS authors that contain specific values to be reused throughout a document. They are set using custom property notation (e.g., --main-color: black;) and are accessed using the var() function (e.g., color: var(--main-color);)

First, we'll add our light or default mode css variables to the :root pseudo class. It matches with the root element in your document tree, generally the <html> tag. We will use :root because we want to avail the variables globally.

Second, we'll add our dark mode css variables.

What is [data-theme="dark"]? This means we are referencing a data attribute called data-theme with a value "dark". We will find the use of it in a while.

Then, we can reference these variables in our stylesheets like so-

This is essentially just a checkbox, however we will add some additional markup to style like a toggle switch. I referenced the styles from this codepen.

The final part is to add the bit of JavaScript to tie it all together.
We have 3 tasks in hand-

Add event handlers to handle accordingly the check/uncheck event of toggle-switch

Store the user preference for future visits

Check for saved user preference, if any, on load of the website

Adding the event handlers

Remember, the data-theme attribute we referenced in CSS above, this is where it's getting added to our root element.

Store the user preference for future visits

We will use browser's localStorage to store the user preference.
Let's modify our switchTheme function -

Check for saved user preference, if any, on load of the website

We will check if the theme preference is saved, if yes then we will, accordingly-
- set our data-theme attribute
- check/uncheck our toggle-switch checkbox

That's it! Check out the full demo below.

I recently added this to my website, so check that out as well, maybe!

Pro-Tip: How to decide on the color scheme?
My suggestion is to stay in the same spectrum of your primary or brand color and generate a palette out of it. Use the darkest shade from the palette as the background color and the lighter shades as font colors when in dark mode. I used this color shades generator for generating my color palette.

Even if you don't end up using the exact colors generated, it is still a good place to start. Even I ended up fine tuning the colors I ultimately used.

# data[].attributes.attachment_link.title
Create A Dark/Light Mode Switch with CSS Variables

# data[].attributes.attachment_link.description
Giving your users a way to customise the interface to their preference is a huge win for user experience. Here we are going to provide the user with a simple switch to toggle between dark mode and light mode and we will also try to remember their preference for future visits.

# data[].attributes.body
In this tutorial Lea shows how to implement a dark mode theme that is activated by the user's system dark mode preference:

CSS Variables to control colours globally

hsl() to control lightness

A prefers-color-scheme media query to detect the user's dark mode system preference

# data[].attributes.attachment_link.description
Dark Mode: Tutorial walk-through. GitHub Gist: instantly share code, notes, and snippets.

# data[].attributes.body
Dark mode in 5 minutes, with inverted lightness variables
by Lea Verou

# data[].attributes.attachment_link.readable_text
By now, you probably know that you can use custom properties for individual color components, to avoid repeating the same color coordinates multiple times throughout your theme. You may even know that you can use the same variable for multiple components, e.g. HSL hue and lightness:

:root { --primary-hs: 250 30%; } h1 { color: hsl(var(--primary-hs) 30%); } article { background: hsl(var(--primary-hs) 90%); } article h2 { background: hsl(var(--primary-hs) 40%); color: white; }

Here is a very simple page designed with this technque:

Unlike preprocessor variables, you could even locally override the variable, to have blocks with a different accent color:

:root { --primary-hs: 250 30%; --secondary-hs: 190 40%; } article { background: hsl(var(--primary-hs) 90%); } article.alt { --primary-hs: var(--secondary-hs); }

This is all fine and dandy, until dark mode comes into play. The idea of using custom properties to make it easier to adapt a theme to dark mode is not new. However, in every article I have seen, the strategy suggested is to create a bunch of custom properties, one for each color, and override them in a media query.

This is a fine approach, and you'll likely want to do that for at least part of your colors eventually. However, even in the most disciplined of designs, not every color is a CSS variable. You often have colors declared inline, especially grays (e.g. the footer color in our example). This means that adding a dark mode is taxing enough that you may put it off for later, especially on side projects.

The trick I'm going to show you will make anyone who knows enough about color cringe (sorry Chris!) but it does help you create a dark mode that works in minutes. It won't be great, and you should eventually tweak it to create a proper dark mode (also dark mode is not just about swapping colors) but it's better than nothing and can serve as a base.

The basic idea is to use custom properties for the lightness of colors instead of the entire color. Then, in dark mode, you override these variables with 100% - lightness. This generally produces light colors for dark colors, medium colors for medium colors, and dark colors for light colors, and still allows you to define colors inline, instead of forcing you to use a variable for every single color. This is what the code would look like for our example:

root { --primary-hs: 250 30%; --secondary-hs: 190 40%; --l-0: 0%; --l-30: 30%; --l-40: 40%; --l-50: 50%; --l-90: 90%; --l-100: 100%; } @media (prefers-color-scheme: dark) { :root { --l-0: 100%; --l-30: 70%; --l-40: 60%; --l-90: 10%; --l-100: 0%; } } body { background: hsl(0 0% var(--l-100)); color: hsl(0 0% var(--l-0)); } h1 { color: hsl(var(--primary-hs) var(--l-30)); } article { background: hsl(var(--primary-hs) var(--l-90)); } article h2 { background: hsl(var(--primary-hs) 40%); color: white; } footer { color: hsl(0 0% var(--l-40)); }

The result looks like this in light & dark mode:

Note that here we indiscriminately replaced all lightnesses with lightness variables. In reality, we don't need to be quite as sweeping. For example, the article titles would actually look better and would have better contrast if we just kept them the same:

These are decisions that are easy to make while you go through your CSS replacing lightness percentages with variables and previewing the result.

The problem with HSL

But why were the article headers easier to read with their original colors than with inverted lightness? The root cause is that HSL lightness does not actually correspond to what humans perceive as lightness, and the same lightness difference can produce vastly different perceptual differences.

That is the big problem with this approach: it assumes that HSL lightness actually means something, but as we've discussed before, it does not. Yellow and blue have the same HSL lightness (50%) for crying out loud! Also, you will notice that your dark colors have smaller differences between them than your light colors, because HSL is not perceptually uniform.

Does that mean the technique is not useful for anything other than a placeholder while we develop our real dark mode, if that?

Well, things are not quite as grim.

Soon enough, we will get LCH colors in the browser. The first browser implementation just recently shipped in Safari and there is activity in that space among the other browser vendors too.

LCH is a much better color space for this technique, because its lightness actually means something, not just across different lightnesses of the same color, but across different hues and chromas.

This next example needs Safari TP 120+ . Compare these two gradients, the top one showing various HSL colors all with lightness 50%, and the bottom various LCH colors, all with lightness 50%. You can even adjust the slider and try different lightnesses:

Here is a screenshot for those of you who don't have access to Safari TP 120+:

Notice that in HSL, some colors (like yellow and cyan) are much lighter than others. In LCH, all colors at the same lightness are, well, the same lightness.

Keep in mind that LCH chroma doesn't really correspond to HSL lightness, so even though we've set it to the same number, it doesn't correspond to the same thing.

So, how would this technique work with LCH colors? Let's try it out!

I used this tool to convert the existing HSL colors to LCH, then tweaked the values manually a bit as the initially converted colors didn't look nice across all LCH lightnesses (note that HSL colors with the same hue and saturation may have different hue and chromas in LCH. The opposite would defeat the point!). This is what this technique looks like with LCH colors instead (you will need Safari TP 120 or later to view this):

And here is a screenshot:

Not only does dark mode look a lot better, but even in light mode, our two alternate colors actually look more uniform since they have the same LCH lightness.

Here is a comparison of the two dark modes:

Here you can see an animated comparison of them over each other:

Note that in reality, until LCH colors are reliably supported everywhere you'd need to provide a fallback via @supports, but for brevity, I did not include one in this demo.

Automating generation of lightness variables

If you are using a preprocessor that supports loops, such as Sass, you can automate the generation of these variables, and make them even more granular, e.g. every 5%:

:root { @for $i from 0 through 20 { --l-#{$i * 5}: #{$i * 5}%; } } @media (prefers-color-scheme: dark) { :root { @for $i from 0 through 20 { --l-#{$i * 5}: #{100 - $i * 5}%; } } }

Can we make lightness variables more DRY?

Some of you may have disliked the repetition of values: we need to declare e.g. --l-40 as 40%, then set it to 60% in dark mode. Can't we derive it somehow, by subtracting the value we already have from 100%?

Those with experience in programming may try something like this:

--l-40: calc(100% - var(--l-40));

However, this will not work. CSS is not an imperative language. It does not have steps of calculation, where variables have different values before and after each step. There is no such concept of time, all declarations that are currently applied, need to be true at once. It's more similar to the reactive evaluation of spreadsheet formulas than to computation in JS and other popular programming languages (there are general purpose reactive programming languages, but they are less well known). Therefore, declarations like the one above are considered cycles: since --l-40 cannot refer to itself, this is an error, and --l-40 would be set to its initial value as an error recovery mechanism (since CSS cannot throw errors).

So, is there a way to avoid declaring lightness variables twice, once for light mode and once for dark mode?

There is, but I wouldn't recommend it. It makes the code more convoluted to read and comprehend, for little benefit. But for the sake of intellectual amusement, I'm going to describe it here.

Instead of setting --l-40 to 40%, we are going to set it in terms of its difference from 50%, i.e. -10%. Then, calc(50% + var(--l-40)) gives us 40% and calc(50% - var(--l-40)) gives us 60%, the two values we need. We can therefore declare one variable that is -1 in dark mode and 1 in light mode, and just multiply with that.

Here is a subset of what our code would be like with this:

:root { --dm: 1; /* Example declaration: */ --l-40: -10%; } @media (prefers-color-scheme: dark) { :root { --dm: -1; } } /* Example usage: */ footer { color: hsl(0 0% calc(50% + var(--dm) * var(--l-40)); /* Ewww! */ }

And hopefully now you can see why I wouldn't recommend this: it makes usage much more complicated, to DRY up a few declarations that would only be specified once. It's this kind of obsessive adherence to DRY that programmers eventually realize is counterproductive.
Liked this article? Sign up for my Smashing Workshop on Dynamic CSS for more content like this!

# data[].attributes.attachment_link.title
Dark mode in 5 minutes, with inverted lightness variables

# data[].attributes.attachment_link.description
By now, you probably know that you can use custom properties for individual color components, to avoid repeating the same color coordinates multiple times throughout your theme. You may even know that you can use the same variable for multiple components, e.g.

# data[].attributes.body
In this activity we will combine these two tutorials (with a dash of MediaQueryList logic) to create a dark mode toggle that defaults to the user's system Dark Mode preference unless the user chooses to override this setting on the page using the Toggle.

# data[].attributes.attachment_link.readable_text
In this activity we will combine two tutorials (with a dash of MediaQueryList logic) to create a dark mode toggle that defaults to the user's system Dark Mode preference unless the user chooses to override this setting on the page using the Toggle.

Technologies used in this activity:

CSS Variables to control colours globally

Data attributes and attribute selectors to override the CSS

Element.setAttribute() to toggle the data attributes

Window.localStorage to save the user's dark mode preference locally

A prefers-color-scheme media query to detect the user's dark mode system preference

window.matchMedia() to detect the System Dark Mode preference

Terminology

System Dark Mode Preference : The user's system level Dark Mode setting. This usually set in the OS's (ex. Windows, Mac OS, Linux) System Preferences panel.

Dark Mode Toggle : The page level dark mode preference for the web page. Normally this is a separate preference than the system level. This activity will couple the two to a single Ultimate Toggle (queue applause).

Materials

Reference

Sample Code

Starter pen
Note: this is the finished code from Tutorial 1

Spoilers: Finished pen
Note: this code could be dried out.

Instructions

When you've completed the above steps:

Your Toggle should load with the user's current System Dark Mode preference, unless, the user overrides this by using the page Toggle.

Optional Step 4: If the user changes their System Dark Mode preference while the page is loaded, it should switch the page theme to match. BUT, this does not override the page's toggle preference unless the user clicks the toggle (this can be changed, if desired).

# data[].attributes.attachment_link.description
In this activity we will combine two tutorials (with a dash of MediaQueryList logic) to create a dark mode toggle that defaults to the user's system Dark Mode preference unless the user chooses to override this setting on the page using the Toggle.

# data[].attributes.body
Note: this is the finished code from Tutorial 1.

# data[].attributes.body
Note: this code could be dried out.

# data[].attributes.attachment_link.readable_text
Custom properties (sometimes referred to as CSS variables or cascading variables) are entities defined by CSS authors that contain specific values to be reused throughout a document. They are set using custom property notation (e.g., --main-color: black;) and are accessed using the function (e.g., color: var(--main-color);).

Complex websites have very large amounts of CSS, often with a lot of repeated values. For example, the same color might be used in hundreds of different places, requiring global search and replace if that color needs to change. Custom properties allow a value to be stored in one place, then referenced in multiple other places. An additional benefit is semantic identifiers. For example, --main-text-color is easier to understand than #00ff00, especially if this same color is also used in other contexts.

Custom properties are subject to the cascade and inherit their value from their parent.

Declaring a custom property is done using a custom property name that begins with a double hyphen (--), and a property value that can be any valid CSS value. Like any other property, this is written inside a ruleset, like so:

Note that the selector given to the ruleset defines the scope that the custom property can be used in. A common best practice is to define custom properties on the pseudo-class, so that it can be applied globally across your HTML document:

However, this doesn't always have to be the case: you maybe have a good reason for limiting the scope of your custom properties.

Note: Custom property names are case sensitive - --my-color will be treated as a separate custom property to --My-color.

As mentioned earlier, you use the custom property value by specifying your custom property name inside the function, in place of a regular property value:

Let's start with this simple CSS that applies the same color to elements of different classes:

We'll apply it to this HTML:

... which leads us to this:

Notice the repetition in the CSS. The background color is set to brown in several places. For some CSS declarations, it is possible to declare this higher in the cascade and let CSS inheritance solve this problem naturally. For non-trivial projects, this is not always possible. By declaring a custom property on the pseudo-class and using it where needed throughout the document, a CSS author can reduce the need for repetition:

This leads to the same result as the previous example, yet allows for one canonical declaration of the desired property value; very useful if you want to change the value across the entire page later.

Custom properties do inherit. This means that if no value is set for a custom property on a given element, the value of its parent is used. Take this HTML:

... with the following CSS:

In this case, the results of var(--test) are:

For the class="two" element: 10px

For the class="three" element: 2em

For the class="four" element: 10px (inherited from its parent)

For the class="one" element: invalid value, which is the default value of any custom property

Keep in mind that these are custom properties, not actual variables like you might find in other programming languages. The value is computed where it is needed, not stored for use in other rules. For instance, you cannot set a property for an element and expect to retrieve it in a sibling's descendant's rule. The property is only set for the matching selector and its descendants, like any normal CSS.

Using the function, you can define multiple fallback values when the given variable is not yet defined; this can be useful when working with Custom Elements and Shadow DOM.

Note: Fallback values aren't used to fix the browser compatibility. If the browser doesn't support CSS custom Properties, the fallback value won't help. It's just a backup for the browser which supports CSS Custom Properties to choose a different value if the given variable isn't defined or has an invalid value.

The first argument to the function is the name of the custom property to be substituted. The second argument to the function, if provided, is a fallback value, which is used as the substitution value when the referenced custom property is invalid. The function only accepts two parameters, assigning everything following the first comma as the second parameter. If that second parameter is invalid, such as if a comma-separated list is provided, the fallback will fail. For example:

Including a custom property as a fallback, as seen in the second example above, is the correct way to provide more than one fallback. The technique has been seen to cause performance issues as it takes more time to parse through the variables.

Note: The syntax of the fallback, like that of custom properties, allows commas. For example, var(--foo, red, blue) defines a fallback of red, blue - anything between the first comma and the end of the function is considered a fallback value.

The classical CSS concept of validity, tied to each property, is not very useful in regard to custom properties. When the values of the custom properties are parsed, the browser doesn't know where they will be used, so must, therefore, consider nearly all values as valid.

Unfortunately, these valid values can be used, via the var() functional notation, in a context where they might not make sense. Properties and custom variables can lead to invalid CSS statements, leading to the new concept of valid at computed time.

When the browser encounters an invalid var() substitution, the initial or inherited value of the property is used.

Consider the code snippet below.

This paragraph is initial black.

As expected, the browser substitutes the value of --text-color in place of var(--text-color), but 16px is not a valid property value for . After substitution, the property doesn't make any sense. The browser handles this situation in two steps:

1. Check if the property color is inheritable. Yes, but <p> doesn't have any parent with color property. So move on to the next step.

2. Set the value to its default initial value, i.e., black.

The paragraph color will not be blue because invalid substitution is replaced by the initial value, not by the fallback. If you had written color: 16px without any variable substitutes, then it was a syntax error. The previous declaration will then be used.

Note: While a syntax error in a CSS property / value pair will lead to the line being ignored, using a cascaded value, invalid substitution -- using a custom property value that is invalid -- is not ignored, leading to the value to be inherited.

To use the values of custom properties in JavaScript, it is just like standard properties.

BCD tables only load in the browser

Note: The custom property prefix was var- in the earlier spec, but later changed to --. Firefox 31 and above follow the new spec. ( bug 985838)

# data[].attributes.attachment_link.title
Using CSS custom properties (variables) - CSS: Cascading Style Sheets | MDN

# data[].attributes.attachment_link.description
Custom properties (sometimes referred to as CSS variables or cascading variables) are entities defined by CSS authors that contain specific values to be reused throughout a document. They are set using custom property notation (e.g., --main-color: black;) and are accessed using the var() function (e.g., color: var(--main-color);).

# data[].attributes.headline
Article: Learn CSS Variables in 5 minutes

# data[].attributes.subject
Article: Learn CSS Variables in 5 minutes

# data[].attributes.attachment_link.title
Learn CSS Variables in 5 minutes - A tutorial for beginners

# data[].attributes.attachment_link.description
CSS Custom Properties (also known as Variables) is a big win for front-end developers. It brings the power of variables to CSS, which results in less repetition, better readability and more flexibility. Plus, unlike variables from CSS preprocessors, CSS Variables are actually a part of the DOM, which has a

# data[].attributes.attachment_link.readable_text
The CSS attribute selector matches elements based on the presence or value of a given attribute.

Represents elements with an attribute name of attr.

Represents elements with an attribute name of attr whose value is exactly value.

Represents elements with an attribute name of attr whose value is a whitespace-separated list of words, one of which is exactly value.

Represents elements with an attribute name of attr whose value can be exactly value or can begin with value immediately followed by a hyphen, - (U+002D). It is often used for language subcode matches.

Represents elements with an attribute name of attr whose value is prefixed (preceded) by value.

Represents elements with an attribute name of attr whose value is suffixed (followed) by value.

Represents elements with an attribute name of attr whose value contains at least one occurrence of value within the string.

Adding an i (or I) before the closing bracket causes the value to be compared case-insensitively (for characters within the ASCII range).

Adding an s (or S) before the closing bracket causes the value to be compared case-sensitively (for characters within the ASCII range).

The HTML specification requires the attribute to be matched case-insensitively due to it primarily being used in the element, trying to use attribute selectors to with the attribute of an ordered list doesn't work without the case-sensitive modifier.

CSS

HTML

Result

BCD tables only load in the browser

# data[].attributes.attachment_link.title
Attribute selectors - CSS: Cascading Style Sheets | MDN

# data[].attributes.attachment_link.description
The CSS attribute selector matches elements based on the presence or value of a given attribute. Represents elements with an attribute name of attr. Represents elements with an attribute name of attr whose value is exactly value. Represents elements with an attribute name of attr whose value is a whitespace-separated list of words, one of which is exactly value.

# data[].attributes.attachment_link.readable_text
Sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value.

To get the current value of an attribute, use getAttribute(); to remove an attribute, call removeAttribute().

A specifying the name of the attribute whose value is to be set. The attribute name is automatically converted to all lower-case when setAttribute() is called on an HTML element in an HTML document.

A containing the value to assign to the attribute. Any non-string value specified is converted automatically into a string.

Boolean attributes are considered to be true if they're present on the element at all. You should set value to the empty string ("") or the attribute's name, with no leading or trailing whitespace. See the example below for a practical demonstration.

Since the specified value gets converted into a string, specifying null doesn't necessarily do what you expect. Instead of removing the attribute or setting its value to be , it instead sets the attribute's value to the string"null". If you wish to remove an attribute, callremoveAttribute().

InvalidCharacterError

The specified attribute name contains one or more characters which are not valid in attribute names.

In the following example, setAttribute() is used to set attributes on a .

This demonstrates two things:

The first call to setAttribute() above shows changing thename attribute's value to "helloButton". You can see this using your browser's page inspector (Chrome,Edge,Firefox, Safari).

To set the value of a Boolean attribute, such as disabled, you can specify any value. An empty string or the name of the attribute are recommended values. All that matters is that if the attribute is present at all,regardless of its actual value, its value is considered to be true. The absence of the attribute means its value isfalse. By setting the value of thedisabled attribute to the empty string (""), we are settingdisabled to true, which results in the button being disabled.

DOM methods dealing with element's attributes:

BCD tables only load in the browser

Using setAttribute() to modify certain attributes, most notably value in XUL, works inconsistently, as the attribute specifies the default value. To access or modify the current values, you should use the properties. For example, use Element.value instead of Element.setAttribute().

# data[].attributes.attachment_link.description
Sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value. To get the current value of an attribute, use getAttribute() ; to remove an attribute, call removeAttribute() .

# data[].attributes.attachment_link.readable_text
The localStorage read-only property of the interface allows you to access a object for the 's origin; the stored data is saved across browser sessions.

localStorage is similar to sessionStorage, except that while localStorage data has no expiration time, sessionStorage data gets cleared when the page session ends - that is, when the page is closed. ( localStorage data for a document loaded in a "private browsing" or "incognito" session is cleared when the last "private" tab is closed.)

A object which can be used to access the current origin's local storage space.

SecurityError

The request violates a policy decision, or the origin is not a valid scheme/host/port tuple (this can happen if the origin uses the file: or data: schemes, for example). For example, the user may have their browser configured to deny permission to persist data for the specified origin.

The keys and the values stored with localStorage are always in the UTF-16 format, which uses two bytes per character. As with objects, integer keys are automatically converted to strings.

localStorage data is specific to the protocol of the document. In particular, for a site loaded over HTTP (e.g., http://example.com), localStorage returns a different object than localStorage for the corresponding site loaded over HTTPS (e.g., https://example.com).

For documents loaded from file: URLs (that is, files opened in the browser directly from the user's local filesystem, rather than being served from a web server) the requirements for localStorage behavior are undefined and may vary among different browsers.

In all current browsers, localStorage seems to return a different object for each file: URL. In other words, each file: URL seems to have its own unique local-storage area. But there are no guarantees about that behavior, so you shouldn't rely on it because, as mentioned above, the requirements for file: URLs remains undefined. So it's possible that browsers may change their file: URL handling for localStorage at any time. In fact some browsers have changed their handling for it over time.

The following snippet accesses the current domain's local object and adds a data item to it using Storage.setItem().

The syntax for reading the localStorage item is as follows:

The syntax for removing the localStorage item is as follows:

The syntax for removing all the localStorage items is as follows:

BCD tables only load in the browser

# data[].attributes.attachment_link.description
The localStorage read-only property of the interface allows you to access a object for the 's origin; the stored data is saved across browser sessions. localStorage is similar to sessionStorage , except that while localStorage data has no expiration time, sessionStorage data gets cleared when the page session ends - that is, when the page is closed.

# data[].attributes.attachment_link.title
dotCSS 2018 - David DeSandro - Read color hex codes

# data[].attributes.attachment_link.readable_text
The prefers-color-scheme CSS media feature is used to detect if the user has requested a light or dark color theme.

The user might indicate this preference through an operating system setting (e.g. light or dark mode) or a user agent setting.

Indicates that user has notified that they prefer an interface that has a light theme, or has not expressed an active preference.

Indicates that user has notified that they prefer an interface that has a dark theme.

The elements below have an initial color theme. They can be further themed according to the user's color scheme preference.

Day (initial) Day (changes in light scheme) Day (changes in dark scheme) Night (initial) Night (changes in light scheme) Night (changes in dark scheme)

BCD tables only load in the browser

# data[].attributes.attachment_link.title
prefers-color-scheme - CSS: Cascading Style Sheets | MDN

# data[].attributes.attachment_link.description
The prefers-color-scheme CSS media feature is used to detect if the user has requested a light or dark color theme. The user might indicate this preference through an operating system setting (e.g. light or dark mode) or a user agent setting.

# data[].attributes.attachment_link.readable_text
The interface's matchMedia() method returns a new MediaQueryList object that can then be used to determine if the matches the media query string, as well as to monitor the document to detect when it matches (or stops matching) that media query.

Syntax

mqList = window.matchMedia(mediaQueryString)

Parameters

mediaQueryString

A string specifying the media query to parse into a MediaQueryList.

Return value

A new MediaQueryList object for the media query. Use this object's properties and events to detect matches and to monitor for changes to those matches over time.

Usage notes

You can use the returned media query to perform both instantanteous and event-driven checks to see if the document matches the media query.

To perform a one-time, instantaneous check to see if the document matches the media query, look at the value of the property, which will be true if the document meets the media query's requirements.

If you need to be kept aware of whether or not the document matches the media query at all times, you can instead watch for the event to be delivered to the object. There's a good example of this in the article on Window.devicePixelRatio.

Examples

This example runs the media query (max-width: 600px) and displays the value of the resulting MediaQueryList's matches property in a ; as a result, the output will say "true" if the viewport is less than or equal to 600 pixels wide, and will say "false" if the window is wider than that.

JavaScript

let mql = window.matchMedia('(max-width: 600px)');

document.querySelector(".mq-value").innerText = mql.matches;

The JavaScript code simply passes the media query to match into matchMedia() to compile it, then sets the <span>'s to the value of the results' property, so that it indicates whether or not the document matches the media query at the moment the page was loaded.

HTML

<span class="mq-value"></span>

A simple <span> to receive the output.

Result

See Testing media queries programmatically for additional code examples.

Specifications

Browser compatibility

See also

# data[].attributes.attachment_link.description
The Window interface's matchMedia() method returns a new MediaQueryList object that can then be used to determine if the document matches the media query string, as well as to monitor the document to detect when it matches (or stops matching) that media query.

# data[].attributes.headline
Article: Detecting System Dark Mode Preference

# data[].attributes.subject
Article: Detecting System Dark Mode Preference

# data[].attributes.headline
Adding event listeners to MediaQueryList

# data[].attributes.subject
Adding event listeners to MediaQueryList

# data[].attributes.attachment_link.readable_text
The onchange property of theMediaQueryList interface is an event handler property representing a function that is invoked when the event fires, i.e when the status of media query support changes. The event object is aMediaQueryListEvent instance, which is recognized as a MediaListQuery instance in older browsers, for backwards compatibility purposes.

BCD tables only load in the browser

# data[].attributes.attachment_link.title
MediaQueryList.onchange - Web APIs | MDN

# data[].attributes.attachment_link.description
The onchange property of the MediaQueryList interface is an event handler property representing a function that is invoked when the change event fires, i.e when the status of media query support changes. The event object is a MediaQueryListEvent instance, which is recognized as a MediaListQuery instance in older browsers, for backwards compatibility purposes.