微軟正式宣布 Internet Explorer (簡稱 IE 瀏覽器)將於 2022/6/15 停止支援,(the Internet Explorer 11 desktop application will be retired and go out of support on June 15, 2022, for certain versions of Windows 10),但不確定到了那天會發生什麼事,會像 Flash Player 一樣完全無法使用? 網頁設計人員似乎對此都歡欣鼓舞,覺得以前不能用的 CSS 寫法,以前不能用的 JS 寫法、以前不能用的 HTML 元素像 detail&summary,現在可以全部解禁、大用特用了,打包都不用加 babel 了,但真的是這樣嗎?

IE 死後讓我們迎接被國外戲稱新 IE 的…Safari 瀏覽器,本文先不討論 macOS 上的桌面版 Safari,主要著重在行動裝置端的 iOS 與 iPadOS。
寫這篇文章的時候,iOS16 連 beta 版都還沒出來,可能在幾個月後的 WWDC 才會發表,在討論之前先來看一下 Apple 官方的數據adoption rate,有多少比例的蘋果行動裝置沒有升級到最新的作業系統? iPhoe 大約有六七成,iPad 只有五六成。

ios adoption rate 2022/05

Safari 為何成為新的瀏覽器界毒瘤?

  1. iOS/iPadOS 裡的瀏覽器都只是換皮的 Safari
    說法來自之前 Apple Stores Review 的一行字,Apps that browse the web must use the iOS WebKit framework and WebKit Javascript,今年看的話是 2.5.6 Apps that browse the web must use the appropriate WebKit framework and WebKit Javascript。瀏覽器當然也是一個 App,這讓 Apple 行動裝置端裡的 Google Chrome 簡單來說只是換皮的 Safari,骨子裡的網頁引擎還是與 Safari 相同,Safari 不能用的東西換瀏覽器也不會變成能用。
    當然 Android 作業系統也不是完美的,像使用者就是不更新 Google Play Store 裡面的 Android System WebView,導致很多瀏覽器 bug 或安全性問題沒辦法更新? 或是有些 Android app 包了一整套自己的瀏覽器,導致 app 特別大包? 但是 Apple 的應用程式政策,跟其他政策一起,就產生了各種玩弄網頁開發者的化學反應。
  2. 瀏覽器版本=作業系統版本
    Safari 瀏覽器必須要跟作業系統一起更新,沒辦法獨立安裝更新,要是使用者就是不更新手機的作業系統,那所有需要仰賴網頁瀏覽器運作的東西,都有機會無法正常顯示或使用。
  3. 跟其他瀏覽器不一樣
    例如同一個網頁在 Google Chrome 跟 Firefox/Sarafi 長得不一樣,肯定是 Firefox/Safari 出了 bug? 其實這問題很複雜,諸如 PWA 之類的有些是系統不開放,有的真的是 Google Chrome Android 老早就能用,但 iOS Safari 就是一直到近一兩年才開始支援,有時候反而有問題的是 Google Chrome,總之跟 Google Chrome 不一致的一些網頁顯示方式與執行結果,容易會被開發者或使用者覺得是 bug,也許每個問題背後都有很多歷史淵源,但時間流速特別快的軟體/網路資訊產業哪有這個時間去關心呢? 趕快把需求做完才是真的。

以下介紹10個,就算完全不考慮 IE,在現在主流瀏覽器 仍然有機會造成網頁顯示、操作互動上有問題的 CSS 或 JS

scroll-margin

這個 CSS 屬性是對於有卷軸 scrollbar 的元素,可以設定一個相對於容器的外邊距數值,有 margin 當然也有 scroll-padding。
例如頁面上緣放了個 position:fixed 的導覽列之類的,然後點擊錨點連結後,網頁會移動到指定位置,但那個位置上緣內容會被導覽列蓋住。

在以往要再用其他方法去調整,例如用 JS 控制點擊連結時、網頁載入時,錨點正確應該捲動到的位置,非常麻煩,但改用 scroll-margin 只要加一行 css 就好
:target{scroll-margin-top:40px;}

40px 是要留的距離,但這麼方便的玩意要等到 iOS14.5 才有用,如果高度是會變動的,就只能再用另外的做法。

Scroll-behavior

