关于去除border-image 1像素的细线的方法

作者: TAIS3 分类: css奇技怪巧 发布时间: 2023-06-02 14:45

CSS3提供了一个border-image的属性,这个属性可以做一些不规则的多边形边框,类似九宫格的切图,非常强大.

但是有个问题,在chrome上面,9宫格会出现一像素的细线.下面直接转一篇文章.

 

border-image诡异细线

写在前面

一个诡异的border-image问题,想了很久,如下:

可爱的popup

如果手头的设备是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 boxcontent 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飞走,贴图记下:

border-image 2倍图

border-image 1倍图

二.原因分析

又想起zxx那个铺地砖的例子:

这么比方吧,您从万科地产买了个99.5m*99.5m的毛坯房,地面要贴瓷砖,都是1m*1m的正方形瓷砖。如果是“平铺”,对不起,这1m边长的瓷砖不行,要处理!怎么处理法?很简单,每个瓷砖压成0.995m*0.995m的,这样就可以了,所以,平铺就是以完整的单元铺满整个区域。如果是重复,就直接把这1m*1m的瓷砖从一个角落一个一个的放置,放到头放不下了怎么办?直接把瓷砖从中间“咔”掉,于是最后会在房子的边角看到很多半截的瓷砖。

(引自CSS3 border-image详解、应用及jQuery插件 « 张鑫旭-鑫空间-鑫生活

虽然不管怎么铺,理论上都不应该存在这4条细线,但计算总是受限于精度,比如scale引起的半像素偏移,这4条线应该与之类似,问题来自浏览器实现,或者说是计算精度损耗

如果是精度的问题,平铺(round)和重复(repeat)都存在裁剪计算,精度损耗可能会比较严重,而拉伸(stretch)没有裁剪计算,只有插值计算,理论上效果应该会好一些,下面尝试一下

三.解决方案

尝试用stretchround

在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当然不行,透明了还怎么盖)

这个问题证明了另一件事情:repeatround都是从中心向两头铺的(所以才会有4条细线)

四.结论

border-image是一个强大的属性,但很遗憾,目前其真正强大的特性还没有办法使用,虽然已经好几年过去了

目前(2016-10-22)如果非要用,建议只用border-image-repeat: stretch不建议使用repeat/round,因为存在细线的问题,除非某一天Android 6.0也成为历史了

box-shadowborderborder-radiustransform可以实现大部分相框,但border-image绝对是最简单粗暴的方式,值得期待

 

最后,解决方法,使用

transform: translateZ(1px);

 

即可

发表回复