在移动端web开发中我们经常会碰到半圆形锯齿分隔线设计,如下图红色框部分,这其实是模拟了真实场景中的纸质账单。
需要特别提醒的是,整个卡片是有阴影的,所以分隔线部分也需要有阴影效果。可能很多同学会说:这个还不好实现,直接让UI切个图不就行了。实践证明这种方法是可以,但是会有一点小问题:1)半圆形锯齿分隔线需要带阴影切图,此时切图的阴影效果和上面卡片采用css方式实现的阴影效果可能会有些差别;2)带阴影的切图左右两边和卡片左右阴影对齐不容易,特别是自适应各种手机屏幕宽度时。当然上述两个问题通过多次微调和测试也许是可以解决的。
本着能用CSS解决的问题尽量不借助图片的原则(非行业标准,仅个人喜好),我们来思考下,这种效果是否可以使用CSS完美解决。
1、实现半圆形
CSS画半圆是完全没问题的,也相当容易实现。以本例设计稿尺寸,半圆直径6px,相邻半圆间距为2px。直接给出代码
.
2、实现多个半圆横向排列
这一步也很简单,使用flex布局,代码如下
<
至此我们基本已经实现了一行间距为2px的半圆组合成的分隔线
3、实现分隔线阴影
分隔线阴影我们可以使用渐变色来模拟,由于形状是半圆,所以我们采用CSS radial-gradient函数来创建由原点(渐变中心)辐射开的颜色渐变。通过取色器,取得卡片阴影最深色和最浅色分别为:#ECEDED、#EFF0F0,代码如下:
.
注意:渐变需以圆心为中心点,从最浅色“#EFF0F0”,经圆形径向渐变至最深色“#ECEDED”。由于是半圆,所以需要设置底部(bottom)为径向渐变圆心的纵坐标值,这样才能实现分隔线阴影沿着每个半圆形锯齿的边缘均匀铺开。为方便清晰看到模拟的效果,我将其中一个半圆渐变色做了调整,如下图
详细参数说明参见: 渐变函数
4、定位至卡片底部
由于我们直接将分隔线代码块放在了卡片容器内部的最后,且卡片高度是随内容高度自动伸缩的,所以无需特殊处理,分隔线就已经在卡片底部了。如果卡片高度固定的场景,可以采用下面绝对定位的方式处理。
.item-wrapper{
position: absolute;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
width: 100%;
bottom: 0;
}
注意:item-wrapper增加了绝对定位,要清楚绝对定位的元素的位置相对于最近的已定位祖先元素,如果元素没有已定位的祖先元素,那么它的位置相对于body。所以我们还要给卡片div增加一个相对定位属性,同时注意增加“overflow: hidden”隐藏掉超出卡片宽度的分隔线。
最终代码如下:
<div class="card">
<div class="item-wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
...
</div>
</div>
body{
background-color: #F4F4F4;
}
.card{
position: relative;
width: 300px;
height: 300px;
background: #FFFFFF;
box-shadow: 0 1px 4px 0 rgba(0,0,0,0.04);
overflow: hidden;
}
.item-wrapper{
position: absolute;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
width: 100%;
bottom: 0;
}
.item{
flex-basis: 6px;
flex-shrink: 0;
flex-grow: 0;
height: 3px;
border-radius: 6px 6px 0 0;
margin: 0 2px;
background: radial-gradient(circle farthest-side at bottom, #EFF0F0, #ECEDED)
}
5、抽象成组件
考虑到复用性,可以将上述半圆形锯齿分隔线抽象成组件。
组件可接收三个参数,1)半圆图形的个数count;2)阴影最深色deepColor;3)阴影最浅色lightColor。有这三个参数的控制,就可以根据count自动生成对应数量的div.item,适配不同宽度的卡片,同时deepColor、lightColor的自定义可以适配卡片的不同阴影。
// /components/EndSplitLine/index.js
组件实现代码此处就不再赘述,有兴趣的同学可以参考:React封装的demo。组件路径为/src/components/EndSplitLine,运行效果图如下:
结束语
本文只是提供一种使用CSS特性模拟一些特殊效果的思路,CSS远比我们想象的要强大,只要我们仔细分析问题,一定能找到一种相对完美的解决方案。
能用CSS解决的问题尽量不借助图片!(当然也要看实现成本、运行效率等权衡取舍,万事无绝对^_^)
本例实测,如果采用图片的话,在手机端页面加载时,有时会出现分隔线图片后于其他页面元素加载的情况,体验不太好。而采用CSS方式实现,以目前手机性能,生成的div.item元素即使很多的情况下表现依然很好。