寫在前面
一個詭異的 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 飛走,貼圖記下:
[caption id="attachment_1194" align="alignnone" width="169"]
border-image 2 倍圖[/caption]
[caption id="attachment_1195" align="alignnone" width="169"]
border-image 1 倍圖[/caption]
二。原因分析
又想起 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,具體見http://www.ayqy.net/temp/border-image-pop.html
在 Android 設備上發現用了 stretch 後沒有 4 條細線了,暫時認為 stretch 是可行的解決方案
但在 Chrome 設備模擬會發現細線還在(Mac 的 Chrome 也能看到細線),無論 border-image-repeat 的值是拉伸、平鋪還是重複
在 Mac Safari 下,無論是正常頁面還是「進入響應式設計模式」都看不到細線,而 iphone5s、iphone7 都看不到細線。此外,FF49 存在這個問題,但沒有 Chrome 明顯,IE11 完全沒有這個問題。那麼暫且認為這個問題是Google 家特有的,因為 Chrome 桌面版/移動版與 Android 原生瀏覽器都有,而 IOS 全家好像都沒有
此外,親測發現,細線的問題與 2 倍圖,1 倍圖無關,與圖片尺寸無關,與 fill 與否無關,與螢幕 ppi 有關,但關係不大,具體見:
-
http://www.ayqy.net/temp/border-image-pop-try.html:圖片尺寸、舊版
-webkit-、outline
只有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 絕對是最簡單粗暴的方式,值得期待
寫在最後
Android Studio 實在太慢了,懷念 eclipse,另外,感謝 @旭
暫無評論,快來發表你的看法吧