表格框線異常變粗之謎,調整了瀏覽器縮放比例是其中原因之一
要重現問題很簡單,就是調整電腦瀏覽器縮放設定(用Ctrl+滾輪,或是從瀏覽器工具列裡面選),或是調整 Windows 的縮放設定(例如顯示設定>變更文字、應用程式與其他項目的大小),
只要不是 100%,網頁就會顯示得怪怪的,
例如表格/儲存格的框線會粗細不一,如以下擷圖:
Windows,有一條橫線特別粗
macOS Monterey 接一般的 PC 螢幕,橫線跟直線都有幾條特別粗
macOS Ventura 的 Macbook Air,有幾條直線特別粗
縮放設定會影響網頁顯示
使用者自行調整瀏覽器或裝置設定(例如本例的縮放比例),會導致網頁各種顯示異常的情況,常見的例如:
– 圖片變糊
– SVG 裡面的一些複雜形狀會變得怪怪的
– 影響 RWD 網頁常用的 media query 指令,放大縮小之後吃到其他 breakpoint 的 CSS
– 表格框線、塊狀元素的框線、偽元素的 px 單位形狀都會受影響,出現上圖那種線條粗細不一的情況
– 文字顯示異常,例如某些筆畫特別粗或鋸齒特別明顯之類的
但是這種問題,在網頁前端工程界沒人想管,不是什麼受主流重視、不會有團隊想多花時間處理研究,也不會有客人願意為此多花錢解決。
高年薪的前端職缺,要嘛在主業非常賺錢、沾光時代紅利的公司,或是在於工程面上的成就,要嘛隔一陣子就用不同語言搞陣列反轉、排序,用不同的 framework/library 重構系統程式,或是折騰著引進各種工具鏈和建置流程。
至於視覺跟互動性的工作,還有那些幫視覺設計實現夢想的切版仔、高工時低收入又常常天降隕石的的廣告行銷等特定行業,不少大師都不屑一顧。
Media query 受影響,可以簡單的計算: 例如可視區域 1440px,設定放大 150% 之後,1440/1.5=960,會把寬 960 的畫面拉大成在 1440 的螢幕顯示,還會吃到其他 media query breakpoint 如 max-width:960px 裡面的 CSS 樣式。
既然文字跟畫面元素都放大了,版面上放不下了,所以螢幕較小時才會顯示的版面先跑了出來,也很合理嘛。
但現實就是讓網頁很容易變成顯示行動裝置的那種版面。
儲存格的框線粗細不一就有點難以忍受,叫出 DevTools 來檢查,雖然 box-model 圖形顯示都是 1px,但肉眼看起來就是粗細不一
其實這問題其實不僅儲存格框線會碰到,就連使用偽元素(pseudo element)來做一些東西,完全沒用到任何 border 時也會遇到,如下方範例:
Win 10+ Google Chrome,做了四塊黑色矩形,位置放在容器的四個邊,
調整螢幕縮放會發現有些橫線變得特別粗,隨縮放比例不同,變粗的地方還會各不相同。
電腦 Firefox 瀏覽器(Version 108) 時對於放大後儲存格框線粗細不一的症狀比較輕微,但是偽元素粗細不一的情況也是非常嚴重,到 about:config 裡面把 gfx.webrender.quality.force-subpixel-aa-where-possible 的選項打開了也沒有改善。
很快找到國外有不少討論,像是 HTML Tables has a weird bold horizontal line due to border-collapse property,原因原來既簡單又困難:網頁瀏覽器沒有支援子像素渲染(sub-pixel rendering),所以 1px 的線放大之後變成 1點幾 px,但是瀏覽器顯示不出小數點後面的,所以會變成薛丁格的量子疊加狀態,可能是顯示成 1px,或直接進位顯示成 2px。
網頁要怎麼做出比 1px 還細的線?
網頁瀏覽器沒有支援子像素渲染的說法,似乎也可以解釋另一個經典問題:雖然說像素是螢幕顯示的物理最小單位,但平面設計軟體(例如 Photoshop, illustrator)可以設定框線寬度是零點幾像素,而網頁瀏覽器的 CSS 照著設定,0.6 px~0.9 px 完全都長得一樣粗?
以往這種實作問題,通常會使用改顏色的方法來製作,例如 #000000 的線 0.3 px,就把顏色設成 rgba(0,0,0,.3)
之類的,
或是另外再畫一個矩形當成線條,然後用 transform:scaleY(0.3) 去處理,至少看起來差不多就收工了。
寫程式的網頁課程不會講這個,
因為繪圖軟體有什麼功能跟他無關。
教電腦繪圖軟體的課程不會講這個,
因為瀏覽器跟 CSS 跟他無關。
教 UI 設計軟體的不會解釋這個,
APP 或網頁怎麼寫是工程師的事。
所以框線粗細問題的鍋最後是誰來背? 按照慘業慣例,看最後是誰碰到網頁的,
例如網頁是工程師敲鍵盤寫出來的,那就是工程師的鍋。
例如是設計師/工作人員用一些低代碼/無程式碼工具做出來的,那就是設計師的鍋。
或是由使用者上網發文 diss 那些網頁工具有問題、不好用…,但明明問題起因是網頁瀏覽器本身的顯示技術限制。
這可能跟之前的 圖層影像混合模式 的問題差不多,就是瀏覽器不支援而已。
那怎麼解決?
以前怎麼做,現在就繼續照做,就算知道原因,對解決問題還是沒有任何幫助…
解法一: 0.1px
實測文中提到的方法,改成 0.1 px,確實成功了,100% 時會強制進位顯示成 1px,放大時也還是 1px,不會再粗細不一樣了。
但是對於 3C 設備熟悉的,應該會想到世界上還有一票螢幕,用這個思路邏輯來實作,是會產生問題的!
例如 Apple Macbook/iMac 等裝置的 Retina 螢幕,以及現在一定單價之上主流的行動裝置螢幕,會把每4個甚至更多像素為一組,輸出原來螢幕的一個像素顯示的大小區域內的圖像內容(俗稱 @2x, @3x, 二倍屏、三倍屏),這樣肯定會有問題。
用實機測試,果然..2倍屏的設備,框線變得特別細(如下圖),3倍屏的設備(例如 iPhoneX) 框線根本細得看不見了。
而且要是未來有一天瀏覽器突然支援子像素渲染,那用一般螢幕的 Windows 使用者,也會看到網頁上的線變得超級細,搞不好又要當義工免費改網頁了。
幸好原文又提供其他的方式,繼續試試看。
解法二: 用 min-resolution 和 dpi 當 media query
這個是用 media query 來解決,拿了一個不太常用的單位來設定,專門用來對付使用者把螢幕放大時,畫面上的所有元素要怎麼顯示,例如把線段粗細數值強制寫死
@media (min-resolution: 120dpi) {
table, th, td {border-width: 0.75px;}
}
預設 100% = 96 dpi
放大到 125% = 96*1.25=120dpi
放大到 200% = 96*2=192 dpi
那第一個實作問題就是
Google Chrome 瀏覽器提供的段位是 110%, 125%, 150%, 175%, 200%, 300%, 400%, 500%,
Firefox 瀏覽器提供的段位是 110%, 120%, 133%, 150%, 170%, 200%, 240%, 300%, 400%, 500%,
Windows 10 的縮放顯示設定對某台 4K 提供的段位有 125%, 150%, 175%, 200%, 225%, 250%, 300%, 350%
(ps.有的 1080P 螢幕可能不會出現這麼多段)
雖然放大段位不是讓使用者自己輸入的,但每種瀏覽器與各種螢幕的搭配,將會造成各種不同的放大段位設定。
那 CSS 要設非常多組囉!否則只要有一種段位沒設定到,放大倍率相乘時有小數點跑出來,仍然會造成網頁顯示時線條粗細不一。
第二個實作問題是,放大的同時還是會讀到原本現有給小螢幕用的 max-width/min-width px 單位的 media query,這種陰陽對抗、CSS 權重和各種樣式覆蓋問題肯定是人腦難以承受的了,還有機會讓本來正常顯示的行動裝置出現異常。
解法三: JS 的 window.devicePixelRatio
解法三沒有要解決顯示問題,只是偵測環境,然後顯示提示,請使用者調回正常設定…
可以透過監聽 load 和 resize,用 JS 的 window.devicePixelRatio
來取得一個 DPR 數值
100% 的情況下會得到 window.devicePixelRatio = 1
放大的時候就會是其他數值,就可以把這個數值拿來用,例如針對不是 1 的情況顯示一個提示視窗,請使用者不要調整瀏覽器縮放。
但是又回到剛剛 Retina 螢幕的問題,蘋果筆電、iPad、iPhone 等設備,預設情況下會是 2 或 3,所以瀏覽網頁也會看到這些莫名其妙的提示訊息。
程式可以再加入更多條件來判斷,
但要是使用者用了「切換為電腦版網站(修改 UserAgent 字串)」,
或是關閉特定瀏覽器功能,
都會導致判斷條件失準。
其他表格框線顯示疑難雜症
看似平凡無奇的表格/儲存格格框線,在設定 border-spacing:0
與 border-collapse:collapse
之後,在現代瀏覽環境還有許多罄竹難書的問題:
- 用解法一的 0.1px 之術,如果用 Macbook 筆電,會發生電腦螢幕上看到 0.1px 超細框線的情形,那改成抓 UserAgent 來判斷作業系統? 那如果使用者用 Mac Mini 外接一塊看不出 0.1px 框線的普通螢幕呢? 情況變得更加複雜,開始要考慮去網路上尋找一些莫名奇妙的 media query….
- 如果儲存格有複雜的跨欄跨列,在 iOS Safari 會看起來有粗有細,而用 Android 手機就顯示得好好的,非常無言。
- 承上,某條儲存格線特別細,可以使用
border-top-width:1.2px
之類的方式來純肉眼對照硬調。 - 再承上,在 iOS Safari 這些肉眼上終於看似一樣粗的儲存格框線,在 Android 上卻會如實反映因為加了
border-top-width:1.2 px
而每一條粗細不一的線。 - 若某一橫排想要做固定表頭(在 Excel 叫凍結頂端列)的效果,加了
poition:sticky
,在手機雙系統都會發生框線消失的情況,iOS 甚至還沒 sticky 狀態時就看不到儲存格框線了。
這些問題跟瀏覽器縮放毫無關聯,網頁編排人員還是前端工程師請自求多福。
結論
本文探討的是放大時出現線條粗細不一的問題,還有各種解法都會衍生出更多問題。最後還是勉強用了一些 workaround,電腦上放大不會粗細不一,手機上看也不會太細或消失。
不是探討如何避免問題(必然會發生,無法避免),也不是探討畫面放大了,線是否應該跟著變粗嗎……這種視覺哲學問題。
網頁放大也能顯示正常,這會是服務差異化、高齡化社會的設計議題嗎? 我想只是白折騰而已,太多不可控制的因素了。
聽說 W3C 已經有在訂定一些新規則,針對這種除不盡或浮點數要進位還是捨去的情況去控制,等規範出來、瀏覽器實作、使用者把瀏覽器都更新上去,應該數年起跳,只能期望下一輩入行的不用再為這種問題煩惱了。
延伸閱讀
- Subpixel_rendering 維基百科對於 Subpixel_rendering 的解釋,不過其實有些會用顯微鏡去拍手機像素點的科技類 YouTuber 也談論過這些議題,但多半是探討像素點排列方式,和某些情況下螢幕顏色會什麼會發綠發紅之類的議題。
- In CSS, “px” is not an angular measurement and it is not non-linear 網頁 CSS 同樣也有 inch, cm 之類的單位,這篇研究的是探討螢幕像素是如何與 CSS 中的單位與物理世界的單位相配合。
- Sub-pixel rendering and borders – Chen Hui Jing 同樣研究比 1px 還小的小數點後面那些數字的問題。
- Sub-Pixels calculated and rendered differently among browsers – stackoverflow 在某些情況產生小數點時,邊邊會被裁掉或是蓋到外面去的情況
- chokcoco – CSS 渐变锯齿消失术 跟縮放比較無關,但是探討一種用純 CSS 實現背景圖案的方式,容易在 DPR=1 的螢幕看起來不太順眼。