关于去除border-image 1像素的细线的方法
CSS3提供了一个border-image的属性,这个属性可以做一些不规则的多边形边框,类似九宫格的切图,非常强大.
但是有个问题,在chrome上面,9宫格会出现一像素的细线.下面直接转一篇文章.
border-image诡异细线
写在前面
一个诡异的border-image
问题,想了很久,如下:
如果手头的设备是Android,应该能看到在泡泡边框和文本之间的4条细边,如果擅长找茬,还能发现泡泡尖角下方的那条很细的横线
对应源码如下:
<div style="background-color: silver; padding: 20px;">
<div style="border: 10px solid; border-image: url(http://www.ayqy.net/temp/popup-white.png) 20 fill repeat; width: 136px;">
<div style="padding: 15px;">可爱的popup</div>
</div>
</div>
一.问题重述
应用border-image
后,border box
与content box
之间有一圈透明细线,某些情况下border box
外也有一圈透明细线,如上面的效果
注意:ios好像没有这个问题,但好像所有Android都有,至少Android6.0有,其它设备待测试,如果手头设备有这个问题,麻烦留言告知,谢谢
border-image
相关的部分如下:
border: 10px solid;
border-image: url(http://www.ayqy.net/temp/popup-white.png) 20 fill repeat;
从2倍图上裁剪一圈20px的相框,缩到10px的border上。那么,这一圈细线是哪里来的?
P.S.为了防止bug飞走,贴图记下:
二.原因分析
又想起zxx那个铺地砖的例子:
这么比方吧,您从万科地产买了个99.5m*99.5m的毛坯房,地面要贴瓷砖,都是1m*1m的正方形瓷砖。如果是“平铺”,对不起,这1m边长的瓷砖不行,要处理!怎么处理法?很简单,每个瓷砖压成0.995m*0.995m的,这样就可以了,所以,平铺就是以完整的单元铺满整个区域。如果是重复,就直接把这1m*1m的瓷砖从一个角落一个一个的放置,放到头放不下了怎么办?直接把瓷砖从中间“咔”掉,于是最后会在房子的边角看到很多半截的瓷砖。
(引自CSS3 border-image详解、应用及jQuery插件 « 张鑫旭-鑫空间-鑫生活)
虽然不管怎么铺,理论上都不应该存在这4条细线,但计算总是受限于精度,比如scale
引起的半像素偏移,这4条线应该与之类似,问题来自浏览器实现,或者说是计算精度损耗
如果是精度的问题,平铺(round
)和重复(repeat
)都存在裁剪计算,精度损耗可能会比较严重,而拉伸(stretch
)没有裁剪计算,只有插值计算,理论上效果应该会好一些,下面尝试一下
三.解决方案
尝试用stretch
和round
在Android设备上发现用了stretch
后没有4条细线了,暂时认为stretch
是可行的解决方案
但在Chrome设备模拟会发现细线还在(Mac的Chrome也能看到细线),无论border-image-repeat
的值是拉伸、平铺还是重复
在Mac Safari下,无论是正常页面还是“进入响应式设计模式”都看不到细线,而iphone5s、iphone7都看不到细线。此外,FF49存在这个问题,但没有Chrome明显,IE11完全没有这个问题。那么暂且认为这个问题是Google家特有的,因为Chrome桌面版/移动版与Android原生浏览器都有,而IOS全家好像都没有
只有stretch
时不会出现细线,其它方式都不行
P.S.甚至考虑过用子元素的outline
盖掉细线,纯色不透明背景确实有效,半透明背景下很难准确设置outline
的色值(尤其是设计稿是几个半透明图层叠加时),而且outline
无法解决尖角下方那条细线(父元素outline: 2px solid transparent
当然不行,透明了还怎么盖)
这个问题证明了另一件事情:repeat
和round
都是从中心向两头铺的(所以才会有4条细线)
四.结论
border-image
是一个强大的属性,但很遗憾,目前其真正强大的特性还没有办法使用,虽然已经好几年过去了
目前(2016-10-22)如果非要用,建议只用border-image-repeat: stretch
,不建议使用repeat/round
,因为存在细线的问题,除非某一天Android 6.0也成为历史了
用box-shadow
、border
、border-radius
、transform
可以实现大部分相框,但border-image
绝对是最简单粗暴的方式,值得期待
最后,解决方法,使用
transform: translateZ(1px);
即可