前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >兼容iPhone X* 刘海的正确姿势

兼容iPhone X* 刘海的正确姿势

作者头像
用户1097444
发布2022-06-29 16:06:07
6410
发布2022-06-29 16:06:07
举报
文章被收录于专栏:腾讯IMWeb前端团队

本文由 IMWeb 团队成员 zzbo 首发于 IMWeb 社区网站 imweb.io。点击阅读原文查看 IMWeb 社区更多精彩文章。

9月13日凌晨终于等来了万众瞩目的苹果新品发布会,相信很多小伙伴们都期待新 iphone 可以剪掉刘海胡子,但万万没想到的是等来了三款不同的尺寸的 iphone x ,我的天,等了这么久你给我看这个?码农慌得一批满地找新 iphone 的逻辑像素,然后想着怎么兼容这刘海和胡子。

以往的做法

其实对于 web 前端来说,刘海在绝大多数的场景下是可以不用处理的,因为 safari 或客户端(微信,手Q等)的 statusBar 已经替我们抹平了顶部刘海,我们只需要关心底部的那条黑色的胡子,因为如果页面底部有按钮的话,就会被胡子给挡住,以往我们兼容过 iphone x 的下巴,但现在回想起来不是正确的做法。我们之前是这么处理的: 首先在 <html> 中加入对应的 className: has-bottombar

代码语言:javascript
复制
<html class="has-bottombar">    <head></head>    <body></body></html>

再配上对应的 css:

