Static Site Hosting 服務需求

前陣子研究了一下用 GCP 來放靜態網站,那時候有整理了一下需求,這篇文章把需求的緣由也整理出來,先說在前面,這些需求並不是要求單一家服務就可以達成所有目標,內文也盡量不提到特定服務,所以不同服務要怎樣達到這些需求就有賴各位自行研究了。

支援 CDN

這個需求沒什麼好說了吧。

支援 HTTP/2

主要的服務應該都支援了,不過還是列一下。

支援加上 Security Headers

現在大家對於安全性的要求很高,所以可以加上 security headers 對我來說已經是一個必備的功能了,像是 CSP、HSTS 等,這項需求看廣一點,其實就是要自定義回傳 header 的功能,如果可以根據路徑調整就更好了,基本上應該只有 HTML 文件本身需要這些 header。

支援 HTTP 轉成 HTTPS

在各家瀏覽器的推波助瀾之下,不支援 HTTPS 的網站感覺就是次一等了,所以把 HTTP protocol 的 traffic 全部轉到 HTTPS 這件事情我也列為必備,有兩種支援的方式,一種是服務內建支援 protocol 轉址,這種最好,因為它會保留請求的路徑(path),而不是把訪客導到首頁,另外一種就是用下面要提到的全站轉址的方式來達成。

雖然我自己是都會把 HTTP 轉到 HTTPS,不過看網站目標,也還是有可能需要繼續支援 HTTP 的。

支援全站轉址

主要的需求是把www.example.com轉址到example.com,或是反過來,像www.apple.com那樣,當然最好還能保留請求的路徑,這個看似很基本的設定,其實現在還蠻常會發現有網站沒做到這件事,尤其是台灣的,我真的是黑人問號?_?

除了 host name 的轉換之外,還有一種情形是需要把整個網站的 request 都轉到某個 URL,例如docs.example.com要關站,然後要把流量都轉到https://example.com/docs

以下算是非必備的需求

支援把 404 改寫成 200

非 SSR 的 SPA 然後配上 route 的話,會有個問題就是除了首頁的 route 都會 404,雖然一般可以用 error_document/not_found_page 之類的設定來讓內容可以正確呈現,但是 404 的 status code 還是會有不少問題,一來是影響搜尋引擎的結果,二來是不知道是不是所有瀏覽器都還會正確的處理 404 時的網頁內容,所以最好還是能回正確的 status code,可以辦到這件事的方法就我所知道的也是有兩種,一種是 rewrite 機制,另外一種就是可以寫程式處理 request/respone 的,像是 Lambda@Edge 那樣。不過在處理這個功能時要是直接全部的路徑回應都變 200 其實也不太好,要完美有點麻煩啊。

支援 CORS

如果會有需要靜態的 JSON 檔案,然後跨網域直接抓下來當資料使用,那就會需要支援 CORS header,和上面自定義回傳 header 那一項不太一樣的是,CORS header 其實是有互動而不是寫死的,應該是要根據 request 的 header 內容來改變回傳的 CORS header,如果需要 preflight request 那還要支援 OPTIONS method 和相對應的回應,不過如果單純只是靜態 JSON 檔案,靠自訂回傳 header 的功能直接寫死應該也是夠用了。

支援 Basic Auth

如果有尚未公開的網站,還是希望至少有個基本的保護,Basic Auth 只是其中一種方法。

支援根據 Header 切換 origin

這個需求的來源就是用手機的訪客可以看到手機版網頁,用桌上型電腦的訪客看到桌面版網頁,然後網址想要維持一致而且兩種版本的網站想要分開開發,不一定會有這個需求。然後不得不說,AWS 的CloudFront-Is-*-Viewerheader真是蠻方便的,不過他們沒洩漏過判斷方式,Cloudflare 則是只有企業方案有支援,但是有提供他們如何判斷 device type。

支援根據路徑切換 origin

如果有特定路徑下的網頁是另外開發的,有支援這個功能的話就會比較好處理,一個比較常見的情境是開發文件的 API spec 是用其他工具或服務產生的,例如用 OpenAPI 文件產生的那種就很常見,或是有些語言也都有常用的文件產生工具,例如 Python 的 Sphinx。

支援 brotli

Google 開發的壓縮格式,對文字資料的壓縮表現比以前主流的 gzip 還好,主要的服務應該都支援了,不過還是列一下。


MacOS 我的設定

最近因應新工作買了台新的 M1 Mac mini,所以重新把常用設定弄了一下,這篇文章來紀錄一下。

Mac OS Preference by othree

首先是 一般 裡面的顯示捲軸(scrollbar),預設的設定是 自動依據滑鼠或觸控軌跡板 ,這個選項的意思是,如果你用的是蘋果的滑鼠或觸控板,那他就會用自動隱藏的那種捲軸,如果有其他品牌的外接游標控制設備,那捲軸就是傳統的,有得捲動時就是會一直出現在那,佔據一塊空間,其實我對於這個預設行為有疑惑很久了,為什麼其他品牌的滑鼠就一定要用傳統的捲軸模式?直到某一天在系統篇好設定亂逛的時候才發現原來就是這個選項。

閱讀「MacOS 我的設定」全文

三浦建太郎逝世

本部落格的 ACG 類別真的都用來發這種文了,5 月 20 日的時候,白泉社官方發布訃文,三浦建太郎老師在 5 月 6 日因為主動脈剝離逝世了,享年 54 歲。

白泉社官網還有多國語言版本的訃文。

最令人惋惜的就是他的代表作品烙印勇士(ベルセルク)還未完成了吧,從我還在國高中時就開始看了,不過後來連載速度慢了很多,當時我想說他是不是被夕映治癒了,靈魂內黑黑的東西被洗滌一空,後來才知道他健康出問題了,其實也是不意外,烙印勇士雖然是月刊連載,但是很多畫面其實都是畫的非常精細,很難想像早期要維持那樣的作畫精細度和連載速度要投入多少精力,這幾年速度就慢很多了,差不多都是一兩年才出一本單行本。目前白泉社還沒有說烙印勇士之後要怎樣,不過有特別提到之後確定後會在跟大家說,我自己是認為三浦應該是對於整個故事的發展早就都規劃好了,不過有留下多少資料又是另外一回事,還有就是如果要找人接手,那個作畫也是一個大問題吧。

最後放上兩張圖,是烙印勇士當中我印象最深刻的地方。

ベルセルク

ベルセルク

PS. 東立有出數位版,而且說現在是沒有任何修剪的版本了,至於實體書去年有再版過,現在應該是缺貨中。


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 的關係)。


➡ 看看其它文章