天天看點

網站圖示開發指南(精)

圖示是網站中非常友好的附加物,許多網站都會使用各種圖示來美化頁面樣式,給使用者提供更好的指引。本文将會和大家一起學習頁面圖示的發展曆史,以及最優的解決方案。

網站圖示開發指南(精)
  • 傳統圖示
  • 字型圖示
  • SVG 圖示

傳統圖示

編寫圖示最簡單的方式就是使用一張圖檔,如:

<html>
  <body>
    圖示 <img src="xxx.png" />
  </body>
</html>
           

在我剛開始寫頁面的時候就是這樣做的,感覺 so easy,直到業務變得越來越複雜,我就不得不思考以下幾個問題:

  • 圖示需要适配多個用戶端
  • 圖示太多需要優化
  • 圖示需要動态修改顔色

對于适配多個用戶端的問題,設計師們通常都會給我們提供多個尺寸的設計圖(@1x 圖、@2x 圖),于是我們就可以根據不同的用戶端來選擇對應尺寸的圖檔。

通常使用方式是:媒體類型 或 配置 srcset 。

例如:

<html>
  <head>
    <style>
      /* 使用媒體查詢,為每個端适配不同尺寸的圖檔 */
      .@media screen and (max-width: 300px) {
        .img {
          background-image: url("1x.png");
        }
      }
      .@media screen and (max-width: 600px) {
        .img {
          background-image: url("2x.png");
        }
      }
    </style>
  </head>
  <body>
    <!-- srcset 可以讓不同的用戶端自動比對合适尺寸的圖檔-->
    <!-- 如:當裝置像素比為 2 時,浏覽器會自動選擇 2x 圖進行渲染-->
    <img src="1x.png" srcset="1x.png 1x, 2x.png 2x" />
  </body>
</html>
           

通過上面的方法,多用戶端适配問題解決了,但我們使用了多張内容相同、尺寸不同的圖示,這無疑增加了圖檔的數量。

随着圖檔的增多,圖檔管理就是一個問題。每一張圖檔都會發起一個 HTTP 請求,而浏覽器并行加載同一域名下的請求是有限制的,太多的圖檔無法全部并行加載,就會進行排隊加載,排在後面的圖檔也就不能及時得到渲染。

通常,解決大量圖檔 HTTP 請求,有以下兩種方式:

  • 雪碧圖
  • Base64 圖

雪碧圖指的是,将所有小圖檔合并成一張大圖檔。在浏覽器渲染時,這張大圖檔隻需要發起一次 HTTP 請求,然後就被浏覽器緩存起來了,當再次使用該圖檔時,就會直接從緩存中進行讀取,進而避免了發起多次 HTTP 請求。

首先,我們需要将許多小圖檔合成一張大圖:

網站圖示開發指南(精)

然後在 CSS 中進行定位。

.icon1,
.icon2,
.icon3{
  width: 54px;
  height: 54px;
  background: url("../大圖.png");
}
/* 定位背景圖,讓圖檔顯示到對應的位置 */
.icon1 {
  background-position: -168px 0px;
}
.icon2 {
  background-position: -56px 0px;
}
.icon3 {
  background-position: 0px 0px;
}
           

可以看到,使用雪碧圖布局時,所有的圖檔都使用了同一張大圖,然後使用背景圖去定位,以區分不同的小圖示。

總結一下雪碧圖的特點:

  • 隻需發起一次 HTTP 請求。
  • 隻能通過 CSS 背景圖渲染。
  • 如果隻用到了大圖中的一張小圖,也必須加載整張大圖,有點浪費資源。
  • 不利于維護,每次新增圖示時,都不能影響到之前已經排好的圖示,是以生活工具需要更智能。

接下來,我們看一下 Base64 圖:

Base64 圖指的是,将一張圖檔資料編碼成一串字元串,并使用該字元串代替圖像位址。

<img
  src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAYAAABIdFAMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHhJREFUeNo8zjsOxCAMBFB/KEAUFFR0Cbng3nQPw68ArZdAlOZppPFIBhH5EAB8b+Tlt9MY"
/>
           

可以看到,圖檔的 src 并不是一個位址,而是一個字元串,這樣甚至可以不發起 HTTP 請求,就能渲染圖檔。

Base64 的原理是 Data URLs,即:字首為

data:

協定的 URL,允許開發者向 HTML 中嵌入小檔案。

總結一下 Base64 圖的特點:

  • 無 HTTP 請求。
  • 圖檔内容由字元串表示,通常會很長,這會增加 HTML 的大小。
  • Base64 并不是 url,是以不能進行緩存。
  • 适用于極小的圖檔,如:1x1 的小圖,用作背景圖,重複渲染平鋪整個頁面。

