怎麼畫一條0.5px的邊(更新)

(文章有更新,添加了SVG方案的討論以及transform的方法是能夠的)

什麼是像素css

像素是屏幕顯示最小的單位,在一個1080p的屏幕上,它的像素數量是1920 * 1080,即橫邊有1920個像素,而豎邊爲1080個。一個像素就是一個單位色塊,是由rgba四個通道混合而成。對於一個1200萬像素的相機鏡頭來講,它有1200萬個感光單元,它能輸出的最大圖片分辨率大約爲3000 * 4000。html

那麼像素自己有大小嗎,一個像素有多大瀏覽器

有的,若是一個像素越小,那麼在一樣大小的屏幕上,須要的像素點就越多,像素就越密集,若是一英寸有435個像素,那麼它的dpi/ppi就達到了435。Macbook Pro 15寸的分辨率爲2880 x 1800,15寸是指屏幕的對角線爲15寸(具體爲15.4),根據長寬比換算一下獲得橫邊爲13寸,因此ppi爲2880 / 13 = 220 ppi. 像素越密集即ppi(pixel per inch)越高,那麼屏幕看起來就越細膩越高清。bash

在Mac/Windows上能夠設置屏幕顯示的分辨率,Mac默認爲設備分辨率的一半,它的dpr = 2,即長和寬用2個像素表示1個像素,因此2880個物理像素點實際上只表示1440個邏輯像素:iphone

那麼咱們的問題來了,怎麼在高清屏上畫一條0.5px的邊呢?0.5px至關於高清屏物理像素的1px。這樣的目的是在高清屏上看起來會更細一點,效果會更好一點,例如更細的分隔線。svg

大漠在《再談Retina下1px的解決方案》已經討論過這個問題,這裏咱們再理一理思路。工具

理論上px的最小單位是1,可是會有幾個特例,高清屏的顯示就是一個特例。高清屏確實能夠畫0.5px,對比效果以下:測試

若是咱們直接設置0.5px,在不一樣的瀏覽器會有不一樣的表現,使用以下代碼:ui

