华为 X的豁口和CSS

2019-05-02 13:05栏目:ca888圈内

iPhone X的缺口和CSS

2017/09/19 · CSS · 1 评论 · iPhone

原文出处: 大漠   

苹果公司(Apple)的发布会也开完了,新产品也将登陆了。估计很多开发人员看到iPhone X的设备是要崩溃了,特别对于前端开发人员更是如此。

图片 1

iPhone X的屏幕覆盖了整个手机的屏幕,为相机和其他各部件留出了一个空间。结果是屏幕设计出现了一些尴尬的情况。比如将网站限制在一个“安全区域”。而在屏幕上的安全区域中,造成网站左边或右边有空白区域。

图片 2

很多像我这样的前端开始在考虑,这个蛋疼的东西怎么处理。而且项目中肯定要考虑这个设备的处理方式。值得庆幸的是,有两个小技巧或许可以帮助我们。

苹果的 iPhone X 配备了一个覆盖整个手机的全屏幕,但是顶部保留了一个“凹槽”,为相机和其他各种组件腾出空间。结果是屏幕设计时有一些尴尬局面,例如将网站限制在“安全区域”,那么边缘会有白色空白条。想要移除这个白色空白条虽然不难,在 body 设置一个 background-color 就可以搞定。或者,你可以 viewport-fit=cover 添加到 meta viewport 标签上,以使网页填充满整个屏幕。

iOS 11在状态栏区域带来了一些新的,也许是不直观的行为,这对使用Apache Cordova或Ionic等工具的开发人员尤为重要。尤其是这种行为变化会影响到任何基于Web的应用程序,这些应用程序在进行iOS 11构建时使用fixed定位标题栏。此文章可帮助您了解iOS 11中的Webview视口。

(备注:本文由本人翻译自Darryl Pogue的Understanding the WebView Viewport in iOS 11)

background-color

正如上图所示,左右(或顶、底部)留有空白的安全区域。这个时候,如果你的网站是单一的纯色做为背景,那么最好最简单的解决方案就是在你的body设置一个background-color。为了安全起见,建议同时在htmlbody都设置background-color。这个时候,上面的网站看到的效果是这样的:

图片 3

虽然没有白条,但空出了不少的区域。众所周知,在移动动终端,每一点空间都是非常值钱的,不容我们这样浪费。就算是你的Boss允许你这么做,那也有问题存在。如果你的网站或应用背景不是纯色,是一个渐变,或者是一个图像。此时又进入了蛋疼的阶段。或许你会说,蛋蛋揉揉就不疼了。

图片 4

HTML 代码:<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> 

注意:现有应用程序将继续工作,因为它们始终可以对其视口行为进行更改。这只会影响使用Xcode 9和iOS 11的目标编译的应用程序。

下面为正文内容:

viewport-fit

iOS11与早期的版本有个不同的地方,Webview内容将会尊重所谓的安全区域。这意味着,如果你有一个标题栏固定在顶部(position:fixed;top:0)。它将会在屏幕顶部下面的20px开始渲染。当你向下滚动时,它会移动到状态栏的后面。当你向上滚动时,它会再次下降到状态栏下面(在20px的间隙中,内容会透出,这是一个很尴尬的间隙。无法让人接受)。

 

 如果上面的视频无法正常展示,可以点击这里下载视频,查看效果

如果你对设计追求到极致,无法忍受那样的安全区域,或者说你使用渐变或图像作为背景,那么background-color无法拯救你我。不过,在最新的iOS版本中,苹果已经把viewport-fit增加到了CSS Round Display规范中。

viewport-fit可以设置可视窗口(Visual Viewport)的大小。在设备的物理屏幕上看到的初始布局视窗。在圆形屏幕上,当前屏幕上显示的部分是圆形的,但是Viewport却是矩形的。因此,根据Viewport的大小,页面的某些部可能被剪切。

图片 5