承上,需要點擊同頁的錨點時,頁面有個平順的移動效果,不要瞬間跳到錨點位置?
Scroll-behavior 就是為此而生的,只要加一段 CSS :root{scroll-behavior: smooth;} 就能輕鬆擁有此效果,不用像以前用 jQuery Animate 和增加一堆 preventDefault 去控制卷軸區域的點擊和動態效果。

這個好用的東西可以輕易使用嗎? 多災多難的網頁開發環境當然不行啊!
Google Chome 跟 Microsoft Edge 的 chrome://flags#smooth-scrolling 設定預設值是 Default,Scroll-behavior 不會有作用,要請使用者改成 enabled,重開瀏覽器,才會有作用。
iOS Safari 預設就是打開的(也可以自己到 Safari 的設定裡面去關閉),不過要到iOS 15.4 才開始支援,真是姍姍來遲。為了保險起見,這效果還是用 JS 控制吧。

aspect-ratio

例如一個 iframe 放了一塊 16:9 的影片,寬高各設定 1200px 與 675px,當使用螢幕可視區域寬度小於 1200 時,使用 max-width:100%,沒有意外的話影片的寬度會隨著容器縮小,但高度卻還是 675,那要怎麼讓影片跟著 1200比675 的比例縮小? 這時候 aspect-ratio 就派上用場了。

不過可惜,這東西在 iOS15 起才支援,為了避免有人說嵌入影片在手機上留很多黑邊,以及一些 div 設背景圖而且還要照圖片長寬比縮放的,padding-bottom, 雙層容器 video-container 之類的祖傳技法還是用好用滿吧。

background-attachment:fixed

要讓背景圖固定不要捲動,在以往 IE 的時代非常簡單,只要一行簡單的 css 屬性就能辦到,但這玩意在 iOS 上卻毫無作用,常見的解法只能另外用 div 或偽元素設背景圖,然後上個 position:fixed 來實現,甚至到了近代的 parallex scrolling 視差滾動之類的又有更複雜的作法。

當初 iPhone/iPad 為什麼要封印這個功能? 網路上找不到明確的蘋果說明,只有名人 Paul Irish 在10幾年前 的一條推文,說那個固定背景會造成巨大的重繪成本,並降低網頁捲動的效能。
Android 上的 Samsung Browser, Google Chrome 則是一直都支援的,但 Apple 即使到了 iOS15,支援 ProMotion 的設備越來越多、硬體效能越來越強了,這個 CSS 功能還是沒開放出來。因為很耗效能所以把這個功能封印起來,網頁開發者就不會使用了嗎? 客戶就不會要求了嗎? 也沒有啊,網路上到處都是如何在 iOS 上實現此效果的教學。

rem 單位

如果網頁上有各種大大小小的文字或區塊大小、距離,有 RWD 的網頁設計需求,或是像政府機關的網站常常有那種放大文字的功能,有時候用 em 單位相比傳統的 px 單位更好用,螢幕尺寸變動時,可以更快將所有 em 單位的字或區塊大小、距離一起放大或縮小。
但 em 單位容易因為多包了幾層父層容器而樣式走鐘,或是複製貼上來的內文區有一行 body{font-size:….},而整個爆掉,使用 rem 單位可以更安全的達成此用途。
rem 不算特別新的東西,主流行動裝置瀏覽器跟 IE11 也支援,但有支援跟能否正確顯示,則是完全兩碼子事。例如使用一些沒有更新到 iOS14.4 以上的 iPhone 和 iPad,瀏覽一些網站,例如 QuorbleMaster Styles,可以發現畫面有些異常…

iOS rem error

鍵盤的字母歪掉了,或是範例程式碼的行距跟其他瀏覽器顯示得不一樣?
看似常見的 CSS 排版需求,一個垂直水平置中、一個控制容器高度,難道這網頁用了什麼特殊的寫法嗎?
一查發現,這兩個網頁有個共通點,都用了 rem 單位!
一個文字外層容器用了 line-height:1.5rem,一個用了 button tag 用了 width: calc(10% – 0.25rem)
反正作業系統升級就正常了,沒有去深究他的 root font-size 到底是怎設定的,總之…


奇異博士2預告片

WebP 圖片格式

