tft每日頭條

 > 教育

 > 小實驗裡的大學問

小實驗裡的大學問

教育 更新时间:2024-07-04 16:13:41

圖标雖小,裡面的門道可一點都不少。甚至可以說,圖标的演化是 Web 技術演化的一個縮影。本文将帶你回顧一下圖标簡史,了解一下圖标技術的來龍去脈。

古代:一個圖标一張圖

史前時代的圖标,正如我們的直覺一樣,就是一張圖片。那時候的網絡很慢,一分鐘隻夠下載一個頁面,因此内容為王,美觀是次要的,“沒什麼用”的圖标還沒有被人們視為頁面上的必備元素。圖标個數少、使用頻率低,自然就沒人在上面花心思了。

近代:CSS Sprites(雪碧圖)

随着網上内容迅速豐富,内容的比拼已經沒有更多花樣可玩了,于是網站的競争轉向了“用戶體驗”領域。當然,後來内容又重新回到了舞台中央,不過這已經是後話了。

在體驗方面追求差異化的方式很多,而在寬帶網絡還不夠普及的時代,最直觀的方面就是加載速度。 然而“一個圖标一張圖”的方式在加載速度方面受到了嚴重限制。限制主要來自兩個方面:建立連接的時間,和浏覽器的并發下載數量限制。前者來自 HTTP 協議,而後者則來自浏覽器的實現。

小實驗裡的大學問(小圖标大學問)1

HTTP 方面的限制很容易理解,代理、DNS、握手、發送請求、TTFB 的時間對于像圖标這樣的小文件來說很可能遠超下載内容的時間。

浏覽器的并發限制其實在技術上來說是很有必要的。如果不限制并發下載數,一方面浏覽器就會開很多個線程,用戶的機器受不了;另一方面服務器也會收到大量的并發請求,服務器也受不了,很容易壓垮一些技術不過硬的網站。

浏覽器限制并發下載數,就會導緻超出并發限制的請求被迫進行排隊,對于圖标、圖片、css、js 等小文件很多的頁面來說,即使網速已經較快,這種排隊也可能會持續很久。

顯然,優化的方向就是減少并發下載的需求。因此,優化的方案也就顯而易見了:把各種小圖标拼合成一個大圖,然後想辦法讓浏覽器把它重新切成多個就可以了。恰好,浏覽器有一個特性叫background-position,也就是說假如我們把這張大圖設置為當前元素(寬w、高h)的背景,并且指定了 background-position 為 (x, y),那麼當前元素的背景就是從大圖上 (x, y, x w, y h) 截取出來的那個區域。這樣一來,就把 N 個并發下載合并成了一張大圖和一個 css 文件。

這種方案如果做手動拼合是非常繁瑣的,因此有人開發了工具來整合到前端工具鍊中,并且 UX 的一些工具也逐漸提供了直接導出雪碧圖的功能。

近代:Data URL

除了拼合成雪碧圖之外,還有另一種技術也可以減少并發下載請求,那就是 Data URL。

簡單來說,Data URL 就是這樣的形式:data:[<mediatype>][;base64],<data>, 比如 data:image/svg xml;utf8,<svg ... > ... </svg>, 也可以對 data部分進行 base64 編碼, 比如data:image/svg xml;base64,PHN2ZyB4bWxucz0iaHR0cDo。

小實驗裡的大學問(小圖标大學問)2

對于浏覽器來說,Data URL 和普通的 http URL 沒有什麼區别 —— 除了不用額外下載。因此,凡是能用 http URL 的地方都可以換成 Data URL,比如 html 中的 <img src="...">,css 中的 background-image: url(...)。這樣一來,就把圖标的下載合并到了 html/css 的下載過程中。

但是,這種方式也有缺點,那就是拖慢了整體渲染速度。

