FOUC (Flash of unstyled content) 網頁樣式短暫失效是什麼?原因為何?

FOUC(Flash of Unstyled Content)是指在網頁在載入的過程中由於 CSS 樣式的載入延遲或阻塞,導致頁面中的內容在沒有樣式的情況下短暫展示給用戶的現象。

為什麼 CSS 樣式會延遲或阻塞

通常 CSS 樣式會延遲的原因有以下幾點:

  1. 使用外部 CSS 樣式將 CSS 做分離載入,由於訪客網路速度問題導致有些 CSS 載入延遲。
  2. 引入 CSS 放置位置錯誤
  3. CSS 樣式是透過後續 JavaScript 套用的狀況

瀏覽器網頁解析步驟

當瀏覽器在加載網頁時,會先解析 HTML 語法後再載入 CSS 樣式。如果 CSS 樣式的載入被延遲或阻塞,頁面就會在沒有樣式的情況下展示給用戶,隨後再樣式載入完後突然套用樣式,最終造成頁面閃爍或變化。

使用外部 CSS 分離樣式,需要計算 Critial Path

一般來說使用外部 CSS 是不會有 FOUC 的問題的,但如果你為了網站效能想將 CSS 樣式分離,那麼你需要找出網頁中的 Critial Path (重要樣式路徑) 以確保重要的 CSS 是在網頁一開始載入時就被讀取,而非是要等待後續外部檔案載入完成後才能應用。

延伸閱讀:CSS SEO:6 種方法教你優化 CSS 樣式提升網頁核心體驗指標

引入 CSS 位置錯誤導致 FOUC

由於瀏覽器網頁解析步驟是由第一行到最後一行,我們習慣會將 CSS 放置於 head 內,讓網頁優先載入樣式。但有可能你誤將樣式放置於 body 末端或是其他需要用到樣式之前的地方,那麼便會造成 FOUC。

CSS 樣式是透過 JavaScript 套用的狀況

瀏覽器通常會等待所有 HTML 與 CSS 載入完後才執行 JavaScript,如果你的 CSS 樣式是透過 JavaScript 後續疊加上的,那麼便會在 JavaScript 尚未執行之前產生 FOUC 的現象。

這個問題最常出現在在需要透過 JavaScript 隱藏、顯示元素時,例如頁籤功能。解決的方法也相當容易,僅需要預設將元素設定為隱藏,執行後才開始做顯示,而非一開始就將元素設定為顯示,就不會有一開始顯示後來才隱藏的狀況發生。

以下例子來說,我們一開始預設就將所有 tab 除了第一個以外都設定為 display: none,就不會導致所有 tab 在 JavaScript 在還沒執行前顯示在畫面上。

<div class="tabs">
  <div class="tab active" style="display: block"></div>
  <div class="tab" style="display: none"></div>
  <div class="tab" style="display: none"></div>
</div>

<script>
  jQuery('tab:not(.active)').css('display', 'none')
</script>

在 VueJS 中,有一個 v-cloak 便是相同的作用,相關使用方式可以看v-cloak 在 Vue.js 中的作用是什麼?