Everything about CSS environment variables

When the iPhone X came out with the infamous notch, you may have heard of the new safe-area-inset values, which allowed browsers to detect the area of the screen that was covered by the notch and move content around appropriately.

Recently, these values have been formalised as part of a new specification for CSS Environment Variables. This specification is still in the stage of Editor’s Draft which means that, although some browsers may begin implementation, it is not yet an official part of the specification. However, it does have good support with browsers that need it, e.g. iOS Safari on the iPhone X, and can be used in a progressive way.

We already have CSS variables, don’t we? #

CSS Custom Properties, better known as CSS Variables, officially became a W3C recommendation in 2015, making it safe for web page authors to use (with appropriate fallbacks for non-supporting browsers).

For the first time in CSS, these variables allowed us to create references to frequently-used values and use those references around our stylesheet instead. The references, or “variables”, were scoped to an element and created in a similar way to how we define normal property-value declarations.

button {
--padding: 10px;

These variables could then be accessed using the var() notation.

button {
padding-top: var(--padding);

Although these type of variables solved a lot of problems, they also had a few limitations.

Because CSS variables are scoped to an element, they are only accessible to that specific element, not globally. In order to make variables accessible to our whole stylesheet, we would have to apply the variables to the :root element. Since these variables are cascading, they will be available to all child elements.

:root {
--colour-primary: #bae;

button {
background-color: var(--colour-primary);

h1 {
color: var(--colour-primary);

Another side-effect of the variables being scoped to an element is that they can’t be used outside CSS declarations. CSS variables can’t be used in other places such as with @media rules.

:root {
--breakpoint: 600px;

@media (min-width: var(--breakpoint)) {
/* Doesn't work :( */

Will not work

Finally, because CSS variables are cascading, the browser needs to be prepared for their value to change at any moment. This means that, even if they aren’t being changed, the browser will not be able to perform any optimisations to store the value in a permanent way.

Enter environment variables #

CSS environment variables were created as a solution to the constraints of the custom properties, also called “cascading variables”. They have three key differences to the cascading variables:

  1. They are defined once, globally, and can never be changed
  2. They can be used as any value to any property or @ rule, e.g. media queries
  3. They can be defined by either the user agent or the stylesheet author

How environment variables are created #

CSS environment variables can either be created by the user-agent, or by the author of the stylesheet.

User-agent environment variables #

User agents, e.g. browsers, will be able to set their own environment variables. Currently, the only ones that exist are the safe area inset variables.

The safe area insets are four length variables, which create a rectangle on the screen, outlining the area that is safe for content to be placed within.

Variable Name Value type
safe-area-inset-top length
safe-area-inset-right length
safe-area-inset-bottom length
safe-area-inset-left length

Author environment variables #

Although the specification says that stylesheet authors, i.e. web developers, will be able to create environment variables, how this will be done has not been decided on yet.

Using environment variables (today) #

A CSS environment variable is accessed using the env() notation. This notation accepts two values - the variable name, and a fallback value for if the variable wasn’t found.


For example, we can use the safe area inset variables to apply padding to the body element and ensure all content is within a safe area.

body {
padding-top: env(safe-area-inset-top, 12px);
padding-right: env(safe-area-inset-right, 12px);
padding-bottom: env(safe-area-inset-bottom, 12px);
padding-left: env(safe-area-inset-left, 12px);

Support and progressive enhancement #

As I mentioned, the specification for CSS environment variables is still in Editor’s Draft, which means things will probably change. Despite this, the support for this feature is already at 70% and therefore can be used.

Data on support for the css-env-function feature across the major browsers from caniuse.com

A good way to use this feature today is to rely on the cascade and use appropriate fallbacks.

body {
/* No variables */
padding-top: 12px;

/* iOS Safari 11.2, Safari 11 */
padding-top: constant(safe-area-inset-top, 12px);

/* iOS Safari 11.4+, Safari 11.1+, Chrome 69+, Opera 56+ */
padding-top: env(safe-area-inset-top, 12px);

Keep in touch KeepinTouch

Subscribe to my Newsletter 📥

Receive quality articles and other exclusive content from myself. You’ll never receive any spam and can always unsubscribe easily.

Elsewhere 🌐