Ok,我們來總結一下傳統圖檔畫圖示的幾種方式:

網站圖示開發指南(精)

最後剩下動态修改圖檔顔色的問題,這個就比較難控制了,可以用 CSS Filter 去做濾鏡,通過調整圖檔的模糊度、對比度、灰階、透明度等,間接地改變圖檔顔色。

例如:

img {
  // 讓圖檔變灰
  filter: grayscale(100%);
  // 讓圖檔變模糊
  filter: blur(5px);
  // ...
}
           

但是 CSS Filter 能修改的顔色是有限的,如果想任意修改圖示顔色,我們繼續往下看。

字型圖示

随着網際網路的不斷發展,字型圖示逐漸來到了我們的視野,它可以像處理文字一樣去處理圖示,大大地提高了圖示的靈活性。使用字型圖示可以非常輕松地修改圖示顔色。

字型圖示的使用方式

字型圖示使用方式特别友善,我們隻需要在頁面中引入對應的字型檔案,然後編寫對應的字元就可以了。

字型圖示有兩種寫法:

  • 直接編寫 Unicode 編碼。
  • 使用僞類去寫 Unicode 編碼。

例如:

<html>
  <head>
    <style>
      /* 首先引入字型檔案 */
      @font-face {
        font-family: "iconfont";
        src: url("iconfont.eot"), url("iconfont.woff") format("woff"), url("iconfont.ttf")
            format("truetype"), url("iconfont.svg#iconfont") format("svg");
      }
      /* 定義字型類 */
      .iconfont {
        font-family: "iconfont";
        font-size: 16px;
      }
      /* 在僞類中編寫 unicode 字元 */
      .icon-edit:before {
        content: "\e603";
      }
    </style>
  </head>
  <body>
    <!-- 使用 &# + unicode 編碼可以渲染對應的字元。 -->
    直接使用字元編碼:
    <i class="iconfont">&#xe603;</i> 使用類名渲染(将字元寫在了僞類中):<i
      class="iconfont icon-edit"
      style="color:red"
    ></i>
  </body>
</html>
           

可以看到,有了字型圖示後,我們可以像處理文字一樣去修改圖示的顔色。

字型圖示的原理

字型圖示的本質是一種字元,而字元又是字型渲染出來的,字型決定了我們在鍵盤上敲打的字元最終在頁面上長什麼樣。

這就好比書法家寫字,不同的字型就是不同的書法家,不同的書法家雖然都在寫同一個字,但是由于字迹的不同,寫出來的文字也就大不相同。

網站圖示開發指南(精)

試想一下:有一個特立獨行的書法家,他并不按照正常的寫法來寫字,他寫出來的字都是一個個的小圖示,那不就是字型圖示了嗎 😄

其實,書法家寫字這個道理,在網頁中也是一樣的。

頁面在渲染文字的時候,會先将文字轉換為對應的 unicode 編碼,然後根據 css 中配置的

@font-face url

找到對應的字型檔案(eot ttf woff 等),接下來在該字型檔案中找到這個 unicode 編碼對應的繪制外形,最後繪制在頁面上。

深入字元編碼

在計算機中,我們能看到的所有字元,底層都是用二進制來表示的,如:空格符在二進制中就是

00100000

,大寫的字母

A

在二進制中就是

01000001

為了友善維護字元和二進制的關系,前輩們将這些對應關系記錄成一張表,如:

ID 字元 二進制
32 空格符 00100000
65 A 01000001

這個表就是我們常說的字元編碼,上表即 ASCII 編碼的一部分。

最初的 ASCII 編碼隻能表示 128 個符号,主要存儲的是 26 個英文字母的大小寫和數字等。有了 ASCII 編碼後,我們就能編寫對應的字型去渲染表中的字元了,但其他沒有被記錄的符号也就無法顯示了,如:不同國家的漢字、emoji 符号等。

為了解決中文字元編碼問題,國家制定了 GB2312 編碼,該編碼收錄了 6763 個漢字,涵蓋了中國大陸 99.75% 的使用頻率,能滿足絕大多數的漢字需求。

但 GB2312 編碼隻适用于中文,而世界上還有 200 多個國家,他們也有自己獨特的文字,難道每一個國家都需要自制一套字元編碼嗎?

其實不用,在 1991 年 10 月,誕生了 unicode 編碼,它制定了一套統一的編碼标準,收納了世界上所有國家的文字元号,到目前為止,已經有 100 多萬個符号。

unicode 最多 4 個位元組,一個位元組 8 個比特位(表示二進制中的 0 或 1),也就是

2**32

個狀态,完全可以容納世界上所有的符号。

是以,任何一個符号,都可以在 unicode 編碼中被找到。