通过viewport-fit可以设置可视视窗的大小,也就是可以控制剪切区域。viewport-fit接受三个值:

  • auto:这个值不影响初始布局视窗,整个Web页面是可视的。在视窗之外的UA绘制的是未定义的,它可能是画布的背景色,或者是UA认为合适的其他东西
  • contain:最初的布局视窗和视觉布局视窗被设置为最大的矩形。在Viewport之外的UA绘制的是未定义的,它可能是画布的背景色,或者UA认为合适的其他东西
  • cover:初始布局视窗和视觉布局视窗被设置为设备物理屏幕的限定矩形

当在非矩形显示器上设置Viewport的边界框(Viewport Bounding Box)大小时,必须考虑以下因素:

  • 由于Viewport边界框(Viewport Bounding Box)的面积大于显示区域,导致了剪切区域
  • 在Viewport边界框和显示区域之间的间隙

开发人员可以决定哪一个因素比较重要。如果必须保证Web页面的任何部分都没有隐藏,那么避免剪切比在Viewport的边界框和屏幕的边框之间有个间隙更为重要。如果开发者不想让Web页面在可读性上变得很小,那么最好将viewport-fit设置为cover,并在考虑剪切部分时实显示页面。

理论都是较为空洞的,来看规范中提供的两个小示例。

这个示例显示了在圆形屏幕上通过viewport-fit来指定Viewport的边界框的大小。当指定viewport-fit的属性值为contain,将初始的Viewport应用于显示的最大的矩形。

@viewport (viewport-fit: contain) { /* CSS for the rectangular design */ }

1
2
3
@viewport (viewport-fit: contain) {
    /* CSS for the rectangular design */
}    

图片 6

viewport-fit的值为cover时,初始的Viewport应用于受限的矩形:

@viewport { viewport-fit: cover; } @media (shape: round){ /* styles for the round design */ } @media (shape: rect){ /* styles for the rectangular design */ }

1
2
3
4
5
6
7
8
9
@viewport {
    viewport-fit: cover;
}
@media (shape: round){
    /* styles for the round design */
}
@media (shape: rect){
    /* styles for the rectangular design */
}

图片 7

有关于viewport-fit更详细的介绍,可以查阅W3C规范文档。

回到我们的课题中来。解决iPhone X的安全区域。这里我们也将使用viewport-fit属性来解决。使用非常简单,在项目的之间添加一个标签。在这个标签中配置viewport-fit=cover。如下所示:

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/>

1
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/>

添加了这个标签之后,刚才的网站效果就变成了这样:

图片 8

因此,要将标题栏恢复到屏幕的顶部,就像在iOS10中一样,在状态栏的后面,你需要添加viewport-fit="cover"到你的viewportmeta标签中。

当然如果你要覆盖这个Viewport,你可能需要使用一些特技来避免隐藏的内容。

图片 9

回到iPhone X中。很明显,现在的设计需要一些手动调整来适应这个缺口,但是如何处理现在已经是开发人员和设计人员的事情了。这个时候估计开发和设计都在揉着自己的蛋蛋,怕碎了。

图片 10

要了解这些变化,我们需要看看它的历史。


safe-area-inset-*

现在iPhone X的形状不规则,其状态栏的高不再是20px,而且在摄像头和扬声器的设置下,你的标题栏内容将会完全无法访问到。需要注意的是,这也适用于固定在屏幕底部的页脚,它将被麦克风阻塞。

幸运的是,苹果添加了一种方法,将安全区域布局指南暴露给CSS。他们添加类似一个CSS的变量概念,叫作CSS constants。可以考虑这样的CSS变量,这些变量是由系统设计的,不能被覆盖。它们可以通过CSS的constant()函数来完成。这个函数已经向CSS工作组提出了标准化的建议。

