Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.
Experimental: Check browser support before using this in production.
The env()
function replaces environment variables into CSS. To be more precise, it is a way to insert user-agent-defined variables into your stylesheet. It works similarly to the CSS var()
function and custom properties, but rather than being scoped to the element it’s declared on, the CSS env()
function is globally scoped to the document.
footer {
position: fixed;
bottom: env(safe-area-inset-bottom, 0px);
left: 0;
width: calc(100% - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
}
The env()
function is defined in the CSS Environment Variables Module Level 1 specification.
Syntax
The env()
function takes an environment variable name (e.g., safe-area-inset-top
) and an optional fallback value (e.g., 0px
).
env() = env(<custom-ident>, <declaration-value>?)
You can use it anywhere a length, color, or other value fits — think background-color
, width
, or padding
as in the example below:
padding-top: env(safe-area-inset-top, 10px); /* Adds notch padding or 10px */
Common variables include:
safe-area-inset-top
,safe-area-inset-right
,safe-area-inset-bottom
,safe-area-inset-left
: Offsets for device-safe areas (e.g., notches, status bars).
The
safe-area-inset-*
variables are the only universally supported environment variables defined in the CSS Environment Variables Module Level 1. They were introduced to tackle the iPhone X’s notch, and are now implemented across all major browsers (Chrome, Firefox, Safari, Edge) for iOS, Android, and other platforms. They offset content from device-specific obstructions, which makes them the primary use case forenv()
, as they solve a widespread problem without requiring custom setup.
env()
in CSS?
Initially introduced in iOS 11 (September 2017) for the iPhone X’s notch, the CSS env()
function is a part of CSS Environment Variables Module Level 1, which pulls dynamic values from the browser or OS. It debuted as constant()
before being standardized in the CSS Working Group’s Environment Variables Module draft by 2018. It helped address the chaos of notched displays, giving developers a native way to style around hardware quirks.
The env()
function accesses environment variables in CSS. It retrieves dynamic values like safe-area-inset-top
, -right
, -bottom
, -left
(in pixels), reflecting device or app settings. If a variable is undefined, a fallback (e.g., 0px
) kicks in. Unlike var()
, which uses developer-defined properties, env()
uses browser-provided data, updating as conditions change (e.g., rotation).
Basic usage
Let’s start with a classic scenario. You’re designing a full-screen hero section and want it to look polished on phones with notches or curved edges. You can choose to guess padding or risk clipped content, or bring in env()
to handle it effortlessly. Here’s how env()
helps:
.hero {
padding-top: env(safe-area-inset-top, 20px);
padding-bottom: env(safe-area-inset-bottom, 20px);
height: calc(100vh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
}
If you test this on an iPhone with a notch, you might discover that the safe-area-inset-top
is 44px
(covering the sensor area), so your hero’s padding-top
becomes 44px
, pushing content below the notch. On a notch-less Android, it falls back to 20px
. The height
calculation ensures the section fills the viewport without overflowing, subtracting insets dynamically.
Sticky navigation
You’re building a mobile app-like site with a navigation bar that sticks to the bottom. You want it to sit cleanly above the device’s home indicator (like iPhone’s swipe bar) without gaps or overlaps. env()
makes this a breeze, and here’s how you can make it your own:
.nav {
position: sticky;
bottom: env(safe-area-inset-bottom, 0px);
left: env(safe-area-inset-left, 0px);
right: env(safe-area-inset-right, 0px);
}
In the demo above, the safe-area-inset-bottom
(say, 34px
for iPhone’s home indicator) ensures the nav floats just above it, avoiding any area where it’d be untappable. On a flat-edged device, it falls back to 0px
, hugging the bottom perfectly. Also, the left
and right
insets keep it clear of curved corners.
Keyboard-aware inputs
You’re adding a chat input at the bottom of a messaging app. When the keyboard pops up on mobile, you don’t want it covering your input field. env()
can adjust for the keyboard’s safe area, making the UI feel thoughtful:
.chat-input {
position: fixed;
bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
left: env(safe-area-inset-left, 10px);
right: env(safe-area-inset-right, 10px);
}
On an iPhone, safe-area-inset-bottom
might jump to 34px
when the keyboard appears, pushing the input up so it’s not hidden. The calc()
adds a 10px
buffer for breathing room. On a keyboard-less desktop, it falls back to 10px
padding.
Non-standard environment variables
While the safe-area-inset-*
environment variables are the only ones defined in the spec and are also supported everywhere, Chrome introduced two unofficial variables titlebar-area-*
and keyboard-inset-*
.
titlebar-area-*
: It returns the safe area the title bar uses for the window’s button. It’s mainly used in progressive web apps that cover the full screen. Its suffix can be-x
,-y
,-width
or-height
.keyboard-inset-*
: It returns the safe area occupied by virtual keyboards in mobile. Its suffix can be-width
,-height
,-left
,-right
,-top
or-bottom
.
Besides those two, there are also two official environment variables defined in the spec but with no support in any browser: safe-area-max-inset-*
and viewport-segment-*
. You can check the demo below to see if your browser supports any of them:
Custom environment variables
For now, you can only define custom environment variables in your project using tools like PostCSS with the postcss-env-function
plugin, which enables non-standard variables beyond browser-defined ones. First, install the plugin:
npm install postcss postcss-env-function --save-dev
In your PostCSS config (e.g., postcss.config.js
), add the plugin and define custom variables:
module.exports = {
plugins: [ require("postcss-env-function") ({variables: {"custom-theme": "#3498db", "custom-spacing": "20px"}})];
}
Then, in your CSS, use env()
to access these variables:
.header {
background: env(custom-theme, #ccc);
padding: env(custom-spacing, 10px);
}
During the build, PostCSS replaces env(custom-theme)
with #3498db
and env(custom-spacing)
with 20px
, falling back to #ccc
and 10px
if undefined. This approach lets you manage project-specific variables centrally, though it requires a build step and is not native to browsers.
env()
variables
Future of As PWAs evolve, I envision env()
becoming a powerful tool for deeper integration with app settings, especially for branding and accessibility. Imagine a progressive web app where env()
could directly pull values from the manifest.json
file to style UI elements. For example, I suggest a future variable like env(manifest-background-color)
to access the background_color
(e.g., #ffffff
) from the manifest, allowing the screen’s background to match:
.splash {
background: env(manifest-background-color, #fff);
}
Or, picture yourself crafting a progressive web app with a custom theme color set in its manifest file (e.g., theme_color: #f1c40f
). In the future, having env()
pull that color directly from the manifest file would be a fun way to play with branding:
.header {
background: env(theme-color, #f1c40f);
padding: 15px;
color: white;
text-align: center;
}
With env(theme-color)
, your header inherits that exact shade in the manifest.json
file without hardcoding it. If the app updates its theme, the CSS updates too.
env()
vs. other techniques
The vw
/vh
, media queries and JavaScript tackle responsiveness but do nothing much regarding device context. Unlike env()
, where it is its specialty. Here’s how they compare:
env() | Proportional to the viewport. | Media Queries | JavaScript | |
---|---|---|---|---|
Purpose | Device/OS variable access. | Viewport scaling. | Breakpoint-based styles. | Programmatic styling. |
Syntax | env(safe-area-inset-top, 0px) | width: 100vw | @media (max-width: 600px) | element.style.padding = '20px' |
Behavior | Dynamic, context-specific offsets. | Proportional to viewport. | Discrete style changes. | Any logic, any property. |
Precision | Exact for safe areas, custom UI. | Broad viewport sizing. | Stepped, range-based. | Ultimate control, complex setup. |
Use Case | Notches, app themes, font scales. | Fluid layouts. | Screen-size layouts. | Data-driven dynamics. |
Example | padding: env(safe-area-inset-left) | height: 100vh | @media (min-width: 600px) | window.innerWidth checks |
Demo
Here, safe-area-inset-bottom
with env()
helps to keep the footer above the home bar (e.g., 34px
on iPhone), and width
shrinks to avoid side insets.
Specification
The env()
function is defined in the CSS Environment Variables Module Level 1 specification, which is currently in Editor’s Draft.
Browser support
You can always use the built-in fallback inside env()
second argument, and also define the variable as usual before using env()
:
padding: 10px;
padding: env(safe-area-inset-top, 10px);