通常來講,浏覽器的下載優先級是 html > css > 圖片等資源的,因此我們經常看到一個網站展現出來之後,裡面的圖片還隻顯示了一半,過一會兒才會完全顯示。如果我們把大量圖标塞到 css 甚至 html 中,就會增大它們的體積,導緻首屏展現變慢。

所以,是否使用 Data URL 技術需要仔細權衡,根據性能測量數據進行優化。

現代:字體圖标

随着視網膜屏幕的登場,圖标面臨着新的嚴峻挑戰,那就是分辨率。

通常來說,圖标文件的分辨率和屏幕的邏輯分辨率是一樣的,但是在視網膜屏下,這個論斷不再成立。如果視網膜屏的設備像素比(devicePixelRatio,簡稱 dpr)是 3,那麼圖标就需要三個像素才能在視網膜屏下繪制出一個完美的邏輯像素,否則就會有粗糙感。

即使不考慮下載大小的問題,也需要對原有工具鍊進行改造才行。那不如幹脆試試另一種方案。

近代的另一項發明派上了用場,那就是“自定義字體”。

這本來是為了解決讓浏覽器顯示更好看的文字而創造的技術,比如要想用一種用戶機器上沒有的字體顯示藝術字,我們隻需要提供一個字體文件,這些字體文件包含我們要用的那些文字的字體輪廓數據就可以了。這些輪廓數據是矢量數據,用來表示每個字的“畫法”:從 0,0 開始,以 50%,10% 為控制點,畫一條貝塞爾曲線到 100%,30%。顯然,這種數據是不會受到屏幕分辨率影響的,就像我們日常看到的文字一樣,無論把它放到多大,它都是平滑而且不失真的。事實上,這正是一切矢量繪圖技術共同的優點。請記住它,因為後面我們還會用到另一種矢量繪圖技術。

既然我們可以通過控制顯示數據,把字母 A 顯示為手寫體的 A,那麼我們是不是也可以把它顯示成一個看起來和 A 完全不一樣的圖标呢?比如……一座房子?當然可以,事實上,這正是字體圖标的基本原理。

除了支持平滑縮放的優勢以外,字體圖标還有另一個優勢,那就是它本身就是文字。它會受到字号、前景色、行高等參數的控制,和普通文字沒有任何區别。而圖标,在實際應用中經常會和普通文字一起混排,這些特點正是我們想要的。

小實驗裡的大學問(小圖标大學問)3

不過,字體圖标也有一些缺點。

首要的缺點是單色。由于字體中隻有矢量數據,沒有顔色數據,因此,字體圖标必然是單色的。這在一些場景下是不夠用的。

其次是工具鍊複雜。雖然有一些工具可以幫你把一組 svg 文件拼合成一個字體文件,但是它們對 svg 的格式有嚴格的要求,不是任何一個 svg 都可以用的。你很難向 UX 解釋什麼樣的圖能用、什麼樣的圖不能用。其次,即使是可用的 svg,你也很難告訴工具每個圖标的字體基線是哪個(通俗來說,基線就是你這個圖标的底部和字母 g 的底部對齊,還是和字母 h 的底部對齊)。

基于這些特點,在普通的團隊中使用自定義字體圖标是相當困難的。不過好在還有不普通的團隊,比如 FontAwesome,他們專門制作、維護了一組免費圖标貢獻給開源社區。如果你需要的圖标恰好是其中之一,那麼直接用就可以了,你需要做的隻是引入它的 css 之後,在 html 中使用<i class="fa fa-home"></i>。

當代:svg 圖标

FontAwesome 雖好,但也不是萬能的。它往往不足以融入 UX 的 Design System,而 UX 顯然也不願意削足适履,為了圖标而改變自己的整體設計。

因此,對開發團隊更友好的方式仍然應該是高度可定制的、方便單個處理的。如果能直接使用 UX 提供給我們的 svg 文件顯然是最理想的。問題在于,該怎麼用。這裡面的門道可就多了。

小實驗裡的大學問(小圖标大學問)4

