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

2017-10-26  本文已影响75人  你期待的花开

iPhone X造型上有个显著的特质,就是有个明显的刘海。
然后,也出现了一些酷酷的交互。体验

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

方法一

环绕齐刘海滚动实现原理

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);
}

此时,后面没有设置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)';
});

详尽代码

CSS代码:
.box {
    max-width: 414px;
    height: 480px;
    border: solid #000;
    margin: auto;
    overflow: auto;
}
.shape {
    float: left;
    width: 30px; height: 340px;
    shape-outside: polygon(0 0, 0 150px, 16px 154px, 30px 166px, 30px 314px, 16px 326px, 0 330px, 0 0);
    transition: shape-outside .15s;
}
.liuhai {
    width: 24px; height: 180px;
    background: url(liu.png) no-repeat left center;
    position: absolute;
    margin-top: 150px;
}
.content ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.content li {
    border-bottom: 1px solid #eee;
    padding: .5em;
}
HTML代码:
<div id="box" class="box">
    <i id="shape" class="shape"></i>
    <i class="liuhai"></i>
    <div class="content">
        <ul>
            <li>为了防止看花眼</li>
            <li>我就手动敲下面的文字</li>
            <li>原本我偷懒</li>
            ...
            <li>理论上还可以使用CSS region实现</li>
            <li>但没有这个方法容易理解</li>
        </ul>
    </div>
</div>
JS代码:
var eleShape = document.getElementById('shape');
var eleBox = document.getElementById('box');
// 保证shape元素高度足够
eleShape.style.height = eleBox.scrollHeight + 'px';

var funShape = function () {
    var scrollTop = eleBox.scrollTop;
    // 滚动偏移应用在shape-outside上
    var 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)';
    eleShape.style.shapeOutside = shapeOutside;
};
// 滚动时候实时改变shape形状
eleBox.addEventListener('scroll', funShape);
funShape();

方法二

我们还可以使用shape-outside:url(image.png)语法实现类似的效果,其中'image.png'就是用来被环绕的图片,环绕与否是基于计算alpha通道决定,用句简单的话描述,就是沿着图片非透明区域环绕。

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

.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()实现需要同时改变多个坐标值。

详尽代码

CSS代码:
.box {
    max-width: 414px;
    height: 480px;
    border: solid #000;
    margin: auto;
    overflow: auto;
}
.shape {
    float: left;
    width: 30px; height: 180px;
    margin-top: 150px;
    -webkit-shape-outside: url(liu-outside.png);
    shape-outside: url(liu-outside.png);
    transition: margin-top .15s;
}
.liuhai {
    width: 24px; height: 180px;
    background: url(liu.png) no-repeat left center;
    position: absolute;
    margin-top: 150px;
}
.content ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.content li {
    border-bottom: 1px solid #eee;
    padding: .5em;
}
HTML代码:
<div id="box" class="box">
    <i id="shape" class="shape"></i>
    <i class="liuhai"></i>
    <div class="content">
        <ul>
            <li>为了防止看花眼</li>
            <li>我就手动敲下面的文字</li>
            <li>原本我偷懒</li>
            ...
            <li>理论上还可以使用CSS region实现</li>
            <li>但没有这个方法容易理解</li>
        </ul>
    </div>
</div>
JS代码:
var eleShape = document.getElementById('shape');
var eleBox = document.getElementById('box');

var funShape = function () {
    var scrollTop = eleBox.scrollTop;
    // 滚动偏移应用在margin-top上
    eleShape.style.marginTop = (150 + scrollTop) + 'px';
};
// 滚动时候实时改变shape形状
eleBox.addEventListener('scroll', funShape);
funShape();

四、CSS Shapes的兼容性

兼容性

以上参考此处

五、css Shapes 的更多应用

链接

示例
示例
上一篇下一篇

猜你喜欢

热点阅读