總結一下字型圖示的特點:

  • 字型圖示是矢量圖,即使放大也不會變模糊。
  • 字型圖示可以通過 CSS 樣式進行控制,使用更加靈活。
  • 字型檔案一般比較大,但可以将不用的字型删掉。删除字型中沒有用到的漢字

最後,字型圖示雖好,但它的本質仍然一種文字,是以 CSS 在設定 color 時隻能選一種顔色,如果我們想制作一個多色的小圖示,也就無能為力了。

SVG 圖示

SVG 誕生于 1999 年,目的是用來繪制矢量圖形,它主要通過定義必要的線和形狀來建立一個圖形。

SVG 圖示使用方式

SVG 采用 XML 格式的文法來畫圖,例如:

<html>
  <head>
    <style>
      .my-style {
        /* 控制填充色 */
        fill: red;
      }
      .my-style use {
        color: orange;
      }
    </style>
  </head>
  <body>
    <svg style="display: none;">
      <symbol viewBox="0 0 24 24" id="heart">
        <path
          d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"
        ></path>
      </symbol>
    </svg>

    <svg class="my-style">
      <use xlink:href="#heart" />
    </svg>
  </body>
</html>
           

可以看到,首先我們把需要使用的圖示封裝到 symbol 标簽中,在使用時隻需要 use 一下就可以了。這跟我們定義一個 CSS class 然後再去 HTML 中引用是一個道理。

通常的 SVG 圖示庫會把所有用到的圖示封裝到一個 JS 檔案中,我們隻需要引入這個 JS 檔案,然後就能直接 use 對應的圖示了。

我們再看一個多色圖示的例子:

<html>
  <head>
    <style>
      /* svg 中的元素存在于 shadom 中,可以通過自定義變量傳遞參數 */
      .icon {
        width: 100px;
        height: 100px;
        margin-right: 10px;
      }
      .icon--fill {
        fill: grey;
      }
      .icon--color {
        fill: #ef5b49;
        --handle-color: #c13127;
        --cup-color: #ef5b49;
        --smoke-color: #cacaea;
      }
      .icon--color-alt {
        fill: #2f3fff;
        --handle-color: #1f2bac;
        --cup-color: #2f3fff;
        --smoke-color: #a5acbd;
      }
    </style>
  </head>
  <body>
    <svg xmlns="http://www.w3.org/2000/svg" class="hidden">
      <symbol id="icon-coffee" viewBox="0 0 20 20">
        <title>icon-coffee</title>
        <!-- 使用自定義變量 -->
        <path
          fill="var(--handle-color)"
          d="M15,17H14V9h3a3,3,0,0,1,3,3h0A5,5,0,0,1,15,17Zm1-6v3.83A3,3,0,0,0,18,12a1,1,0,0,0-1-1Z"
        />
        <rect
          fill="var(--cup-color)"
          x="1"
          y="7"
          width="15"
          height="12"
          rx="3"
          ry="3"
        />
        <path
          fill="var(--smoke-color)"
          d="M7.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,0,1-1.79.89Z"
        />
        <path
          fill="var(--smoke-color)"
          d="M3.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"
        />
        <path
          fill="var(--smoke-color)"
          d="M11.07,5.42a5.45,5.45,0,0,1,0-4.85,1,1,0,0,1,1.79.89,3.44,3.44,0,0,0,0,3.06,1,1,0,1,1-1.79.89Z"
        />
      </symbol>
    </svg>
    使用
    <svg class="icon icon--color" aria-hidden="true">
      <use xlink:href="#icon-coffee" href="#icon-coffee" />
    </svg>
  </body>
</html>
           

可以看到,SVG 和 HTML 一樣具有樹形結構,結構中的 path 都是圖形中的一個區域,這些區域可以被 CSS 選擇器比對到。當我們比對到對應的區域時,就能進行對應的顔色修改了,一張多色的 SVG 圖也就做好了。案例

網站圖示開發指南(精)

總結一下 SVG 圖示的特點:

  • 支援動态修改多個區域的顔色
  • 支援漸變色
  • 矢量圖,放大也不會變模糊

思考與總結

本文介紹了 3 種小圖示的使用方式,這裡做一個簡單回顧。

  • 傳統圖示,簡單粗暴,切好圖就能用,但需考慮不同尺寸以相容不同裝置,圖檔的顔色不好更改。
  • 字型圖示,需要引入字型檔案,然後編寫特定的字元,可以很友善的修改顔色,但隻能是單色。
  • SVG 圖示,需要引入預先定義好圖示的 SVG 檔案,然後将具體的圖示 use 出來即可,可以分别修改圖示中不同部位的顔色。

總體來說,3 種圖示使用起來都很簡單,而 SVG 圖示則是一個大趨勢,我們可以視具體情況來做選擇。

網站圖示開發指南(精)

繼續閱讀