借助CSS Shapes实现元素滚动自动环绕iPhone X的刘海

一、iPhone X的刘海发型和衍生的交互

iPhone X的刘海头

iPhone X造型上有个显著的特质,就是有个明显的刘海。

然后,也出现了一些酷酷的交互。

例如下面这个交互:

iPhone X刘海与列表交互

交互视频效果戳这里体验:http://t.cn/Rp01GKc

就是页面滚动的时候,列表会自动绕着iPhone X的刘海排列。

看上面微博截图的反应,好像觉得这个效果实现很难,实际上,CSS3里面针对这种特定形状环绕的效果已经支持很久了,CSS3 Shapes和CSS3 Regions都是可以实现的,本文就将展示如何使用CSS3 Shapes实现元素内容在滚动的时候自动环绕iPhone X的齐刘海的效果。

二、CSS3 Shapes实现元素滚动自动环绕iPhone X头部刘海效果

眼见为实先看效果,您可以狠狠的点击这里:CSS3 Shapes实现列表环绕iPhone X刘海头demo

亦可以直接手机(如果是iPhone的话)扫下面二维码体验:

列表环绕齐刘海演示页面二维码

滚动列表,可以看到类似下面gif的效果:

列表环绕 iPhone X刘海gif截屏效果

环绕齐刘海滚动实现原理

CSS Shapes中有个CSS属性名为shape-outside,可以让内联元素以不规则的形状进行外部排列,其语法如下(参考自MDN):

/* 关键字值 */
shape-outside: none;
shape-outside: margin-box;
shape-outside: content-box;
shape-outside: border-box;
shape-outside: padding-box;

/* 函数值 */
shape-outside: circle();
shape-outside: ellipse();
shape-outside: inset(10px 10px 10px 10px);
shape-outside: polygon(10px 10px, 20px 20px, 30px 30px);

/* <url>值 */
shape-outside: url(image.png);

/* 渐变值 */
shape-outside: linear-gradient(45deg, rgba(255, 255, 255, 0) 150px, red 150px);

shape-outside属性要想生效,本身需要是浮动float元素。

本文demo效果实现使用的是shape-outside:polygon(),通过点坐标勾勒出和齐刘海形状相似的多边形形状,CSS代码为:

.shape {
  float: left;
  shape-outside: polygon(0 0, 0 150px, 16px 154px, 30px 166px, 30px 314px, 16px 326px, 0 330px, 0 0);
}

如下图紫色区域示意:
CSS shapes勾勒出的近似齐刘海的形状

此时,后面没有设置BFC(块状格式化上下文)的列表元素就会自动环绕这个形状排列,也就是自动避开了齐刘海区域。

然后,只要搞个假的iPhone X的齐刘海图片覆盖在区域上就可以了。

至此,一个静态的列表环绕齐刘海的效果就完成了。

下面关键的问题是如何让滚动的时候,列表元素动态的跟着环绕呢?

由于shape-outside所在的元素是浮动元素,因此,必定会跟着容器一起滚动,我们需要的效果是我们所绘制的这个刘海区域需要是固定的,怎么办?此时,我是借助JavaScript处理的。

原理很简单,监听容器的滚动事件,让我们的shape-outside绘制的区域实时偏移滚动的大小。此时肉眼看上去的效果就是shape-outside区域永远固定在了滚动容器clientHeight的中间。

整个效果就这么实现了,相关JS如下:

box.addEventListener('scroll', function () {
  var scrollTop = box.scrollTop;
  // 滚动偏移应用在shape-outside上
  shape.style.shapeOutside = 'polygon(0 0, 0 '+ (150 + scrollTop) +'px, 16px '+ (154 + scrollTop) +'px, 30px '+ (166 + scrollTop) +'px, 30px '+ (314 + scrollTop) +'px, 16px '+ (326 + scrollTop) +'px, 0 '+ (330 + scrollTop) +'px, 0 0)';
});

更详尽的代码尽在demo页面

三、CSS Shapes环绕iPhone X刘海的其它更简易方法

如果我们的技术选型是更看重简单易懂,而不是资源消耗与占用,还可以使用shape-outside:url(image.png)语法实现类似的效果,其中'image.png'就是用来被环绕的图片,环绕与否是基于计算alpha通道决定,用句简单的话描述,就是沿着图片非透明区域环绕。

由于使用url()的形状计算是基于图片元素,和inset(), circle(), ellipse()或者polygon()这些基础形状方法的计算性质不一样,因此,可以直接使用垂直方向的margin进行偏移。这要比polygon()这样实时计算坐标位置要好理解的多。

我们不妨看下CSS和JS代码,如下:

.shape {
  float: left;
  shape-outside: url(liu-outside.png);
  margin-top: 150px;
}
box.addEventListener('scroll', function () {
  var scrollTop = box.scrollTop;
  // 滚动偏移应用在margin-top上
  shape.style.marginTop = (150 + scrollTop) + 'px';
});

