圖示對於現代網頁介面至關重要。它們能簡化導航、明確功能並增強視覺吸引力。然而,高效地實現圖示面臨諸多挑戰,例如可伸縮性、動態載入和伺服器端渲染 (SSR) 相容性。
為了應對這些挑戰,我們開發了 Nuxt Icon v1 — 一個專為 Nuxt 專案量身定製的多功能現代化解決方案。Nuxt Icon 在既有圖示渲染技術的基礎上,引入了新穎的方法,在效能、可用性和靈活性之間架起了橋樑。
在這篇文章中,我們將探討圖示渲染的挑戰、圖示解決方案的演變,以及 Nuxt Icon 如何結合這些方法的優點,為開發者提供無縫體驗。
為什麼圖示具有挑戰性?
乍一看,圖示似乎很簡單——它們本質上只是微小的影像元素,用於增強使用者介面,提供視覺提示並提高可用性。
然而,從工程角度來看,它們帶來了幾個挑戰。理想的圖示應該具備以下特點:
- 可著色:適應主題和配色方案。
- 可伸縮:在各種尺寸和解析度下都能清晰渲染。
- 易管理:圖示集可能包含數百或數千個圖示。
- 高效打包:最大限度地減少網路請求。
- 最佳化載入:影響應用程式效能和使用者體驗。
- 動態性:支援使用者生成或執行時定義的圖示的動態載入。
滿足所有這些需求需要一個精心設計的解決方案,以平衡各種權衡。讓我們探索圖示解決方案的演變以及它們如何應對這些挑戰。
圖示解決方案之旅
多年來,開發人員嘗試了各種技術來高效地渲染圖示。讓我們探討這些解決方案的演變以及它們所面臨的挑戰。
<img>
標籤:早期 1.
最直接的解決方案:使用 <img>
標籤。這是早期網路的首選方法。
您將託管您的影像資源,並使用 <img>
標籤連結到該影像,指定其寬度和高度。它很簡單,不需要設定或執行時依賴,並且在瀏覽器中原生工作。
然而,它也有缺點。影像可能會畫素化,缺乏顏色控制,並且無法很好地縮放。每個圖示都是一個單獨的影像檔案,導致許多網路請求,這可能會很慢,尤其是在 HTTP 1.1 時代。在影像下載之前,您可能會看到一閃而過的不可見圖示,這會損害使用者體驗。最後,它的書寫相當冗長,因為您需要指定影像的完整路徑並管理相對路徑。這解釋了為什麼這種方法在當今的現代網站上很少使用。
2. 網頁字型:圖示字型
作為圖示演進的下一步,網頁字型成為一種流行的解決方案。字型本質上是向量化且可著色的,這使它們非常適合圖示。
圖示集提供商通常將其圖示編譯成一個特殊的字型檔案,為每個圖示分配一個唯一的 Unicode 字元。這伴隨著一個 CSS 檔案,將這些 Unicode 值對映到特定的圖示類。
這種方法的優點顯而易見:它易於使用、可著色、可縮放,並且只需一次請求即可載入所有圖示。
然而,也有一些缺點。預先載入大型字型檔案可能會很慢,並且自定義圖示集具有挑戰性。此外,在字型載入之前,您可能會遇到不可見圖示的閃爍,因為沒有可用的備用字型。
3. 內聯 SVG:基於元件的圖示
隨著現代前端框架的出現,重用 HTML 元素變得顯著更容易。這催生了直接將 SVG 標籤內聯為元件的想法。
為了支援這種方法,許多圖示集提供了針對每個框架量身定製的包裝器包。例如,MDI 圖示使用共享元件並將圖示資料作為 props 傳遞,而 Tabler 圖示為每個圖示提供專用元件。
由於這些是 SVG,它們本質上是可著色、可縮放的,並保留了 SVG 的所有特性。通常,圖示會被打包到應用程式中,從而消除額外的網路請求,並確保它們對 SSR 友好並在首次渲染時可見。
然而,這種方法也有其缺點。它會生成大量的 SVG DOM 元素,當使用大量圖示時可能會影響效能。它還會增加捆綁包大小,並且需要針對每個圖示集和框架組合提供特定的整合支援,從而導致一定程度的供應商鎖定。這使得切換到不同的圖示集或框架具有挑戰性。
儘管存在這些權衡,但這種方法在今天仍然被廣泛採用,因為對於大多數專案來說,切換圖示集或框架並非頻繁的必要。
4. Iconify 執行時:動態 API 訪問
Iconify透過聚合超過 100 多個集合的 200,000 多個圖示,徹底改變了圖示的使用方式。其執行時解決方案透過 API 動態獲取圖示,從而無需預先打包即可動態訪問任何圖示。
這非常適合渲染來自使用者提供內容或其他在構建時未知的動態內容中的圖示。而且設定起來非常簡單,甚至可以作為 CDN 使用,無需任何構建工具。
雖然這種方法提供了極大的靈活性,但它也伴隨著一些權衡。它引入了執行時依賴,這意味著圖示只有在 JavaScript 載入並獲取圖示資料後才會渲染。這種方法也對伺服器端渲染 (SSR) 和快取層(例如漸進式 Web 應用程式 (PWA) 中使用的快取層)帶來了挑戰。
5. 按需元件圖示
憑藉 Iconify 統一的介面和 Vite 的按需載入方法,我們開發了unplugin-icons
。此工具允許您按需將任何圖示作為元件匯入。
作為一項unplugin
,它支援所有流行的構建工具,包括 Vite、webpack 和 rspack。我們為 Vue、React、Svelte 和 Solid 等流行框架提供編譯器。藉助 Iconify,您可以在任何框架中使用任何圖示,最大限度地減少供應商鎖定。
雖然此技術與以前的元件圖示解決方案具有相同的優缺點,但與構建工具的整合使我們能夠提供完整的 Iconify 集合,同時只交付您實際使用的圖示。然而,DOM 元素管理等執行時問題仍然存在。
6. 純 CSS 圖示
作為開發UnoCSS的附帶產物,我們發現了將圖示完全嵌入 CSS 的潛力,從而產生了創新的解決方案:純 CSS 圖示.
這種方法涉及將 SVG 圖示作為資料 URL 內聯,並提供一個類來顯示圖示。經過一些調整,這些圖示變得可著色、可縮放,甚至能夠顯示 SVG 動畫。
瀏覽器可以快取 CSS 規則,並且每個圖示只需 一個 DOM 元素 即可渲染。這種方法將圖示打包在一個 CSS 檔案中,無需額外的請求。由於它是純 CSS,圖示會與您介面的其餘部分一同顯示,無需任何執行時,並且與 SSR 自然協同工作——您的伺服器在伺服器端不需要任何額外的工作。
唯一的缺點是無法完全自定義 SVG 內部的元素,以及需要在構建時打包圖示,這不具備動態性。
整合到 Nuxt 中的挑戰
雖然我認為純 CSS 圖示等等按需元件圖示對於大多數靜態用法來說已經足夠,但 Nuxt 作為功能齊全的框架,對高效整合圖示有更多的要求:
- SSR/CSR:Nuxt 既支援伺服器端渲染 (SSR) 又支援客戶端渲染 (CSR) 模式。我們非常關注終端使用者體驗,並希望確保圖示能夠即時渲染而不會閃爍。
- 動態圖示:在像Nuxt Content這樣的整合中,內容可以在執行時或從外部源提供,這些我們在構建時是不知道的。我們希望確保我們有能力很好地整合這些情況。
- 效能:我們希望確保圖示高效打包,並最佳化圖示載入以獲得最佳效能。
- 自定義圖示:雖然 Iconify 提供了廣泛的圖示選擇,但我們也知道專案擁有自己的圖示集,或希望使用 Iconify 中沒有的付費圖示是很常見的。支援自定義圖示對我們的使用者至關重要。
考慮到這些要求,讓我們重新審視前面討論的解決方案,看看它們如何應對。
對於動態圖示,Iconify Runtime 脫穎而出,成為一個可行的選擇。它允許動態獲取圖示,使其適用於在構建時未知的內容。然而,它也有其缺點。對執行時依賴的依賴意味著它無法與 SSR 無縫整合,並且不支援自定義圖示,因為請求被定向到 Iconify 的伺服器,這些伺服器無法訪問我們本地的圖示設定。
相反,純 CSS 圖示提供了出色的效能和 SSR 相容性。它們確保圖示即時渲染而不會閃爍,並且高效打包。然而,它們在動態圖示方面表現不足,因為它們需要在構建時打包,並且缺乏適應執行時內容更改的靈活性。
平衡這些權衡確實具有挑戰性。那麼,為什麼不利用這兩種方法的優勢呢?透過理解這些權衡,我們可以更好地欣賞 Nuxt Icon v1 提供的平衡解決方案。
Nuxt Icon v1 介紹:兩全其美的方案
憑藉 Nuxt 模組系統的靈活性,Nuxt Icon 結合了 CSS 圖示的即時渲染和 Iconify 圖示的動態獲取,集兩全其美之優勢。這種雙重方法提供了一個多功能、現代且可定製的圖示解決方案,可無縫適應您專案的需求。
雙重渲染模式
為了解決渲染方法中的權衡,Nuxt Icon 引入了一個通用的 <Icon>
元件,它支援 CSS 和 SVG 兩種模式,並且這兩種模式都對 SSR 友好。根據您的定製需求,您可以為每個圖示在這兩種模式之間切換。
在 CSS 模式下,圖示在 SSR 期間包含在 CSS 中,確保它們即時渲染而無需任何執行時成本。在 SVG 模式下,圖示在 SSR 期間作為 HTML 內聯,提供相同的即時渲染優勢。這兩種方法都確保圖示在初始螢幕上立即顯示而不會有任何延遲,提供無縫的使用者體驗。
圖示包
動態圖示帶來了獨特的挑戰,尤其是在高效載入方面。為了解決這個問題,我們利用 Iconify 的 API,它允許我們透過網路請求按需提供任何圖示。然而,僅僅依賴此 API 可能會引入延遲,特別是如果伺服器在地理上遠離您的使用者。
為了緩解這種情況,我們引入了圖示包的概念。我們可以將常用圖示直接打包到 客戶端包
中。這確保這些圖示即時渲染,無需額外的網路請求。然而,由於包大小可能增加,打包所有可能的圖示是不可行的。
考慮到 Nuxt 是一個全棧框架,我們可以透過引入 伺服器包
來實現平衡。在伺服器端,包大小問題較小,允許我們包含更廣泛的圖示集。在 SSR 期間,可以快速獲取這些圖示並根據需要傳送給客戶端。此設定確保常用圖示的高效能,同時仍提供從 Iconify 提供任何圖示作為回退的靈活性。
透過結合客戶端靜態圖示打包和伺服器端動態圖示打包,我們在效能和靈活性之間實現了最佳平衡。
資料流
下面是說明 Nuxt Icon 如何請求圖示資料的流程圖
- 您使用
<Icon>
元件並提供圖示名稱
。 - Nuxt Icon 將首先檢查圖示是否在
客戶端包
中可用,或在 SSR 有效負載中(在 SSR 期間已知的圖示將出現在有效負載中)。如果可用,圖示將立即渲染。 - 如果圖示在客戶端不可用,Nuxt Icon 將從隨您的 Nuxt 應用程式一起提供的伺服器 API 中獲取圖示資料。在伺服器端點內部,它將從
伺服器包
中查詢以檢視圖示是否可用。 - 在此之間,涉及多個快取系統。伺服器端點快取、HTTP 快取和客戶端快取可確保高效快速地獲取圖示。由於圖示資料不會頻繁更改,我們使用硬快取策略以確保最佳效能。
- 當圖示在客戶端和伺服器端都未知(動態圖示)時,伺服器端點將回退到 Iconify API 來獲取圖示資料。由於伺服器端點是快取的,Iconify API 將僅為每個唯一圖示呼叫一次,無論有多少客戶端請求它,以節省雙方資源。
這種分層方法確保了高效的圖示交付,平衡了速度和靈活性,同時儘可能動態。並且平衡了每個解決方案之間的權衡。
立即體驗 Nuxt Icon
Nuxt Icon v1 代表了圖示渲染領域多年創新的結晶。無論您是構建動態應用程式、靜態網站,還是介於兩者之間的任何專案,Nuxt Icon 都能適應您的需求。
透過執行以下命令,您可以輕鬆地將 Nuxt Icon 新增到您的專案中:
npx nuxi module add icon
然後,在您的 Vue 元件中匯入 <Icon>
元件,並按照Iconify 的約定:
<template>
<Icon name="i-lucide-activity" />
</template>
提供圖示 名稱
。文件探索更多,體驗其功能,並告訴我們您的想法。我們很高興看到 Nuxt Icon 如何改變您的專案!
祝您 Nuxting 愉快 ✨