在這種場景下雪碧圖和 Data URL 仍然是可用的,因為它們隻需要圖片,而不管圖片的格式,svg 也是圖片,也有同樣的優缺點 —— 但能支持視網膜屏。

不過,svg 的特點,讓我們還有了一些另外的用法。

首先,可以把 svg 内聯到 html 中。svg 和 html 在語法上非常像,都是 xml 語系,隻是使用了不同的命名空間(xmlns),因此我們可以把 svg 作為一個元素内聯到 html 中,現代浏覽器可以正确地解釋它們。這種用法比較自然,html 中引入的 css 也同樣可以作用于 svg 内部的元素上,圖文可以無縫整合在一起。

不過這種用法有兩個問題。其一是 svg 中各個元素的 id 會并入頁面的命名空間中,比如在 svg 中引用了一個名為 a 的過濾器,那麼如果 html 或另一個 svg 中也定義了它,就會互相沖突。在稍大點的項目中要解決這種沖突會相當麻煩。其二是如果這個圖标出現很多次,它的内容就會在 html 中重複很多遍,體積也會相應的增大。

好在,svg 有一種機制可以解決這個問題,也就是use 标簽。使用 use 标簽,你可以根據 id 引用本頁面中的 svg 元素,甚至來自其它 svg 文件中的元素。比如要引用本頁面中的 id 為 a 的 rect 元素,你隻需要寫 <use xlink:href="#a">即可,并且在這裡你可以指定自己的 svg 屬性,以覆蓋原始元素上的 svg 設置。這樣一來,圖标内容被重複很多遍的問題就解決了。如果寫成 <use xlink:href="path/to/file.svg#a"> 則可以引用外部文件 path/to/file.svg 中定義的元素,那麼 id 沖突的問題也同樣解決了,因為它們不在同一個命名空間。

不過,這種方式相對于字體圖标還有兩個缺點:

一是圖标的顔色不會自動跟随文字顔色。比如原始元素定義的 rect 是紅色的,那麼無論你把它混排到什麼顔色的文字中,它都是紅色的。難道我們要在每個使用它的地方都手動覆蓋一下顔色嗎?當然不必,我們還有另一個特性可以解決這個問題,那就是 currentColor。這是一個預定義的特殊顔色值,它的意思就是取當前的文字顔色。比如當你寫<rect fill="currentColor"></rect> 時,把它混排到灰色文字中,這個rect的填充色就是灰色的,混排到藍色文字中就是藍色的。而且,這個圖标的其它部分你仍然可以指定特定的顔色,比如圖标主體部分跟随文字顔色,而某個特殊區域總是顯示為藍色。 經過這樣的處理之後,你不但可以彌補相對于字體圖标的缺點,還可以更進一步,支持彩色圖标了!即使你不需要彩色圖标,憑借 svg 對元素透明度的支持,也可以讓你的圖标比字體圖标更加豐富多彩。

二是圖标的大小不會自動跟随字體大小。不過這個就好解決了,因為 css 中有一個特性就是把當前字号作為尺寸單位,也就是 em,比如圖标大小設置為1em就會讓圖标的實際尺寸跟當前字号一緻。

當代:合字(Ligature)

你知道“囍”字嗎?嚴格來說,它不是一個字,而是一個“合字”。也就是說這是兩個漢字,隻是顯示成了一個字的樣子。隻是因為它非常常見,所以在字庫中給了它一個單獨的位置。但是大多數類似的文字是得不到這種特殊待遇的,比如“孔孟好學”的合體,以及“biangbiang面”中的“biang”字;字母上的聲調(比如漢語拼音)也是合字。