constant()函数具有四个布局的值:

  • constant(safe-area-inset-top):在Viewport顶部的安全区域内设置量(CSS像素)
  • constant(safe-area-inset-bottom):在Viewport底部的安全区域内设置量(CSS像素)
  • constant(safe-area-inset-left):在Viewport左边的安全区域内设置量(CSS像素)
  • constant(safe-area-inset-right):在Viewport右边的安全区域内设置量(CSS像素)

在实际使用中,可以把这些值添加到marginpadding中,可以添加四个项,也可以只添加你所需要的。比如顶部或左侧。

在上面的示例的网站上添加了以下的值:

padding: constant(safe-area-inset-top) constant(safe-area-inset-right) constant(safe-area-inset-bottom) constant(safe-area-inset-left);

1
padding: constant(safe-area-inset-top) constant(safe-area-inset-right) constant(safe-area-inset-bottom) constant(safe-area-inset-left);  

这完全解决了在菜单和社交媒体图标上的问题。

图片 11

然后,你要考虑到任何重叠的情况,通常是由安全区域处理的。有一些新的CSS可以帮助你适应这种情况。查看 Stephen Radford 的文档:

状态栏与安全区

图片 12

来看一个示例

假设你有一个固定位置的标题栏,你的iOS10的CSS可能是这样写的:

header { position: fixed; top: 0; left: 0; right: 0; height: 44px; padding-top: 20px; /* Status bar height */ }

1
2
3
4
5
6
7
8
9
header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 44px;
 
    padding-top: 20px; /* Status bar height */
}

为了自动调整iPhone X和其他iOS11设备,你可以在meta标签的viewport中添加viewport-fit="cover"

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/>

1
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"/>

然后通过CSS的constant()修改padding-top的值:

header { position: fixed; top: 0; left: 0; right: 0; height: 44px; /* Status bar height on iOS 10 */ padding-top: 20px; /* Status bar height on iOS 11 */ padding-top: constant(safe-area-inset-top); }

1
2
3
4
5
6
7
8
9
10
11
12
13
header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 44px;
 
    /* Status bar height on iOS 10 */
    padding-top: 20px;
 
    /* Status bar height on iOS 11 */
    padding-top: constant(safe-area-inset-top);
}

对于不知道如何解决constant()语法的旧设备来说,你可以做一个降级的处理。你可以使用CSS的calc()函数。也可以借用@supports来使用。

