为 iPhone X 设计网站

下面关于安全区域内边距的部分已于 2017 年 10 月 31 日更新,以反映 iOS 11.2 测试版中的变化。

开箱即用,Safari 能在新 iPhone X 的全面屏上精美地显示您现有的网站。内容会自动嵌入显示屏的安全区域内,因此不会被圆角或设备的传感器外壳遮挡。

内边距区域会填充页面指定的 background-color (在 <body><html> 元素上指定),以与页面的其余部分融为一体。对于许多网站来说,这已经足够了。如果您的页面只有文本和图片,并且背景是纯色,那么默认的内边距看起来会很棒。

其他页面——特别是那些设计有全宽水平导航栏的页面,如以下页面——可以选择性地更进一步,充分利用新显示屏的特性。iPhone X 人机界面指南详细介绍了一些需要记住的通用设计原则,UIKit 文档讨论了原生应用可以采用的特定机制,以确保其显示效果良好。您的网站可以利用 iOS 11 中引入的一些类似的新 WebKit API,充分利用显示屏的全面屏特性。

在阅读本文时,您可以点击任何图片,访问相应的实时演示页面并查看源代码。

Safari's default insetting behavior
Safari 的默认内边距行为。

使用整个屏幕

第一个新功能是对现有 viewport meta 标签的扩展,称为 viewport-fit,它提供了对内边距行为的控制。viewport-fit 在 iOS 11 中可用。

viewport-fit 的默认值是 auto,这会导致上面看到的自动内边距行为。为了禁用该行为并使页面布局到屏幕的全尺寸,您可以将 viewport-fit 设置为 cover。这样设置后,我们的 viewport meta 标签现在看起来像这样

<meta name='viewport' content='initial-scale=1, viewport-fit=cover'>

重新加载后,导航栏看起来好多了,从边缘延伸到边缘。然而,立即清楚的是,为什么尊重系统的安全区域内边距很重要:页面的一些内容被设备的传感器外壳遮挡,并且底部导航栏非常难以使用。

viewport-fit=cover
使用 `viewport-fit=cover` 填充整个屏幕。

尊重安全区域

在采用 viewport-fit=cover 后,使我们的页面再次可用的下一步是选择性地对包含重要内容的元素应用内边距,以确保它们不会被屏幕的形状遮挡。这将使页面充分利用 iPhone X 增加的屏幕空间,同时动态调整以避开圆角、传感器外壳和访问主屏幕的指示器。

Safe and Unsafe Areas
iPhone X 横向模式下的安全区域和非安全区域,并标示出内边距。

为此,iOS 11 中的 WebKit 包含了一个新的 CSS 函数 env(),以及一组四个预定义的环境变量safe-area-inset-leftsafe-area-inset-rightsafe-area-inset-topsafe-area-inset-bottom。结合使用时,这些变量允许样式声明引用每侧安全区域内边距的当前大小。

env() 函数在 iOS 11 中以 constant() 的名称发布。从 Safari Technology Preview 41 和 iOS 11.2 测试版开始,constant() 已被移除并替换为 env()。如有必要,您可以使用 CSS 回退机制支持这两个版本,但今后应优先使用 env()

env() 在任何 var() 可用的地方都有效——例如,在 padding 属性内

.post {
    padding: 12px;
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
}

对于不支持 env() 的浏览器,包含它的样式规则将被忽略;因此,重要的是要继续为任何使用 env() 的声明单独指定回退规则。

Safe area constants
尊重安全区域内边距,以便重要内容可见。

结合使用 min() 和 max()

本节介绍从 Safari Technology Preview 41 和 iOS 11.2 测试版开始可用的功能。

如果您在网站设计中采用安全区域内边距,您可能会注意到,除了安全区域内边距之外,很难指定您想要一个最小的内边距。在上面的页面中,我们将 12px 的左内边距替换为 env(safe-area-inset-left),当我们旋转回纵向时,左侧安全区域内边距变为 0px,文本紧贴屏幕边缘。

No margins
安全区域内边距不能替代外边距。

为了解决这个问题,我们希望指定我们的内边距应该是默认内边距或安全区域内边距中的较大者。这可以通过全新的 CSS 函数 min()max() 实现,这些函数将在未来的 Safari Technology Preview 版本中可用。这两个函数都接受任意数量的参数并返回最小值或最大值。它们可以在 calc() 内部使用,或相互嵌套,并且两个函数都允许在其内部进行类似 calc() 的数学运算。

对于这种情况,我们想使用 max()

@supports(padding: max(0px)) {
    .post {
        padding-left: max(12px, env(safe-area-inset-left));
        padding-right: max(12px, env(safe-area-inset-right));
    }
}
重要的是要使用 @supports 进行 min 和 max 的功能检测,因为它们并非在所有地方都受支持,并且由于 CSS 对无效变量的处理,请不要在 @supports 查询中指定变量。

在我们的示例页面中,在纵向模式下,env(safe-area-inset-left) 解析为 0px,因此 max() 函数解析为 12px。在横向模式下,当 env(safe-area-inset-left) 因传感器外壳而变大时,max() 函数将解析为该大小,从而确保其中的重要内容始终可见。

max() with safe area insets
使用 max() 将安全区域内边距与传统外边距结合使用。

经验丰富的网页开发者以前可能遇到过“CSS 锁”机制,通常用于将 CSS 属性限制在特定值范围内。结合使用 min()max() 将使这变得容易得多,并且在未来实现有效的响应式设计方面会非常有帮助。

反馈和问题

您今天就可以开始采用 viewport-fit 和安全区域内边距,只需使用 Xcode 9 中包含的 iPhone X 模拟器中的 Safari。我们非常乐意听到您采用这些功能的情况,因此请随时将反馈和问题发送至 web-evangelist@apple.com 或 Twitter 上的 @webkit,并向 WebKit 的错误跟踪器提交您遇到的任何错误。