以前會碰到一個惱人的網頁設計怪問題,
要重現問題很簡單,就是調整電腦瀏覽器縮放設定(用Ctrl+滾輪,或是從瀏覽器工具列裡面選),或是調整 Windows 的縮放設定(例如顯示設定>變更文字、應用程式與其他項目的大小),只要不是 100%,網頁就會顯示得怪怪的,例如表格/儲存格的框線會粗細不一,如以下範例:


Windows,有一條橫線特別粗


macOS Monterey 接一般的 PC 螢幕,橫線跟直線都有幾條特別粗


macOS Ventura 的 Macbook Air,有幾條直線特別粗

縮放設定會影響網頁顯示

使用者自行調整瀏覽器或裝置設定(例如本例的縮放比例)而導致網頁顯示異常,常見的例如:
– 圖片變糊
– SVG 裡面的一些複雜形狀會變得怪怪的
– 影響 RWD 網頁常用的 media query 指令,放大縮小之後吃到其他 breakpoint 的 CSS
– 表格框線、塊狀元素的框線、偽元素的 px 單位形狀都會受影響,出現上圖那種線條粗細不一的情況
– 文字顯示異常,例如某些筆畫特別粗或鋸齒特別明顯之類的

但是這些在網頁前端工程界也不是什麼受主流重視、不會讓人多花時間處理,也不會有客人願意為此多花錢解決的問題。
高年薪的前端職缺要嘛是在用不同語言搞陣列反轉、排序,用不同的 framework 重構系統介面,或是折騰著引進各種工具鏈和建置流程,多半在於工程類上的成就,或是在主業非常賺錢、沾光時代紅利的公司,至於視覺跟互動性那些切版仔工作、高工時低收入又常常天降隕石的的廣告行銷等特定行業,不少大師都不屑一顧。

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 完全都長得一樣粗?
以往這種實作問題通常會使用改顏色的方法來製作,例如 的線 0.3 px,就把顏色設成 rgba(0,0,0,.3) 之類的,
或是另外再畫一個矩形當成線條,然後用 transform:scaleY(0.3) 去處理,至少看起來差不多就收工了。

寫程式的網頁課程不會講這個,因為繪圖軟體有什麼功能跟他無關,
教電腦繪圖軟體的課程不會講這個,因為瀏覽器跟 CSS 跟他無關,
教 UI 設計軟體的不會解釋這個,APP 或網頁怎麼寫是工程師的事,
總之跟之前的 圖層影像混合模式 的問題差不多,就是瀏覽器不支援而已。
那怎麼解決? 以前怎麼做現在就繼續照做,知道原因對解決問題沒有任何幫助…

解法一: 0.1px

實測文中提到的方法,改成 0.1 px,確實成功了,100% 時會強制進位顯示成 1px,放大時也還是 1px,不會再粗細不一樣了。

但是對於 3C 設備熟悉的應該會發現用這個思路邏輯來實作,是會產生其他問題的,例如 Apple Macbook/iMac 等裝置的 Retina 螢幕,以及現在一定單價之上主流的行動裝置螢幕,會把每4個甚至更多像素為一組,輸出原來螢幕的一個像素顯示的大小區域內的圖像內容(俗稱 @2x, @3x, 二倍屏、三倍屏),這樣肯定會有問題。

一看果然…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 字串)」或是關閉特定瀏覽器功能,都會導致判斷條件失準。

您目前使用裝置的 window.devicePixelRatio:

其他表格框線顯示疑難雜症

看似平凡無奇的表格/儲存格格框線,在設定 border-spacing:0border-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 已經有在訂定一些新規則,針對這種除不盡或浮點數要進位還是捨去的情況去控制,等規範出來、瀏覽器實作、使用者把瀏覽器都更新上去,應該數年起跳,只能期望下一輩入行的不用再為這種問題煩惱了。

延伸閱讀