Webp 圖片格式兼具 gif 動圖、png 透明通道的功能,但是不普及的原因有很多,除了 Photoshop 在 2022/2 的 23.1 版本才內建了儲存為 webp 格式功能,而且選項是擺在另存圖片,而不是網頁圖片較常用的「轉存為」或「儲存無網頁用(舊版)」裡面,
網站系統要另外再修改伺服器 MIME、圖片上傳程式,檔案產生機制、載入圖片的方式、嵌入圖片的語法。
但最大的問題無疑是瀏覽器相容性! 如此大費周章產生一種新的格式圖片,但是瀏覽器竟無法顯示!

不只 IE11 無法顯示 WebP,iOS Safari 也要到版本 14 起才開始支援,關於 WebP 的愛恨情仇在之前的文章 使用 WebP 圖片不一定能提升跑分,還可以讓相關服務業者賺大錢 內已有提及,不再贅述。

backdrop-filter

backdrop-filter 有一套基本的效果,例如 blur 可以用來做一個簡單的模擬毛玻璃效果,會自動把遮蓋住的區域作霧化處裡,完全不需要自己計算捲動區域什麼的,下圖左邊是它的效果:

黑條區域設定了
background:rgba(0,0,0,.5);backdrop-filter: blur(3px);

這個效果在 iOS9 Safari 很早的版本開始就一直支援的,Google Chrome 76 開始也支援,但很不巧,還是有瀏覽器不支援,左邊是有支援的瀏覽器顯示的樣子,右邊是不支援的。
那右邊這個跟 IE 一樣不支援的瀏覽器到底是誰? 就是 2022/5 發布的 Firefox 版本號100 啦! 因為 Firefox 有畫面顯示有破圖或閃動之類的 bug,現階段仍需要靠使用者自己手動開啟瀏覽器設定才行。(How to enable backdrop-filter in Firefox)

flexbox 的 gap

如下面一個簡單的網頁版面範例,要把它做成真的網頁,

用 flexbox 排的話,要想像網頁上所有東西都要變成矩形:
藍色矩形外圍的寬度是多少? 數值還是百分比?
X 跟 Y 的數值各是多少?
Y是固定數值? 還是百分比?
Y是1.5%的話,x 是 100 – 1.5*2,然後再除以3,所以 x 是不能整除的 32.33%
螢幕大於多少的時候,第 1,4,,7,10 個項目… 不要有左邊距,寫成 nth-child(n) 算式的話是…,第 3, 6, 9, 12 個項目…不要有右邊距,寫成 nth-child(n) 算式的話是…
然後螢幕大於多少的時候,變成一排兩個的時候。奇數個項目不要有左邊距,偶數個項目不要有右邊距,寫成 nth-child(n) 算式的話是…

用 gap 的話不用這麼麻煩,根本不用考慮什麼最左邊、最右邊? 只要幾個屬性就可以排出來
.list{display:flex;flex-wrap: wrap;gap:2%}
.list>.item{width: 32%;}

要等到 iOS 14.5 開始才支援 gap,所以在不認識 gap 的瀏覽器上面,y 的值就歸零,東西通通黏在一起囉!
相較之下,用 display:grid 在 iOS 的相容性可能還比較高,大部分的屬性只要 iOS12 就支援了,也不用特別加 -webkit 之類的 vendor prefix。

Optional chaining(可選串連)

由於網頁程式開發的發展,現在很流行在使用者的瀏覽器上(client side)處理整坨陣列,用 MDN 的官方範例
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const dogName = adventurer.dog.name;
console.log(dogName);

這種寫法,當 adventurer 裡面沒有 dog.name,這時候 IE11, iOS Safar 13.3 就會直接 JS 報錯「無法取得未定義或 Null 參考的屬性 ‘name’」之類的,然後網頁上後續的 JS 程式整組壞光光無法執行。
古典的保險作法是每次要取用值的時候,寫一堆判斷 null 或 === ‘undefined’ 的,或是直接包 try catch? 若當網頁上的 dog 有幾十項 name, gender, city…拉哩拉雜的欄位,這些判斷的東西將讓整個網頁程式碼變得又臭又長。

但在支援 Optional chaining 的瀏覽器,只要多加一個問號 const dogName = adventurer.dog?.name;
console.log(dogName) 就會得到 undefined ,較輕鬆進行處理。
在以下這種情況也能用,當 data-city 的屬性壓根不存在的時候,再也不會 Cannot read properties of null 讓 JS 整段壞光光。
console.log(document.querySelector('.box').getAttribute("data-city")?.includes("xx"));//得到undefined
console.log(document.querySelector('.box').getAttribute("data-city")?.indexOf("xx") == -1);//得到false

