env()

Baseline 广泛可用 *

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2020 年 1 月⁩ 起,所有主流浏览器均已支持。

* 此特性的某些部分可能存在不同级别的支持。

env() CSS 函数可用于将用户代理定义的环境变量的值插入到 CSS 中。

语法

css
/* Without a fallback value */
env(safe-area-inset-top);
env(titlebar-area-width);
env(viewport-segment-right 0 0);

/* With a fallback value */
env(safe-area-inset-right, 1em);
env(titlebar-area-y, 40px);
env(viewport-segment-width 0 0, 40%);

参数

env( <environment-variable>, <fallback> ) 函数接受以下参数:

<environment-variable>

一个 <custom-ident>,指定要插入的环境变量的名称。如果提供的名称表示一个类数组环境变量,则名称后会跟一个或多个 <integer> 值,用于标识该名称引用的特定实例。区分大小写的环境变量名称可以是以下之一:

safe-area-inset-topsafe-area-inset-rightsafe-area-inset-bottomsafe-area-inset-left

从视口顶部、右侧、底部或左侧内边距边缘的安全距离,定义了可以将内容安全放置而不会被非矩形显示器的形状切断的区域。这四个值形成一个矩形,在此矩形内的所有内容都是可见的。如果视口是矩形,并且没有工具栏或动态键盘等功能占用视口空间,则这些值为 0;否则,它是一个大于 0px 值。

safe-area-max-inset-topsafe-area-max-inset-rightsafe-area-max-inset-bottomsafe-area-max-inset-left

当所有动态用户界面功能都收起时,其对应的动态 safe-area-inset-* 变量的静态最大值。虽然 safe-area-inset-* 的值会随着当前可见内容区域的变化而变化,但 safe-area-max-inset-* 的值是常量。

titlebar-area-xtitlebar-area-ytitlebar-area-widthtitlebar-area-height

可见的 titlebar-area-* 区域的尺寸。当使用清单字段 display_overridewindow-controls-overlay 值时,这些变量可用。这些变量的值可用于确保在桌面设备上安装的渐进式 Web 应用(PWA)中,内容不会与窗口控制按钮(即最小化、最大化和关闭)重叠。

keyboard-inset-topkeyboard-inset-rightkeyboard-inset-bottomkeyboard-inset-leftkeyboard-inset-widthkeyboard-inset-height

设备屏幕虚拟键盘相对于视口边缘的内边距和尺寸。在 VirtualKeyboard API 中定义。

viewport-segment-widthviewport-segment-heightviewport-segment-topviewport-segment-rightviewport-segment-bottomviewport-segment-left

特定视口分段的尺寸和偏移位置。viewport-segment-* 关键字后跟两个以空格分隔的 <integer> 值,表示分段的水平和垂直位置或索引。仅当视口由两个或多个分段组成时(如在可折叠或带铰链的设备上),才会定义 viewport-segment 关键字。

<fallback> 可选

一个备用值,如果第一个参数中引用的环境变量不存在,则会插入此值。第一个逗号之后的所有内容都被视为备用值。这可以是一个单一的值、另一个 env() 函数,或者一个用逗号分隔的值列表。

描述

env() 函数用于将全局作用域的、用户代理定义的环境变量的值插入到你的 CSS 中。env() 函数可以用作属性值,或代替属性值或描述符的任何部分(例如,在媒体查询规则中)。

该函数接受一个 <environment-variable> 作为其第一个参数。这是一个区分大小写的 <custom-ident>,与要替换的环境变量的名称相等,但如果需要,也可以包含额外的以空格分隔的值。例如,env(viewport-segment-width 0 0) 将返回具有多个视口分段的设备上顶部或左侧分段的宽度。

第二个参数(如果提供)是备用值,如果第一个参数中引用的环境变量不受支持或不存在,则使用该值。备用值可以是另一个环境变量,甚至可以带有自己的备用值。

备用值的语法类似于用于插入 CSS 自定义属性var() 函数的备用值语法,它允许使用多个逗号。第一个逗号和函数末尾之间的任何内容都被视为备用值。但是,如果 env() 函数在不包含逗号的属性值或描述符中使用,那么包含逗号的备用值将是无效的。

当浏览器首次读取和解释下载的 CSS 文本时,包含语法有效的 env() 函数的属性或描述符在解析时被假定为有效。它仅在计算时进行语法检查,即在每个 env() 函数被其浏览器提供的值(或备用值,如果作为第一个参数传递的环境变量不是一个可识别的环境变量名)替换之后。如果该值无效且未提供备用值,则包含 env() 函数的属性或描述符在计算值时无效

env() 替换无效,并且包含了无效的备用值或省略了备用值时,该声明不会被忽略。相反,会使用属性的初始值继承值。该属性被设置为一个新值,但可能不是预期的值。

用例

最初由 iOS 浏览器提供,用于允许开发者将其内容放置在视口的安全区域内,而不会被设备刘海或圆角遮挡,safe-area-inset-* 值可以用来帮助确保内容对观看者可见。此功能后来扩展到其最初目的之外,以支持诸如防止设备通知覆盖部分应用用户界面等用例。

env() 变量的另一个用例是桌面渐进式 Web 应用(PWA),这些应用使用窗口控件覆盖功能来利用整个应用程序窗口的表面区域。使用 titlebar-area-*,开发者可以将元素放置在标题栏原本所在的位置,并确保内容不会被窗口控制按钮遮挡

viewport-segment-* 变量名可用于设置你的容器,使其整齐地适应多视口分段设备(如铰链式或可折叠设备)的可用分段。viewport-segment-* 名称后面的整数表示环境变量所引用的多个分段中的哪一个。

名称后跟整数

当环境变量是类数组时,意味着该名称可能引用多个值,例如在具有多个视口分段的设备上,<environment-variable> 参数既包括变量的名称,也包括函数所引用的变量特定实例的索引。例如,对于 viewport-segment-* 变量,变量名称与两个整数一起传递给 env() 函数,这两个整数表示要返回其值的分段的索引。这些值都是 0 或更大的整数。第一个整数表示分段的水平索引,其中 0 是最左边的分段,第二个值表示分段的垂直索引,其中 0 表示最底部的分段。

Two device segment layouts; in a horizontal layout, 0 0 is the first segment and 1 0 is the second segment. In a vertical layout, the indices are 0 0 and 0 1

  • 在水平并排布局中,左侧分段由 0 0 表示,右侧分段由 1 0 表示。
  • 在垂直从上到下布局中,顶部片段由 0 0 表示,底部片段由 0 1 表示。
  • 在具有两个以上分段的设备中,数字可能会更大。例如,具有三个水平分段的设备可能用 1 0 表示中心分段,用 2 0 表示右侧分段。

例如,以下代码返回一个双分段可折叠设备上右侧分段的宽度,其中分段是水平排列的:

css
env(viewport-segment-width 1 0)

有关完整的可运行演示,请参阅 Viewport segment API 演示源代码)。另请查看使用 Viewport Segments API 以获取完整的演示说明。

正式语法

<env()> = 
env( <custom-ident> <integer [0,∞]>* , <declaration-value>? )

示例

使用 env() 确保按钮不被设备 UI 遮挡

在以下示例中,env() 用于确保固定的应用工具栏按钮不会被出现在屏幕底部的设备通知所遮挡。在桌面上,safe-area-inset-bottom0。然而,在屏幕底部显示通知的设备上,例如 iOS,它包含一个为通知显示留出空间的值。然后,这个值可以用于 padding-bottom 的值中,以创建一个在该设备上看起来自然的间隙。

HTML

我们有一个包含伪应用程序的 <main> 部分和一个包含两个 <button> 元素的 <footer>

html
<main>Main content of app here</main>
<footer>
  <button>Go here</button>
  <button>Or here</button>
</footer>

CSS

使用 CSS 弹性盒子布局,我们创建了一个高度仅为所需高度的页脚,而包含应用程序的主体部分则填满了视口的其余部分:

css
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  font: 1em system-ui;
}

main {
  flex: 1;
  background-color: #eeeeee;
  padding: 1em;
}

footer {
  flex: none;
  display: flex;
  gap: 1em;
  justify-content: space-evenly;
  background: black;
}

button {
  padding: 1em;
  background: white;
  color: black;
  margin: 0;
  width: 100%;
  border: none;
  font: 1em system-ui;
}

我们设置 position: sticky 将页脚固定在视口的底部。然后,我们使用 padding 简写为页脚添加内边距。我们将 safe-area-inset-bottom 环境变量的值添加到初始的 1em 底部内边距中。在对此变量具有正值的设备上,将显示一个更大的黑色区域,以确保页脚中的按钮永远不会被遮挡。

css
footer {
  position: sticky;
  bottom: 0;

  padding: 1em 1em calc(1em + env(safe-area-inset-bottom));
}

结果

使用备用值

此示例利用了 env() 的可选第二个参数,该参数在环境变量不可用时提供备用值。

HTML

我们包含一段文本:

html
<p>
  If the <code>env()</code> function is supported in your browser, this
  paragraph's text will have 50px of padding between it and the left border —
  but not the top, right and bottom. This is because the accompanying CSS is the
  equivalent of <code>padding: 0 0 0 50px</code>, because, unlike other CSS
  properties, user agent property names are case-sensitive.
</p>

CSS

我们设置了 300pxwidth 和一个 border。然后我们添加 padding,使用 env() 函数并为每边的内边距大小提供一个备用值。我们故意为左内边距设置了一个无效的值(请记住,环境变量名称是区分大小写的),以演示备用值的使用。

css
p {
  width: 300px;
  border: 2px solid red;
  padding: env(safe-area-inset-top, 50px) env(safe-area-inset-right, 50px)
    env(safe-area-inset-bottom, 50px) env(SAFE-AREA-INSET-LEFT, 50px);
}

结果

使用 env() 确保内容不被桌面 PWA 中的窗口控制按钮遮挡

在以下示例中,env() 确保在使用 Window Controls Overlay API 的桌面渐进式 Web 应用中显示的内容不会被操作系统的窗口控制按钮遮挡。titlebar-area-* 值定义了一个矩形区域,该区域通常是标题栏显示的地方。在不支持窗口控件覆盖功能的设备(例如移动设备)上,将使用备用值。

这是安装在桌面设备上的 PWA 通常的样子:

Illustration of what a PWA installed on desktop normally looks like, with window control buttons, a title bar, and web content below that

借助窗口控件覆盖功能,Web 内容覆盖了整个应用窗口表面区域,窗口控件和 PWA 按钮则作为覆盖层显示:

Illustration of what a PWA installed on desktop looks like with the Window Controls Overlay feature, with window control buttons, no title bar, and web content spanning the whole window

html
<header>Title of the app here</header>
<main>Main content of app here</main>
css
header {
  position: fixed;
  left: env(titlebar-area-x);
  top: env(titlebar-area-y);
  width: env(titlebar-area-width);
  height: env(titlebar-area-height);
}

main {
  margin-top: env(titlebar-area-height);
}

注意:使用 position:fixed 可以确保标题栏不会随其余内容滚动,而是与窗口控制按钮保持对齐,即使在支持弹性过度滚动(也称为橡皮筋效应)的设备/浏览器上也是如此。

视口分段

Viewport segment API 演示使用 Viewport Segments API 指南提供了使用 env() 函数和 viewport-segments-* 环境变量的演示和说明。

规范

规范
CSS Environment Variables Module Level 1
# env-function

浏览器兼容性

另见