<!DOCType html> <html> <head> <meta charset="utf-8"> <style> .hr { width: 300px; background-color: #000; } .hr.half-px { height: 0.5px; } .hr.one-px { height: 1px; } </style> </head> <body> <p>0.5px</p> <div class="hr half-px"></div> <p>1px</p> <div class="hr one-px"></div> </body> </html>複製代碼

在PC上的不一樣瀏覽器上測試測試結果以下所示:url

其中Chrome把0.5px四捨五入變成了1px,而firefox/safari可以畫出半個像素的邊,而且Chrome會把小於0.5px的當成0,而Firefox會把不小於0.55px當成1px,Safari是把不小於0.75px當成1px,進一步在手機上觀察IOS的Chrome會畫出0.5px的邊,而安卓(5.0)原生瀏覽器是不行的。因此直接設置0.5px不一樣瀏覽器的差別比較大,而且咱們看到不一樣系統的不一樣瀏覽器對小數點的px有不一樣的處理。因此若是咱們把單位設置成小數的px包括寬高等,其實不太可靠,由於不一樣瀏覽器表現不同。

第二種能想到的方法是縮放,可否設置1px,而後scale 0.5呢,咱們能夠嘗試一下,以下代碼所示:

<style> .hr.scale-half { height: 1px; transform: scaleY(0.5); } </style> <p>1px + scaleY(0.5)</p> <div class="hr scale-half"></div>複製代碼

效果以下圖所示:

咱們發現Chrome/Safari都變虛了,只有Firefox比較完美看起來是實的並且還很細,效果和直接設置0.5px同樣。因此經過transform: scale會致使Chrome變虛了,而粗細幾乎沒有變化。可是若是加上transform-origin: 50% 100%:

.hr.scale-half {
    height: 1px;
    transform: scaleY(0.5);
    transform-origin: 50% 100%;
}複製代碼

你們就都變實了,很完美,Chrome的效果以下(感謝@默語摸魚的指正):

除了這個方法以外,咱們還想到作移動端的時候還使用了rem作縮放,但實際上rem的縮放最後仍是會轉化成px,因此和直接使用0.5px的方案是同樣的。


還有什麼辦法呢?還能夠用線性漸變linear-gradient,以下代碼所示:

<style> .hr.gradient { height: 1px; background: linear-gradient(0deg, #fff, #000); } </style> <p>linear-gradient(0deg, #fff, #000)</p> <div class="hr gradient"></div>複製代碼

linear-gradient(0deg, #fff, #000)的意思是:漸變的角度從下往上,從白色#fff漸變到黑色#000,並且是線性的,在高清屏上,1px的邏輯像素表明的物理(設備)像素有2px,因爲是線性漸變,因此第1個px只能是#fff,而剩下的那個像素只能是#000,這樣就達到了畫一半的目的。邏輯分析很完美,實際的效果又怎麼樣呢,以下圖所示:

咱們發現這種方法在各個流覽器上面都不完美,效果都是虛的,和完美的0.5px仍是有差距。這個效果和scale 0.5的差很少,都是經過虛化線,讓人以爲變細了。

還有另一種方法,使用boxshadow,以下代碼所示:

<style> .hr.boxshadow { height: 1px; background: none; box-shadow: 0 0.5px 0 #000; } </style> <p>box-shadow: 0 0.5px 0 #000</p> <div class="hr boxshadow"></div>複製代碼

設置box-shadow的第二個參數爲0.5px,表示陰影垂直方向的偏移爲0.5px,效果以下:

這個方法在Chrome和Firefox都很是完美,可是Safari不支持小於1px的boxshadow,因此徹底沒顯示出來了。

還能夠使用SVG,利用SVG的描邊等屬性的1px仍是物理像素的1px,而不是高清屏的1px。以下代碼所示:

<style> .hr.svg { background: none; height: 1px; background: url("data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1px'><line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line></svg>"); } </style> <p>svg</p> <div class="hr svg"></div>複製代碼

設置background爲一個svg文件,這個svg單獨拷出來是這樣的:

<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1px'>
    <line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line>
</svg>複製代碼

使用svg的line元素畫線,stroke表示描邊顏色,默認描邊寬度stroke-width="1",因爲svg的描邊等屬性的1px是物理像素的1px,至關於高清屏的0.5px,另外還可使用svg的rect等元素進行繪製。在Chrome和Safari的效果以下:

這個方案也是很完美,可是在firefox掛了,究其緣由是由於firefox的background-image若是是svg的話只支持命名的顏色,如"black"、"red"等,若是把上面代碼的svg裏面的#000改爲black的話就能夠顯示出來,可是這樣就很不靈活了。不然只能把svg轉成base64的形式,咱們把svg的內容轉成base64(能夠找一些在線的工具),對好比下:

.hr.svg {
    background: url("data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1px'><line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line></svg>");
    background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMDAlJyBoZWlnaHQ9JzFweCc+PGxpbmUgeDE9JzAnIHkxPScwJyB4Mj0nMTAwJScgeTI9JzAnIHN0cm9rZT0nIzAwMCc+PC9saW5lPjwvc3ZnPg==");
}複製代碼

這樣在firefox也能完美展現了。

其實0.5px的需求在移動端應該會更常見,比較一下以上五種方法在IOS和安卓的表現,以下圖所示:


IOS下的Safari和Chrome表現一致,都是以直接設置0.5px的效果最好,而安卓瀏覽器則是以box-shadow的效果最好(試了5和7),而svg/transform的方案在IOS和安卓的設備上都能完美支持。讀者能夠打開這個網頁,看一下在你的設備是哪一種效果最好。

結合以上,咱們初步獲得如下結論:



使用SVG相對於box-shadow等方法,還有一個好處是能夠藉助svg的元素畫出任意圖形,如四邊形,圓角等。


最後還有一個萬能的方法,那就是經過控制viewport,在移端開發裏面通常會把viewport的scale設置成1:

<meta name="viewport" content="width=device-width,initial-sacle=1">複製代碼

其中width=device-width表示將viewport視窗的寬度調整爲設備的寬度,這個寬度一般是指物理上寬度。默認的縮放比例爲1,如iphone 6豎屏的寬度爲750px,它的dpr=2,用2px表示1px,這樣設置以後viewport的寬度就變成375px。這時候0.5px的邊就使用咱們上面討論的方法。

可是你能夠把scale改爲0.5:

<meta name="viewport" content="width=device-width,initial-sacle=0.5">複製代碼

這樣的話,viewport的寬度就是本來的750px,因此1個px仍是1px,正常畫就行,但這樣也意味着UI須要按2倍圖的出,總體面面的單位都會放大一倍。

在iPone X和一些安卓手機等dpr = 3的設備上,須要設置scale爲0.333333,這個時候就是3倍地畫了。


綜上討論了像素和viewport的一些概念,並介紹和比較了在高清屏上畫0.5px的幾種方法——能夠經過直接設置寬高border爲0.5px、設置box-shadow的垂直方向的偏移量爲0.5px、藉助線性漸變linear-gradient、使用transform: scaleY(0.5)的方法,使用SVG的方法。最後發現transfrom scale/svg的方法兼容性和效果都是最好的,svg能夠支持複雜的圖形,因此在viewport是1的狀況下,可使用transform/SVG畫0.5px,而若是viewport的縮放比例不是1的話,那麼直接畫1px便可

相關文章
相關標籤/搜索