諸如此類的玩意還有 iOS13.4 起支援的 Nullish coalescing,只要寫成這樣
console.log("dogName:"+(dogName?? "mimi"));
就可以給個預設值,但要小心不要因為預設值,讓本來發生例外不應該執行的程式卻被執行到了。

使用者會不會用 iOS13.3 的設備來開網頁? 誰知道呢!
為了避免在比較舊的 iOS Safari 上面爆掉,只能盡量多花時間做一些處理。雖然蘋果裝置的作業系統支援時間都很長,但仍會碰到有些機器太耐用,想升級也升不了,如果不幸碰到 相容於 iOS 14.7 的 iPhone 機型相容於 iPadOS 14.6 的 iPad 機型 以外的裝置,只能自求多福。

CSS Paint API

例如我們要網頁上放一個類似小米 logo 那種比較溫潤的圓角?

小米 logo 曲率
小米花二百万的Logo设计成这样!雷军的钱花的值不值?

這圓角肯定不是普通的單一曲率 border-radius 能做出來的,那這種連續曲率(Curvature continuous)的圓角要怎麼實現? 在網路上找到一個用程式碼實現出來的範例,該作者提供的案例看起來非常棒,引用檔案之後,還可以透過 css Variables 直接改圓角大小。


如何使用CSS Paint API实现超级圆角效果原作者效果DEMO

但是在 iOS15.4 內,右邊的圓角都變成了四四方方的直角? 仔細研究一看作者使用了 CSS Paint API 來畫圓角,不只 iOS 15.4 不支援,電腦 Firefox 也不支援。

看來還是用最直接的做法,把整張稿轉成一張圖最保險,或是考慮用 mask-image 把圖片外框切掉,例如:
‵mask-image: url(mask-mi.svg);mask-size: contain;mask-repeat: no-repeat;mask-position: center;`

但是 IE 不支援 mask-image,而且有一種實務情況,客人想要微調的時候,想要看看圓角更圓一點或是方一點的效果,就要做很多張遮罩圖來替換,就很花時間。

結論

本文提及內容的部分範例放在 old browser css/js test,手上一些 iOS12, 13, 14 老設備的可以打開看看跟 iOS15 的差異。

本文所介紹的東西在 IE11 通通無法使用,而多半是電腦/手機 Google Chrome 老早就支援,所以就算 IE 死了之後,網頁前端被封印的地雷寫法還是非常多,除了上述列的,還有:
– Safari 經典的 body overflow:hidden 問題、100vh 問題、-webkit-fill-available 不能跟 calc 合併使用的問題…
– iOS12.2 起的 text-underline-offset,比較不用擔心設計稿的超連結底線位置,跟網頁做出來的不一樣。
– iOS13.4 開始支援的 min(), max(), clamp(),程式碼是簡潔了,但易讀性就不好說。
– iOS14 起的 :is() / :where() 選擇器(之前叫 :matches),雖然習慣用 SCSS Nesting,有沒有這個好像比較沒差。
– iOS15.4 起支持可以從子層反選到父層元素的 :has() 選擇器,但 Google Chrome 還沒預設開啟。
– iOS15.4 起支持的 @layer,以後查一個東西被哪些樣式影響到,除了算權重、找 framework 是不是設了 !important,又多了一種變因,非常好
– iOS15.4 都還不完整支援的 input type=month 和 input type=week,有的是點了不會跳出選擇器,有的是連正常 input 的樣式都跑不出來
– 文章發布後過幾天的 Google I/O 大會也發表了一些瀏覽器可能將會支援的 CSS 新玩意State of CSS 2022,前端踩雷之路還在持續。

到底是以前寫網頁比較爽,基本幾乎不用考慮不同螢幕尺寸/瀏覽器/裝置類型的問題,還是現代寫網頁比較爽,新的工具一直出來,但很容易又跟舊的開發環境或瀏覽環境不相容,這種問題基本上沒啥意義,反正又回不去了!
如果有人帶著一個現代的網頁回到10幾年前,用當時的網頁瀏覽器打開,版面肯定也是跑版得亂七八糟,JS 也是一堆報錯的。