HTML 文件圖片預設寬高比

Intrinsic aspect ratio of incomplete image

我在 2018 年有篇文章 Intrinsic Size 媒體寬高比,介紹一個標準的草案intrinsicsize,為什麼會需要這東西在那篇文章也有講,主要就是要搭配像是:

img {
  max-width: 100%;
  height: auto;
}

這種寫法非常通用,但是在圖片讀取完成前,<img />標籤的佔位會無法先知道,這會造成頁面在圖片讀取完成後瀏覽器會需要比較大的重新繪製的工作。

這幾天想起來去查了一下近況,發現竟然早早就停止發展了,caniuse 那邊 也顯示瀏覽器都把一些實驗中的支援都拿掉了,細看下去,發現 Firefox 的人當時說要開始試驗另一個比較優雅的方法,也有和 CSS WG 的人開始討論,他們當時的想法就是直接用widthheight屬性來計算寬高比(aspect ratio),不過之後就都沒有標準文件相關的發展細節或連結了。

搜尋一番後,發現 Firefox 在 71 開始就已經發佈這個修改了,當時的 release note 其實有寫,而且 MDN 上還有一篇文章:Mapping the width and height attributes of media container elements to their aspect-ratio,也有介紹這個修改要解決的問題以及技術上是怎樣處理的,簡單一點形容就是:

img { 
  aspect-ratio: attr(width) / attr(height); 
}

不過實際上不是真的使用這條 User Agent style 來實作就是了,因為這個透過widthheight計算出來的寬高比只有在圖片還沒讀取的時候會有效,圖片讀取完成後就會改成用圖片實際的尺寸來計算怎麼顯示了,所以要說它是預設的寬高比也不太正確。

在 CSS Image 這個 Module 的第四章:Sizing Images and Objects in CSS 中,有詳細的定義要怎樣決定圖片在繪製在網頁上時要怎樣處理,還定義了一些專有名詞:

  • Intrinsic dimensions 簡單一點形容就是圖片的原始尺寸,尺寸包含了寬(intrinsic width)、高和寬高比,不一定會全部都有,像是向量圖就只有寬高比,另外 intrinsic 中文翻譯是固有、或是根本的,所以 intrinsic dimentions 也不是真的就是圖片原始尺寸,它的文字敘述是:a preferred or natural size of the object itself。
  • Specified size 使用 CSS 設定的物件大小。
  • Concrete object size 根據上面兩個資訊所決定的實際上物件要繪製的大小,也就是我們眼睛所會看到的圖片呈現的大小。

所以主要就是在寫怎樣計算 concrete object size 了,大概計算過程就是和各位腦袋中想的不會差距太大。不過在這個地方,有一個細節是在 CSS 文件中故意沒有講出來的,就是怎樣取得 intrinsic dimensions,CSS 文件中沒有明確的說 intrinsic width 是來自圖片標籤的width屬性,或是圖片的實際寬度(早在 CSS 2.1 就有寫出 CSS 文件不定義怎樣取得該數值了)。其實 HTML 圖片的 intrinsic dimensions 要怎麼取得是放在 HTML 文件的 15.4.3,15 章都在講 rendering,15.4 則是 replaced elements,也就是圖片、影片之類的內容會整個替換掉的元素,15.4.3 最後一段的第一點是說圖片如果有抓下來的話就直接用圖片的 intrinsic aspect ratio,而第二點是這樣寫的:「If img'swidthandheightattribute values, when parsed using the rules for parsing dimension values), are both not an error, not a percentage, and non-zero, then use the ratio resulting from dividing thewidthattribute value by theheightattribute value.」這邊就明確的寫到用兩個屬性來計算 intrinsic aspect ratio 了,不過針對這個圖片讀取完成前的 intrinsic aspect ratio,並沒有定義一個專有名詞,所以可以看到 cnaiuse 用一個複雜的文字來敘述這項修改,要是我的話應該會把這個值命名為 intrinsic aspect ratio of incomplete image 之類的吧。

最後整理一下:

  • 圖片讀取完成前,如果有設定正確的數值的 width 和 hieght 的話,瀏覽器會先它們來計算 intrinsic aspect ratio
  • 圖片讀取完成後,瀏覽器會用圖片原始的寬高比來作為 intrinsic aspect ratio
  • 本來是希望能用在所有的 replaced elements,不過會造成既有網站壞掉所以目前限制在<img>標籤
  • 以上的修改是大約是今年前半年才進入瀏覽器的

Scroll Margin/Padding

這篇文章要介紹一組算是蠻新的 CSS 屬性,分別是 scroll-marginscroll-padding,這兩個屬性是在 Scroll Snap Module Level 1 裡面定義的,目前主要的瀏覽器都有支援,IE 完全不支援,Safari 則是還在使用舊的非標準的屬性名稱,為什麼要介紹這兩個屬性呢?因為它除了原來 scroll-snap 微調的需求之外,還順便解決了一個存在已久的問題,也就是如果網頁的設計有固定浮動在頁面頂端的 header 時(Sticky/Fixed Header),使用 link 的 fragment 直接定位到頁面特定位置的時候,最上面一部份想顯示給訪客的內容會被 header 覆蓋到。

這個問題大概是從 Sticky Header 出現時就存在了,Stack Overflow 上就可以找到十年前的發問,以前的主要的解決方法就是讓連結的目標有看不到的高度,像是用padding-top,比較乾淨一點是用 pseudo-element 的:before來把內容往下推,不過這幾個方法雖然有用,但是對我來說卻一直不是個最佳解,所以一直以來我都期待能有更漂亮的解決方案,有事沒事就會搜尋一下,然後,終於我發現了這組 CSS 屬性可以用來讓瀏覽器自己捲動到目標時有指定的偏移。

scroll-margin是用在你想要捲動到的目標元件上,也就是有 id 的那個,像我的 blog 就是<article>標籤,給它加個scroll-margin-top: 56px;就可以了:

article {
  scroll-margin-top: 56px;
}

scroll-padding則是要用在 scroll container 上的,而不是目標的父母層,舉例來說,在我這邊,沒有特別設定任何overflow的情形下,scroll container 會落在<html>元件上,而不是<article>外面的<main>,所以設定就要改成:

html {
  scroll-padding-top: 56px;
}

這組 CSS 屬性我是今年才發現的,不過其實 CSS Trick 在去年就有文章介紹了:Fixed Headers, On-Page Links, and Overlapping Content, Oh My! ,真是太後知後覺了(其實也是因為我現在沒用 RSS reader 的關係)。



更之前的文章