圖示對於現代網路介面至關重要。它們簡化導航、闡明功能並增強視覺吸引力。然而,有效率地實作圖示涉及可擴展性、動態載入和伺服器端渲染 (SSR) 相容性等挑戰。
為了應對這些挑戰,我們開發了 Nuxt Icon v1 — 專為 Nuxt 專案量身打造的多功能現代解決方案。透過建立在成熟的圖示渲染技術之上並引入新穎的方法,Nuxt Icon 彌合了效能、可用性和靈活性之間的差距。
在這篇文章中,我們將探討圖示渲染的挑戰、圖示解決方案的演進,以及 Nuxt Icon 如何結合這些方法中最優良的方面,為開發人員提供無縫的體驗。
為什麼圖示具有挑戰性?
乍看之下,圖示似乎很簡單 - 它們本質上只是微小的圖像元素,可以增強使用者介面、提供視覺提示並提高可用性。
然而,從工程的角度來看,它們帶來了幾個挑戰。理想的圖示應該是
- 可著色:可適應主題和配色方案。
- 可縮放:在各種尺寸和解析度下清晰渲染。
- 可管理:圖示集可以包含數百或數千個圖示。
- 有效率地捆綁:最小化網路請求。
- 最佳化載入:影響應用程式效能和使用者體驗。
- 動態:支援為使用者產生或運行時定義的圖示進行動態載入。
要滿足所有這些需求,需要一個經過精心設計的解決方案,以平衡權衡。讓我們探討圖示解決方案的演進,以及它們如何應對這些挑戰。
圖示解決方案的歷程
多年來,開發人員已經嘗試了各種技術來有效率地渲染圖示。讓我們探討這些解決方案的演進以及它們面臨的挑戰。
1. <img>
標籤:早期
最直接的解決方案:使用 <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,因此圖示會與您的 UI 的其餘部分一起顯示,無需運行時,並且可以自然地與 SSR 一起工作—您的伺服器端不需要任何額外的工作。
唯一的缺點是 SVG 內部元素的完整自訂不足,以及需要在建置時捆綁圖示,這不是動態的。
整合到 Nuxt 中的挑戰
雖然我會說 純 CSS 圖示 和 隨需元件圖示 對於大多數靜態用途來說已經足夠了,但 Nuxt 作為一個功能齊全的框架,在有效率地整合圖示方面有更多要求
- SSR/CSR:Nuxt 在伺服器端渲染 (SSR) 和客戶端渲染 (CSR) 模式下工作。我們非常關心最終使用者體驗,並且我們希望確保圖示能夠立即渲染而不會閃爍。
- 動態圖示:在像 Nuxt Content 這樣的整合中,內容可以在運行時或從外部來源提供,這是我們在建置時不知道的。我們希望確保我們有能力很好地整合這些情況。
- 效能:我們希望確保圖示被有效率地捆綁,並且圖示的載入針對最佳效能進行了最佳化。
- 自訂圖示:雖然 Iconify 提供了廣泛的圖示選擇,但我們也意識到專案擁有自己的圖示集或想要使用 Iconify 中不可用的付費圖示是很常見的。支援自訂圖示對於我們的使用者來說至關重要。
考慮到這些要求,讓我們重新審視我們之前討論的解決方案,看看它們的效果如何。
對於動態圖示,Iconify 運行時脫穎而出,成為一個可行的選擇。它允許動態獲取圖示,使其適用於在建置時未知的內容。然而,它也有其缺點。對運行時依賴的依賴意味著它不能與 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 可能會引入延遲,特別是當伺服器在地理位置上遠離您的使用者時。
為了減輕這種情況,我們引入了圖示捆綁包的概念。我們可以將常用的圖示直接捆綁到 Client Bundle
中。這確保了這些圖示能夠立即渲染,而無需額外的網路請求。然而,由於捆綁包大小可能會增加,因此捆綁所有可能的圖示是不可行的。
鑑於 Nuxt 是一個全棧框架,我們可以通過引入 Server Bundle
來達到平衡。在伺服器端,捆綁包大小不再是一個問題,這使我們可以包含更廣泛的圖示集。在 SSR 期間,可以快速獲取這些圖示並根據需要發送到客戶端。這種設定確保了常用圖示的高效能,同時仍然提供了從 Iconify 提供任何圖示作為後備的靈活性。
通過結合客戶端捆綁靜態圖示和伺服器端捆綁動態圖示,我們在效能和靈活性之間取得了最佳平衡。
資料流
這是一個資料流程圖,說明 Nuxt Icon 如何請求圖示資料
- 您使用
<Icon>
元件並提供圖示name
。 - Nuxt Icon 將首先檢查圖示是否在
Client Bundle
或 SSR payload 中可用(在 SSR 中已知的圖示將在 payload 中呈現)。如果是,則圖示將立即渲染。 - 如果圖示在客戶端不可用,Nuxt Icon 將從與您的 Nuxt 應用程式一起運送的伺服器 API 中獲取圖示資料。在伺服器端點內部,它將從
Server Bundle
查詢以查看圖示是否可用。 - 在這之間,涉及多個快取系統。伺服器端點快取、HTTP 快取和客戶端快取,以確保有效率且快速地獲取圖示。由於圖示資料不會經常更改,因此我們使用硬快取策略來確保最佳效能。
- 當客戶端和伺服器都不知道圖示(動態圖示)時,伺服器端點將回退到 Iconify API 以獲取圖示資料。由於伺服器端點被快取,因此對於每個唯一圖示,Iconify API 將僅被調用一次,無論有多少客戶端正在請求它,以節省雙方的資源。
這種分層方法確保了有效率的圖示交付,在速度和靈活性之間取得平衡,同時盡可能地保持動態。並平衡了每個解決方案之間的權衡。
立即試用 Nuxt Icon
Nuxt Icon v1 代表了多年來圖示渲染創新的頂峰。無論您正在建置動態應用程式、靜態網站還是介於兩者之間的任何內容,Nuxt Icon 都能適應您的需求。
通過運行以下命令,可以輕鬆地將 Nuxt Icon 添加到您的專案中
npx nuxi module add icon
然後,在您的 Vue 元件中導入 <Icon>
元件,並按照 Iconify 的約定 提供圖示 name
<template>
<Icon name="ph:arrow-down-duotone" />
</template>
通過 文件 探索更多內容,試驗其功能,並告訴我們您的想法。我們很高興看到 Nuxt Icon 如何改變您的專案!
Nuxting 愉快 ✨