header { position: fixed; top: 0; left: 0; right: 0; height: 44px; /* Status bar height on iOS 10 */ padding-top: 20px; } @supports (constant(safe-area-inset-top)) { header { /* Status bar height on iOS 11 */ padding-top: constant(safe-area-inset-top); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 44px;
 
    /* Status bar height on iOS 10 */
    padding-top: 20px;  
}
 
@supports (constant(safe-area-inset-top)) {
    header {
        /* Status bar height on iOS 11 */
        padding-top: constant(safe-area-inset-top);
    }
}

为了处理可能需要的任何调整,iOS 11 的 Safari 版本引入了一些常量,可以在使用 viewport-fit=cover 时使用。

在早起版本的iOS上,状态栏只是一个固定屏幕上方的黑色条带,并且是不可触摸的。它属于系统UI的一部分,你的app运行在它的下方空间中。

理解iOS11中的WebView

总结

文章根据不同的角度对iPhone X这个所谓的安全区域做的技术处理,而且这些手段都是使用CSS来完成。上面这些资料也是网上获取,由于自己未有这方面的设备,不敢确保技术方案百分百的能解决这个问题。当然如果你有相关的设备,建议自己写一个Demo测试一下。如果你有更好的方案,欢迎一起分享。

  • safe-area-inset-top :视口顶部到安全区域的距离(以CSS像素为单位)。
  • safe-area-inset-right :视口最右边到安全区域的距离(以CSS像素为单位)。
  • safe-area-inset-left :视口最左边到安全区域的距离(以CSS像素为单位)。
  • safe-area-inset-bottom :视口底部到安全区域的距离(以CSS像素为单位)。

随着iOS7的推出,状态栏变成了透明的,它的颜色取自应用程序导航栏的颜色。对于运用在webview中的app比如Cordova,通常要判断iOS的版本然后在固定的导航栏上方预留20px的边距,以便正确的填充导航栏。

发布于09/13/2017,作者:Darryl Pogue

参考资料

  • “The Notch” and CSS
  • Understanding the WebView Viewport in iOS 11
  • Removing the White Bars in Safari on iPhone X

    1 赞 2 收藏 1 评论

图片 13

这些值可以应用到 margin , padding ,或者绝对(absolute)定位的 top 或 left 上。

较新版的iOS对状态栏引入了一些小的修订版本,包括在打电话时状态栏中显示一个额外的横幅,或者应用程序在后台使用定位功能的提示。

iOS11在顶部状态栏区域带来了一些新的可能不太直观的行为改变,但是这对那些使用如Apache Cordova或Ionic等工具的开发人员来说非常重要。值得说明的是,这种改变将会影响任何基于Web的使用了固定状态栏的应用程序,当开发人员意图为iOS11构建这些应用程序时。那么此篇文章将会帮助您了解iOS11中的WebView组件。

它们可以通过 CSS 的 constant() 函数转换成我们常用的属性值,例如, 我将以下内容添加到网站上的主容器中。

在native端,大部分这些兼容措施都被UINavigationBar以及自动布局指南自动解决掉了。屏幕顶部底部布局指南会自动的判断出当前状态栏的正确高度,确保app内容区是『安全区』,状态栏不会覆盖到该区域。如果你根据顶部布局指南使用UINavigationBar,则iOS也会自动将其颜色延伸到状态栏后面。对于Web端来说,没有这样自动化的解决方案。

注意:现有的应用程序依然将正常工作,因为其内部的WebView的组件行为并未改变。这种改变只影响使用Xcode9编译适配iOS11的应用程序。

CSS 代码:padding: constant(safe-area-inset-top) constant(safe-area-inset-right) constant(safe-area-inset-bottom) constant(safe-area-inset-left);  

iOS 11的改变

为了理解这种变化,我们来看看历史版本中状态栏的变化。

凹槽,安全区域和固定(fixed)定位还会造成另一个尴尬局面。 来看看 Darryl Pogue 的报告:

图片 14

状态栏与安全区域

在早期版本的iOS中,状态栏仅仅是屏幕顶部不变的不可触控的黑色条。对开发人员来说状态栏不过是一个系统UI,应用程序在它下面的空间运行而已。

这种情况随着iOS7的到来有所变化,iOS7中的状态栏变成了透明的,并根据导航栏(Navigation Bar)的颜色变化而变化。它意味着如Cordova这样的WebView组件中的应用程序,必须检测运行环境的iOS版本,并将20px的内边距固定添加到页面的顶部,来保证下面内容的显示位置正确。

而在iOS7以后的版本中状态栏只是增加了一些小的修正,包括增加了额外的横幅在通话时或者后台使用地理定位时。

对于本地应用来说,这部分是通过UINavigationBar和autolayout原生控件自动处理的。这些原生组件中的布局规则会保证内容调整到适配状态栏的正确高度,从而显示在状态栏不会遮挡它们的所谓“安全区域”中。同时,如果你的导航栏(UINavigationBar)靠部对其,它的颜色就会自动延伸到状态栏后面,而形成统一的颜色。可不幸的是,对于基于Web的应用程序确不能享用这份福利。

iOS 11与早期版本不同之处在于 webview 内容现在遵循安全区域。这意味着如果你的 header 是一个的 top 设置为 0 的固定(fixed)定位的元素,它将被初始渲染在离屏幕顶部向下 20px 的位置, 对齐到状态栏的底部。当你向下滚动页面时,它会在状态栏后面移动。当你向上滚动,它将再次滑到到状态栏的下方(网页内容会在那条尴尬的 20px 的缝隙中显示)。

你可以在下面这个视频看到有多糟糕:

iOS 11与早起版本的不同在于,webview内容区超出了安全区。这也就是说,如果你有一个头部导航条使用fixed定位元素并且使用top: 0,那么它会在屏幕顶部20px的下方渲染:对齐到状态栏的底部。

iOS11中的改变

图片 15

iPhone 8中iOS 11中的默认显示。

iOS11中不同的是WebView中的内容现在也增加了对这个所谓的“安全区域”的支持。它意味着当你的页面中有个固定位置的标题栏元素(设置为top:0),那它在页面渲染完成后会出现在屏幕顶部的20px以下也就是对齐了状态栏的地方。但是,值得注意的是:当内容向下滚动时,内容会移动到状态栏的后面;而内容向上滚动时,将会再次跌落到状态栏的下方。(留下一个很尴尬的差距落差效果,原文是个视频,这里做了些截图。)

图片 16

页面载入完成后

图片 17

向上滚动

图片 18

再向下滚动

图片 19

最后

幸运的是,将 viewport-fit=cover 添加到 meta viewport 标签就可以轻松修复。

当你向下滚动时,它将向上移动到状态栏的下面。

苹果为什么要这样设计?

我想你应该看过了PhoneX的设计,它有着不规则的屏幕形状,在屏幕顶部切除了一块区域用来放置扬声器和相机。那么如果将页面的元素固定到真实屏幕的顶部,将会出现部分内容被放置在这块切除区域中,而导致根本无法触控使用。通过系统将它对齐到状态栏的底部,可以确保顶部标题栏中的全部内容都可以使用。

这很酷……除了现有的应用程序中出现的那20px的尴尬……

iPhone X 和 iOS 11 其他一些技巧

当你向上滚动时,它将会重新跌落到状态栏的下方(此时会留下一个尴尬的间隙,内容会在这20px的间距内展示)

iOS11中的修正

幸运的是,苹果为开发者提供了一种通过元标签(head中的meta)来控制这个行为的方法。更幸运的是,苹果甚至将这个修复补丁更新到了已经被放弃的UIWebView控件中。

这个可设置的属性是viewport-fit,它有三个可能的值:

  • contain:视图窗口应包含全部网页内容,即内容中的固定元素将被自动包含在所谓的“安全区域”中。
  • cover:网页中需要处理全部视图窗口即真实屏幕中的内容,即你的顶部元素可能会被遮挡,你要自己处理就像在iOS10上面一样。
  • auto:默认值,与contain相同

因此,你要想将你的标题栏还原到最顶部在状态栏的后面,就像你在iOS10中做的,你要在你的页面的head的meta中的viewport设置中增加viewport-fit=cover。

图片 20

看起来很好的视口合适设置覆盖在iOS 11在iPhone 8上。

关于 viewport-fit

viewport-fit可以设置可视窗口(Visual Viewport)的大小。在设备的物理屏幕上看到的初始布局视窗。在圆形屏幕上,当前屏幕上显示的部分是圆形的,但是Viewport却是矩形的。因此,根据Viewport的大小,页面的某些部可能被剪切。

viewport-fit 接受三个值:

  • auto:这个值不影响初始布局视窗,整个Web页面是可视的。在视窗之外的UA绘制的是未定义的,它可能是画布的背景色,或者是UA认为合适的其他东西;
  • contain:最初的布局视窗和视觉布局视窗被设置为最大的矩形。在Viewport之外的UA绘制的是未定义的,它可能是画布的背景色,或者UA认为合适的其他东西;
  • cover:初始布局视窗和视觉布局视窗被设置为设备物理屏幕的限定矩形;

苹果为什么会这么做呢?

iPhoneX

但是对于iPhoneX这种不规则的屏幕怎么办呢?在iPhoneX上状态栏不再是20像素高,并且因为扬声器和相机的遮挡,你的标题栏将完全无法触控使用了。需要注意的是,这种情况同样会出现在固定在底部的页脚部分,它将被麦克风遮挡住。

注意:如果你的应用程序中使用了Launch Storyboard方式,那你的应用程序就只能使用iPhoneX的全屏幕控件。现有的应用程序将自动被显示在顶部和底部之间的矩形空间中。(这个注意不是特别理解,感觉是启动时用了Launch Storyboard,就是全屏幕显示也就是WebView可以显示全屏幕;以前编译的应用会自动夹在中间区域,无法撑满全屏)

图片 21

iPhone X带来了一些新的挑战,即使在窗口合适的情况下也可以覆盖。

不过幸运的是,苹果公司增加了一个方法,将这个“安全区域”的布局规范开放到了CSS中。它被作为一种常量设置被添加到了CSS中,可以通过CSS中的constant()函数来访问,并且这个函数已经被提交给了CSS工作组进行了标准化。

这4个常量分别为:

  • constant(safe-area-inset-top):获取顶部安全区域插入值(单位为像素)
  • constant(safe-area-inset-bottom):获取底部安全区域插入值(单位为像素)
  • constant(safe-area-inset-left):获取左侧安全区域插入值(单位为像素)
  • constant(safe-area-inset-right):获取右侧安全区域插入值(单位为像素)

而苹果还给了我们一个礼物就是这个变量也被更新到了UIWebView中。

CSS constants 示例

假设你有一个固定(fixed)定位的标题栏,在 iOS 10及之前的 CSS 目前看起来像这样:

CSS 代码:header {    position: fixed;    top: 0;    left: 0;    right: 0;    height: 44px;     padding-top: 20px; /* 状态栏高度 */}

要使 iPhone X 和其他 iOS 11 设备自动进行调整,您可以将 viewport-fit=cover 添加到 meta viewport 标签,并更改 CSS 来引用常量:

CSS 代码:header {    /* ... */     /* iOS 10 上 状态栏高度 */    padding-top: 20px;     /* iOS 11  上 状态栏高度 */    padding-top: constant(safe-area-inset-top);}

对于不能识别 constant() 语法的旧设备,请保留备用值。您也可以在CSS calc() 表达式中使用常量。

如果你看到了iphone X的设计图,你就会有一个印象:iphone X未来有一个不规则的屏幕形状,在屏幕顶部有一段『刘海』,用来放置话筒与相机。如果fixed定位的元素定位到了真正的屏幕顶部,那该元素中间部分会被扬声器与相机覆盖,从而无法访问。

使用示例

假设你的页面上有一个固定位置的标题栏,在iOS10中的设置是这样的:

header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 44px;

    padding-top: 20px; /* 状态栏高度 */
}

那么,要为iPhoneX或者其他iOS11的设备进行调整,你需要在页面head中的viewport meta中增加:

<meta name="viewport" content=".... viewport-fit=cover">

更改CSS设置为:

header {
    /* ... */

    /* iOS10中状态栏的高度 */
    padding-top: 20px;

    /* iOS11 中状态栏的高度 */
    padding-top: constant(safe-area-inset-top);
}

图片 22

iPhoneX中的自动填充

需要注意的是,对于不知道如何解析constant语法的旧设备来说,保留返回值是很重要的(我的理解就是指上面的padding-top:20px;)。另外,你还可以在CSS的calc()方法中使用这些常量。

如果你有底部导航栏的话,也要记得为它设置这个样式内容。


(这个是笔者的鸣谢,咱也替广大开发者谢谢了!)

特此感谢苹果公司的WebKit团队的Timothy Horton研发了本文提到的viewport-fit和constant()功能。感谢Shazron,Julio,Kerri,Greg和Mike在测试和验证中提供的贡献。

(译文完毕!)

版权声明:本文由ca888发布于ca888圈内,转载请注明出处:华为 X的豁口和CSS