可以看到,当我们滚动容器的时候,改变的就一个marginTop值就好了;而上面的 shape-outside:polygon()实现需要同时改变多个坐标值。

眼见为实,您可以狠狠的点击这里:shape-outside url实现列表环绕iPhone X刘海demo

如果是iPhone手机,还可以扫下面码体验:

shape-outside url环绕iPhone X刘海二维码

效果类似:

shape-outside url实现的环绕列表效果

有个细节说明
这里有个细节需要说明下,那就是作为环绕区域的图片和前面显示的那个刘海图片不是一张图片,因为我们的刘海区域需要和后面的文字有一段的间隙,因此,url(liu-outside.png)中的这张'liu-outside.png'图片是有特别的实色填充处理的(扩展右侧环绕区域尺寸):

刘海占位区域图片的扩展处理

四、CSS Shapes的兼容性以及结束语

CSS Shapes的兼容性为Chrome浏览器和Safari浏览器(包括iOS)都是支持的,也就意味着我们是可以在iPhone上使用的,完美。只是需要注意的是在iOS10.2及其之前的版本,CSS Shapes的使用还是需要加webkit私有前缀的,但据说iPhone X至少默认iOS 11,而刘海头交互效果就是针对iPhone X处理的,因此webkit私有前缀不加也没关系。

CSS Shapes的Safari浏览器兼容性

本文这个例子可以看出知识广度的重要性,如果我们深究最终效果实现使用的CSS和JS代码,其实就几行代码而已,键盘敲一下,几分钟就结束了。

那为什么广大前端一看到这个效果觉得牛,甚至认为“UI和前端已经哭晕在厕所”呢?其实就是不知道CSS3 Shapes和CSS3 Regions这些与环绕布局相关的CSS属性。

所以,下班回家,经常关注一些前沿技术还是很有必要的,注意是前沿技术,不是流行技术。很多前沿技术因为使用场景小众,并不流行,甚至你可以几年项目都用不到。如果你想在技术上有所造诣,一定要摒弃功利之心,花时间了解之。

以上~

行文匆忙,如果有表述不准确的地方,欢迎指正。

最后感谢您花费宝贵的时间阅读本文!

(本篇完)

分享到:

标签: , , , , , , , ,

赞助商推荐(我也要赞助)

想学到点真东西? ×
如果你有1~3年前端开发经验,不妨 ×


发表评论(目前25 条评论)

  1. IndexXuan说道:

    请问旭神,你们目前 web 适配 iPhone X 都是怎样检测 iPhone X 设备的?用媒介查询屏幕尺寸?能不能提供一些思路啊?感谢感谢~

  2. wein说道:

    真佩服!!!张老师一般在哪些网站可以了解到前沿技术

  3. 果冻王说道:

    刘海区域和后面的文字的间隙可以用shape-margin设置

  4. 桃子说道:

    张老师,通过css的shape-outside实现的效果很受用,但是我想知道针对苹果官方给出的安全区进行开发的效果,如果全屏的背景需要怎么做呢?

  5. 银息说道:

    太牛气了,值得学习。

  6. 1111说道:

    最新火狐浏览器不支持啊

  7. clover说道:

    就喜欢博主这种实时专研的精神

  8. yugasun说道:

    非常赞同旭哥的观点,下班回家多关注前沿技术,开阔视野很重要,比如多到旭哥的博客逛逛,今天又收获满满~

  9. 海伦克里克说道:

    最近遇到坎了,无意中找到了大神的网站,想来试验一下,复制到textarea中的文字能不能保持原格式输出,不过还是出于崇拜大神的心情,知乎10个问答我看了一些,让我很受启发,希望自己能在这多学一些知识。
    “洛阳亲友如相问
    一片冰心在玉壶”

  10. 叫兽说道:

    真是太牛了,学习学习

  11. 猫咪君-VRlie说道:

    虽然我们的产品暂时不考虑横屏的情况。但是我不得不给旭哥说一个“服”字。

  12. 猎奇狮说道:

    不得不说很牛逼~ 但是本地测试是有问题的。需要在服务器环境下测试才行。

  13. mrj说道:

    大佬的博客 广告好多。。。

  14. 阿尔说道:

    大大~~想转载~~~

  15. XXX说道:

    那啥……会造成这个原因是页面撑出安全区域了,设计的锅……

  16. 业余草说道:

    看起来很6666!

  17. lyj说道:

    啥都不服,就服我旭哥

  18. meepo说道:

    技术值得一学,只是这个场景是否成立?为什么要横屏看网页呢?

  19. zhenhappy说道:

    这个情况应该比较少用到,因为正常在使用手机应该是竖屏的状态,横屏看网页的情况还是比较少的,不过不排除一些游戏的内嵌页会用到,所以这个实践还是有意义的,就是不知道具体到实际真机上效果如何

  20. 飞蛾扑火说道:

    沙发

  21. 张坤说道:

    赞一个!