代码语言:javascript
复制
@media only screen and (-webkit-device-pixel-ratio: 3) and (device-height: 812px) and (device-width: 375px) {  .has-bottombar {    height: 100%;    -moz-box-sizing: border-box;    box-sizing: border-box;    padding-bottom: 34px;  }  .has-bottombar:after {    content: '';    z-index: 9999;    position: fixed;    left: 0;    bottom: 0;    width: 100%;    height: 34px;    background: #fff;  }}

这里的处理方法是使用了媒体查询 media query 按照 iphone x 的尺寸(375px * 812px)做特殊处理,主要做两件事情: 1、给 html 底部预留 34px 的间距,让页面里面的内容距底部保持 34px 的间距,从而避开了胡子的遮挡。 2、创建一个 after 伪类通过设置 position:fixed 定位到页面底部,并设置成白色,这一处理主要是遮挡住页面背景色。 效果如下图:

这样只是解决了底部胡子的问题,我们试着横屏看看:

这里有个很明显的问题:页面左边的文字被刘海遮挡。

在 safari 往上段滑动一小段距离,可以看到当 safari 的底部操作栏出现后,页面依然会保留着距底部的 34px 空白。

这些处理如果在9月13日之前是问题不大的,但在 9月13日 之后前端开发的同学头就大了,因为新的三款 iphone 尺寸都不一样(逻辑像素 xr: 375 * 812; xs: 414 * 896; xs max: 414 * 896;)于是,开始奔命于修改 media query。。。如果明年又多几个尺寸那就会是没完没了的改改改。

正确的姿势

在 ios 11 中我们可以使用 viewport-fit=cover + safe-area-inset-*。 那么是不是 ios11 以下就用不了这些了呢?是的,但你见过 iphone x+ 有 ios 11以下的吗? 所以我们可以愉快的搞下去。

开始之前我们先了解什么是 safe area,简单的来说就是除了刘海和胡子以外的区域为安全区域:

关于 viewport-fit

viewport-fit 有3个值: contain: 可视窗口完全包含网页内容(左图) cover:网页内容完全覆盖可视窗口(右图) auto:默认值,跟 contain 表现一致

如何决定 viewport-fit 值?我们要考虑一些问题: 1、在非矩形显示器上设置 viewport 边界时,Viewport边界框(Viewport Bounding Box)的面积大于显示区域,导致了剪切区域 2、如果要保证Web页面的任何部分都没有隐藏,不想让Web页面在可读性上变得很小,那么最好将viewport-fit设置为cover,并在考虑剪切部分时实显示页面。 3、还有另一个考虑是,当我们设置 viewport-fit:contain,也就是默认的时候时,设置 safe-area-inset-* 等 css 属性时不起作用的。 点击这里了解更多关于 viewport-fit

关于 safe-area-inset-*

各种 iphone x 都是不规则形状,我们如何控制页面元素到安全区域呢?apple 把安全区域的位置通过 css 属性提供给了开发者,它们可以通过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像素)

简单来说我们可以通过 constant() 可以获取到非安全边距,再结合 paddingmargin 来控制页面元素避开非安全区域。 Webkit在iOS11中新增CSS Functions: env( )替代constant( ),文档中推荐使用env( ),而 constant( ) 从Safari Techology Preview 41 和iOS11.2 Beta开始会被弃用。在不支持env( )的浏览器中,会自动忽略这一样式规则,不影响网页正常的渲染。为了达到最大兼容目的,我们可以 constant( ) 和 env( ) 同时使用。

代码语言:javascript
复制
.yourFooterClass {  padding-bottom: constant(safe-area-inset-bottom); /* iOS 11.0 */  padding-bottom: env(safe-area-inset-bottom); /* iOS 11.2 */}

本文为了简洁只写 env( )。

实践一波

一、设置网页在可视区域的布局方式

新增 viweport-fit 属性,使得页面内容完全覆盖整个窗口:

代码语言:javascript
复制
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover">
二、让主体内容控制在安全区域内

假设我们的底部按钮高度是50px:

代码语言:javascript
复制
body {  padding-top: env(safe-area-inset-top);  padding-right: env(safe-area-inset-right);  padding-bottom: 50px;  /* 兼容不支持 env( ) 的设备  */  padding-bottom: calc(env(safe-area-inset-bottom) + 50px); /* 在 iphone x + 中本句才会生效 */  padding-left: env(safe-area-inset-left);}

有两个关键点: 1、写在前面的 padding-bottom:50px 为了兼容没有底部胡子的设备,让主体内容偏移出底部按钮的高度,避免按钮遮挡内容。 2、 padding-bottom:calc(env(safe-area-inset-bottom)+50px); 计算 底部非安全区域距离底部按钮高度 之和 来做为 padding-bottom 值,如果设备支持 env,那么 calc 会计算出一个合法的值,本句的优先级则最高,会覆盖前面的 padding-bottom:50px。否则 calc 会计算出一个不合法的值,则本句声明不会生效。这样在不支持 env 设备中也可以达到兼容的目的。

目前到这,在横屏场景下左侧的内容就不会被刘海遮挡住了:

三、底部按钮的处理

首先给底部按钮一个外层容器 .btn-container ,设置样式时其中有几点比较关键: 1、设置 padding-bottom:env(safe-area-inset-bottom);增加一个 padding 值,让底部向外扩展一个非安全区域的距离。 2、设置 background:#FFF 让整个 .btn-container 背景为白色(包括刚新增的 padding-bottom 的区域)这样就可以遮挡住了底部内容。 3、设置 box-sizing:content-box; ,因为在通常情况下 css 在 reset 阶段一般都设置了 *{box-sizing:border-box;} 这样一来设置 padding 就不能向外扩展距离了,所以在这里我们要把他改回 content-box

代码语言:javascript
复制
.btn-container {  box-sizing: content-box;  height: 50px;  line-height: 50px;  color: #fff;  position: fixed;  bottom: 0;  left: 0;  right: 0;  text-align: center;  background: #FFF;  padding-bottom: env(safe-area-inset-bottom);}.btn {  width: 100%;  height: 50px;  line-height: 50px;  background-color: #00c340;  border: none;}

看看效果:

在 safari 中,页面往上稍滑动一点,出现 safari 的操作栏后,底部按钮依然会紧贴着操作栏,非常有灵性:

处理起来一切都显得 简洁优雅细腻。

最后

如果兼容刘海和胡子需要满地找逻辑像素,满地找新 iphone,很可能是没有掌握正确的姿势。 另外,发现在横屏场景下有一个比较有趣的效果,大家可以了解一下,但在实际业务中应该不需要做得这么花哨:

参考: 借助CSS Shapes实现元素滚动自动环绕iPhone X的刘海(https://www.zhangxinxu.com/wordpress/2017/09/css-shapes-outside-iphone-x-head/)

关注我们

IMWeb 团队隶属腾讯公司,是国内最专业的前端团队之一。

我们专注前端领域多年,负责过 QQ 资料、QQ 注册、QQ 群等亿级业务。目前聚焦于在线教育领域,精心打磨 腾讯课堂 及 企鹅辅导 两大产品。

社区官网

http://imweb.io/

加入我们

https://hr.tencent.com/position_detail.php?id=26701

扫码关注 IMWeb前端社区 公众号,获取最新前端好文

微博、掘金、Github、知乎可搜索 IMWebIMWeb团队 关注我们。

👇点击阅读原文获取更多参考资料

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-11-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯IMWeb前端团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 以往的做法
  • 正确的姿势
    • 关于 viewport-fit
      • 关于 safe-area-inset-*
      • 实践一波
        • 一、设置网页在可视区域的布局方式
          • 二、让主体内容控制在安全区域内
            • 三、底部按钮的处理
            • 最后
            • 关注我们
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档