那麼,要如何用标準的方式來顯示這些合字呢?實際上,現代的字體庫早就已經支持合字了,隻是在現實中用得不多,一般人沒怎麼注意罷了。不過,在圖标領域,它重新找回了用武之地。我所知道的最早使用合字的圖标體系是 Google 的 Material Design,比如用 <i class="material-icons">home</i>就可以顯示出一座房子,它是怎麼工作的呢?實際上,material-icons 類為這個 i元素指定了一個支持合字的字體庫:'Material Icons',然後就會在字體庫中檢索出 home 這個合字對應的單字,并且把那個單字顯示出來就可以了。換句話說,home 是某個單字的别名。

但是,我們為什麼不像 FontAwesome 那樣直接引用這個單字,而要用合字中轉一次呢?在回答這個問題之前,我們先要知道一個概念,那就是:

訪問互聯網并不是我們這些健全人的專利!

世界上有很多殘疾人,特别是視障人士,比如盲人、弱視等,甚至等我們老了都有可能加入他們的行列。他們訪問互聯網時難以像我們一樣憑視覺閱讀網頁,而需要借助一種屏幕閱讀器。

屏幕閱讀器無法理解某個單字表示的是房子形狀的圖标,因此頁面的編寫者就需要給這個圖标加上特殊的 aria-label等屬性,以便屏幕閱讀器朗讀它們。這稱為 Accessibility(無障礙),簡稱 a11y。回想一下,你加過幾個這種屬性?很多人都不加,因為麻煩。但使用合字就不需要考慮這種問題了,因為合字本身就是可讀的,在 html 中的寫法就像普通文本一樣。所以,你隻要自然而然的使用合字,就已經滿足了 a11y 的一些要求。

因此,雖然“合字”本身沒有多少新的技術,但是我仍然把它歸于“當代”,它值得作為一種趨勢受到重視。

圖标在開發中的其它方面

在實際的開發工作中,還有一些問題需要考慮。

小實驗裡的大學問(小圖标大學問)5

第一個問題是搖樹優化,也就是說,我們沒有實際使用到的圖标應該自動被優化掉,而不應該讓我們手工檢查哪些圖标沒用到,并且從源碼中删掉。前面的大多數方案都難以給出完美的答案,隻有内聯 svg 方式是一個相對理想的方案。簡單來說,寫一個構建工具,當你在 html 中發現了一個 <img src="path/to/file.svg"> 時,把這個 svg 文件的内容讀出來,并且内聯到 html 中。這樣,隻要一個文件從未被引用過,就會自動優化掉。如果你用基于 WebPack 的構建工具,可以引入我寫的一個 “markup-inline-loader”。當然,如果你使用 Angular 這樣的現代框架,你就不需要為此做什麼額外的工作了。你隻要把每個圖标做成一個組件,使用 svg 内容作為模闆,然後像普通組件一樣引用它就可以了。Angular 會自動幫你優化掉沒有引用過的組件。

第二個問題是 SPA。現代的前端應用基本上都是單頁面應用(SPA),因此往往并不需要同時下載大量的圖标,而是按需加載。因此,“古代”那種“一個圖标一張圖”的方式未必就真的不可接受,針對你的實際業務場景,做一下鍊路分析,它沒準反倒是最合适的方案。

第三個問題是 svg 文件本身的優化。很多工具導出的 svg 文件很啰嗦,裡面有很多對于顯示沒有意義的東西。一些 svg 圖标即使減小到原來體積的一半兒都不會影響顯示,因此,針對 svg 本身做一些優化也是有價值的。當然,這事不必手工來做,有一個現成的工具可以做這事,它叫做 svgo,你隻要運行 npm i -g svgo命令就可以全局安裝它了。你可以用 svgo命令對單個文件或者整個目錄做優化;可以手工使用,也可以把它集成到工具鍊裡。

結語

這些圖标技術,雖然出現時間上有先後,但并不是簡單的替代關系,而是各有優缺點,适用于不同的場景。

随着需求和技術條件的變化,選型策略也要做出調整,有些時候還要混合使用,以發揮各自的優勢。

文/ThoughtWorks汪志成

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关教育资讯推荐

热门教育资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved