使用环境变量

CSS 环境变量模块引入了 CSS 中环境变量的概念,并定义了 env() 函数来启用环境变量。在本指南中,我们将了解什么是环境变量浏览器定义的环境变量,以及如何使用环境变量env() 函数

什么是环境变量?

CSS 环境变量是全局变量;其作用域是整个文档。它们由用户代理定义。环境变量是浏览器或操作系统提供的特殊值,可帮助你的样式适应用户的设备或上下文。它们通过 env() 函数访问。

环境变量的工作方式类似于自定义属性var() 函数,但它们是全局定义和作用域的。这意味着它们的作用域始终是整个文档,而不像自定义属性那样作用于元素。此外,环境变量是只读的,而自定义属性是可变的。

与自定义属性类似,环境变量是区分大小写的。与自定义属性不同,自定义属性不能在声明之外使用,而 env() 函数可以用来替代属性值的任何部分,或描述符的任何部分(例如,在 媒体查询规则中)。

History

Apple 最早在 iOS Safari 浏览器中引入了环境变量,以使开发者能够为不规则的设备显示优化布局。例如带有刘海和曲面边缘的设备。最初的 safe-area-inset-* 环境变量允许开发者将内容放置在视口的安全区域内,无论用户使用何种设备或浏览器。

用例

使用环境变量可以解决的常见问题包括:

  • 设备通知遮挡应用程序用户界面的部分区域。
  • 处理动态键盘显示和隐藏时的视口大小变化。
  • 渐进式 Web 应用(PWA)安装后,将元素放置在标题栏原本所在的位置,并确保内容不会与窗口控制按钮重叠。这在桌面浏览器上尤其是一个问题。

浏览器定义的环境变量

CSS 环境变量规范定义了一些区分大小写的变量,包括:

preferred-text-scale

preferred-text-scale 环境变量表示用户首选的文本缩放因子。这是对操作系统或用户代理的“默认”字体大小所做的调整。在 text-size-adjust 生效的设备和浏览器上,这是 text-size-adjust: auto 应用的缩放因子。例如,如果 text-size-adjust: auto 会导致文本大小加倍,那么 env(preferred-text-scale) 将解析为 2

safe-area-inset-*

四个安全区域内边距环境变量——safe-area-inset-topsafe-area-inset-rightsafe-area-inset-bottomsafe-area-inset-left——通过其与视口边缘的上、右、下、左的内边距来定义一个矩形安全区域。将内容放置在此区域内是安全的,不会被非矩形显示的形状所切断。对于矩形、无遮挡的视口,如常规的台式机和笔记本电脑显示器,这四个值都等于 0。对于非矩形显示——包括带有圆角的全面屏设备和圆形或圆形显示的智能手表——这四个由用户代理设置的值形成一个矩形,使得矩形内的所有内容都是可见且无遮挡的。

safe-area-max-inset-*

四个安全区域最大内边距环境变量——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-inset-* 的值。虽然 safe-area-inset-* 的值会随着当前可见内容区域的变化而变化,但 safe-area-max-inset-* 的值始终保持不变。

viewport-segment-*

这些变量仅与具有多个分区的设备相关,例如可折叠手机。viewport-segment-bottomviewport-segment-leftviewport-segment-rightviewport-segment-top 变量,以及 viewport-segment-heightviewport-segment-width,定义了视口中逻辑上分离的区域的位置和尺寸。这些变量仅在视口被划分为至少两个分区时才会被定义。它们用于将 UI 的不同部分舒适地放置在多分段设备的不同分段中,并避免你的内容被折叠处切断。

其他规范定义了额外的环境变量。

窗口控件覆盖 API 定义了 WindowControlsOverlay 接口,该接口公开了安装在桌面设备上的渐进式 Web 应用(PWA)中标题栏区域的几何信息。当使用 window-controls-overlay display_override 值时,会定义以下环境变量:

titlebar-area-*

titlebar-area-xtitlebar-area-ytitlebar-area-widthtitlebar-area-height 变量定义了在桌面环境中运行的已安装 Web 应用中通常由标题栏占据的区域。使用 titlebar-area-* 变量来确保内容不会与窗口控制按钮(即最小化、最大化和关闭)重叠。

keyboard-inset-*

keyboard-inset-topkeyboard-inset-rightkeyboard-inset-bottomkeyboard-inset-leftkeyboard-inset-widthkeyboard-inset-height 变量提供了关于屏幕虚拟键盘位置和大小的信息,特别是其与视口边缘的上、右、下、左的内边距(宽度和高度内边距是根据其他内边距计算的)。要了解更多信息,请参阅 VirtualKeyboard API

你可能已经注意到,前面所有的变量名都包含了物理术语左、右、上、下、高和宽。不需要逻辑等价物,因为变量名指的是设备硬件的物理属性,而不是显示的网站。

env() 函数

env() 函数用于将环境变量的值插入到 CSS 上下文中。env() 函数可以用于任何元素上任何属性值的任何部分,或任何 at-rule 规则上任何描述符值的任何部分,包括在自定义属性值中。它可以在任何允许使用 CSS 值的地方使用。

基本语法如下:

css
env( <environment-variable-name> )
env( <environment-variable-name>, <fallback-value> )

该函数接受一个区分大小写的环境变量名和一个可选但通常推荐的回退值。

css
line-height: env(preferred-text-scale, 2);
margin: env(safe-area-inset-top, 0) env(safe-area-inset-right, auto)
  env(safe-area-inset-bottom, 3em) env(safe-area-inset-left, auto);

第一个参数是要替换的环境变量的名称。如果提供了逗号后的参数,则为回退值,当第一个参数引用的环境变量不存在时使用该值。在这些示例中,如果浏览器中不存在 preferred-text-scale 环境变量,则 line-height 将被设置为 2。并且,如果浏览器没有 safe-area-inset-* 值,则 margin 将被设置为 margin: 0 auto 3em auto

回退值的语法类似于自定义属性的语法,因为它允许多个逗号。第一个逗号和函数末尾之间的任何内容都被视为回退值。然而,如果属性值或描述符不支持逗号,则该值无效。

如果一个属性或描述符包含了语法上有效的 env() 函数,它在解析时被认为是有效的。它仅在计算时进行语法检查,即在 env() 函数被替换为其浏览器提供的值之后。如果作为第一个参数传递的环境变量不是一个可识别的环境变量名,则使用回退值。回退值可以是另一个环境变量,甚至带有它自己的回退值。如果没有提供回退值,则包含 env() 函数的属性或描述符在计算值时是无效的。

使用 env() 函数和环境变量的示例

我们可以使用环境变量来确保固定的应用工具栏不会被设备底部出现的通知所遮挡。在屏幕底部显示通知的设备上,用户代理将 safe-area-inset-bottom 环境变量的值设置为从遮挡视口的内容顶部到视口底部的距离;在我们的示例中,这很可能是任何可见通知的高度。在矩形的桌面显示器上,safe-area-inset-bottom 通常是 0。我们将使用这个值在视口底部创建空间,以便通知显示而不会遮挡内容。

我们的 <body> 有两个子元素;<main> 包含了我们整个应用,除了 <footer> 工具栏。

html
<body>
  <main>Application</main>
  <footer>Toolbar</footer>
</body>

<body> 被定义为一个填充视口高度的 flex 容器。<main> 应用被允许增长以填充其兄弟元素 <footer> 未占用的任何空间。

css
body {
  display: flex;
  flex-flow: column nowrap;
  height: 100vh;
}

main {
  flex: 1;
  padding: 1em;
  overflow-y: auto;
}

<footer> 被定位以固定在视口的底部。position: sticky 声明根据 bottom 值为 0,将元素相对于 <body>(其滚动祖先和包含块)进行偏移。我们给 <footer> 一个四边都是 1empadding 值。然后,我们将 safe-area-inset-bottom 的值加到 1em 的底部内边距上,并提供 1em 的回退值。

css
footer {
  position: sticky;
  bottom: 0;
  padding: 1em;
  padding-bottom: calc(1em + env(safe-area-inset-bottom, 1em));
}

为简洁起见,隐藏了额外的 CSS。

safe-area-inset-bottom 环境变量值大于 0 的设备上,页脚的底部内边距将超过 1em。这个 CSS 提供了额外的内边距,以便根据需要扩展页脚,无论是由于通知、屏幕上的设备刘海,还是因为设备没有方形的角落。

未来,我们可能会看到对开发者定义的环境变量的支持,但这尚未被定义或实现。

另见