<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          聊聊純 CSS 圖標(biāo)

          共 1691字,需瀏覽 4分鐘

           ·

          2021-11-12 23:19

          感謝印記中文的 QC-L[1] 對(duì)本文進(jìn)行翻譯,英文原文: English Version[2]。

          重新構(gòu)想原子化 CSS?中,我提到了 UnoCSS[4] 的一個(gè)預(yù)設(shè),它提供了在純 CSS 中按需使用任何圖標(biāo)的能力。在這篇文章中,我想和大家分享下它的工作原理。

          我的圖標(biāo)探索之旅

          如果你對(duì)我如何探索圖標(biāo)解決方案的過(guò)程感興趣,下面這個(gè)博文列表,是我在圖標(biāo)探索過(guò)程中總結(jié)和相關(guān)實(shí)驗(yàn)

          • 2020 年 8 月 - 圖標(biāo)探索之旅[5]
          • 2021 年 9 月 - 圖標(biāo)探索之旅后續(xù)[6]
          • 2021 年 10 月 - 重新構(gòu)想原子化 CSS
          • 2021 年 11 月 - 聊聊純 CSS 圖標(biāo) - 你在這里!

          現(xiàn)有方案

          有個(gè)名為 `css.gg`[8] 的純 CSS 圖標(biāo)解決方案,它完全通過(guò)偽元素(::before,::after)來(lái)構(gòu)建圖標(biāo)。使用這種方案意味著你需要對(duì) CSS 工作原理有深刻的理解,但同時(shí)也很難創(chuàng)造更為復(fù)雜的圖標(biāo)(只有3個(gè)元素可以使用)。我在尋找 一種更加通用化的解決方案,可以適用于任何圖標(biāo) 而并非在特定集合中進(jìn)行有限的選擇。

          我的方案

          這個(gè)方案來(lái)源于社區(qū)小伙伴 @husayt[9]unplugin-icons 中提出 需求[10] 并由 @userquin[11]此 PR 中[12] 提供了初版的實(shí)現(xiàn)。這個(gè)方案非常簡(jiǎn)單,用 DataURI[13] 中的圖標(biāo)作為背景圖,并生成如下 CSS。

          .my-icon?{
          ??background:?url(data:...)?no-repeat?center;
          ??background-color:?transparent;
          ??background-size:?16px?16px;
          ??height:?16px;
          ??width:?16px;
          ??display:?inline-block;
          }

          有了這種方案,我們就可以使用一個(gè)單獨(dú)的類(lèi)在 CSS 中內(nèi)嵌任何圖像。

          這個(gè)想法非常有趣,但是這更其實(shí)更像一張圖片而非圖標(biāo)。對(duì)我而言,一個(gè)圖標(biāo)必須是可以根據(jù)上下文進(jìn)行縮放和著色的。

          實(shí)現(xiàn)

          DataURI

          再次感謝 Iconify[14],它將 100 多個(gè)圖標(biāo)集與上萬(wàn)個(gè)圖標(biāo)統(tǒng)一為 一致的 JSON 格式[15]。它允許我們通過(guò)簡(jiǎn)單地提供集合和圖標(biāo) ID 的方式來(lái)獲取任意圖標(biāo)集中的 SVG,使用方式如下:

          import?{?iconToSVG,?getIconData?}?from?'@iconify/utils'

          const?svg?=?iconToSVG(getIconData('mdi',?'alarm'))
          //?(此處并非真實(shí)?API,僅供示意)

          當(dāng)我們得到 SVG 字符串后,可以將其轉(zhuǎn)換為 DataURI:

          const?dataUri?=?`data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`

          說(shuō)到 DataURI,使用 Base64[16] 幾乎一直是我的默認(rèn)選擇 -- 直到我看到 Chris Coyier 所寫(xiě)的 你可能不需要使用 Base64 SVG[17] 文章。對(duì)于圖像等二進(jìn)制數(shù)據(jù)必須使用 Base64 進(jìn)行編碼,以便在 CSS 等純文本文件中使用,而對(duì)于 SVG 來(lái)說(shuō),由于它已經(jīng)是文本格式,所以使用 Base64 編碼實(shí)際上會(huì)使得文件體積變得變大。

          結(jié)合 Taylor Hunt 在 優(yōu)化 DataURI 中的 SVG[18] 提到的相關(guān)技術(shù),進(jìn)一步對(duì)輸出大小進(jìn)行了改進(jìn),以下是我們的最終解決方案。

          //?https://bl.ocks.org/jennyknuth/222825e315d45a738ed9d6e04c7a88d0
          function?encodeSvg(svg:?string)?{
          ??return?svg.replace(',?(~svg.indexOf('xmlns')???'?:?'))
          ????.replace(/"/g,?'\'')
          ????.replace(/%/g,?'%25')
          ????.replace(/#/g,?'%23')
          ????.replace(/{/g,?'%7B')
          ????.replace(/}/g,?'%7D')
          ????.replace(/,?'%3C')
          ????.replace(/>/g,?'%3E')
          }

          const?dataUri?=?`data:image/svg+xml;utf8,${encodeSvg(svg)}`

          可縮放

          使 ”圖片“ 更像圖標(biāo)的第一步,我們需要讓它可以根據(jù)上下文進(jìn)行縮放。

          幸運(yùn)的是,CSS 為我們提供了原生的縮放支持 —— em 單位。

          .my-icon?{
          ??background:?url(data:...)?no-repeat?center;
          ??background-color:?transparent;
          ??background-size:?100%?100%;
          ??height:?1em;
          ??width:?1em;
          }

          通過(guò)改變 heightwidth1em,并設(shè)置 background-size100%,我們可以使得圖片的比例基于其父級(jí)元素的字體大小變化。

          可著色

          在內(nèi)聯(lián)的 SVG 中,我們可以使用 [fill="currentColor"](https://www.w3.org/TR/css-color-3/#currentcolor "fill="currentColor"") 來(lái)為 SVG 著色。但是,當(dāng)我們將其作為背景圖時(shí),它就變成了一個(gè)圖片。SVG 的動(dòng)態(tài)性消失了,currentColor 的效果也隨之消失(這和你無(wú)法覆蓋 PNG 的顏色一樣)。

          如果你 Google 一下,你會(huì)發(fā)現(xiàn)大多數(shù)人都告訴你告訴你,這個(gè)就是個(gè)限制沒(méi)有辦法。少部分人會(huì)給你提供一個(gè)解決方案 -- 在轉(zhuǎn)換為 DataURI 前在 SVG 中設(shè)置顏色,這可以解決對(duì)于特定圖標(biāo)著色的問(wèn)題,但是沒(méi)有從根本上解決上下文著色的問(wèn)題。

          此時(shí),可能會(huì)有小伙伴想到使用 CSS filters[19],就像 Una Kravets 在 使用 CSS 給 SVG 背景上色[20] 一文中提到的那樣。聽(tīng)起來(lái)還不錯(cuò),也許引入一些運(yùn)行時(shí)的 JavaScript 去計(jì)算如何將顏色轉(zhuǎn)化為最終所需的顏色矩陣便可以做到。但這就違背了我們?cè)谔剿骷?CSS 中圖標(biāo)的目的。

          在我快要放棄這個(gè)方案時(shí),我無(wú)意中發(fā)現(xiàn)了 Noah Blon 的 在 CSS 背景圖片中為 SVGs 上色[21]。文中提到了一個(gè)非常絕妙的主意,通過(guò)使用 CSS masks[22] 對(duì)背景進(jìn)行蒙版 - 一個(gè)從未聽(tīng)說(shuō)過(guò) CSS 屬性。

          .my-icon?{
          ??background-color:?red;
          ??mask-image:?url(icon.svg);
          }

          與其想辦法給背景圖片著色,不如換種思路,把圖標(biāo)作為一個(gè)蒙版,來(lái)對(duì)背景的顏色進(jìn)行裁剪。這樣做,我們還可以使用 currentColor 為其著色!

          .my-icon?{
          ??background-color:?currentColor;
          ??mask-image:?url(icon.svg);
          }

          彩色圖標(biāo)

          我們把單色的圖標(biāo)做成了可著色的,但又遇到了新的問(wèn)題。當(dāng)使用 mask 時(shí),圖標(biāo)的顏色和內(nèi)容會(huì)丟失。例如:

          我想,很多時(shí)候可能很難通過(guò)一種方案來(lái)解決所有問(wèn)題。

          但是,其實(shí)我們可以使用兩種方案!還記得我們最開(kāi)始提到了將圖像作為背景圖片的方案嗎?這個(gè)不正適用于彩色圖標(biāo) -- 畢竟使用彩色圖標(biāo)時(shí),我們也不需要修改它的顏色。

          解決方案其實(shí)很簡(jiǎn)單,我們只需找到一種方法來(lái)巧妙地區(qū)分單色圖標(biāo)和彩色圖標(biāo)。既然我們可以得到 SVG 的內(nèi)容,我們便可以使用如下方法:

          //?如果?SVG?的圖標(biāo)包含?`currentColor`?的值
          //?它大概率是一個(gè)單色圖標(biāo)
          const?mode?=?svg.includes('currentColor')
          ????'mask'
          ??:?'background-img'

          const?uri?=?`url("data:image/svg+xml;utf8,${encodeSvg(svg)}")`

          //?單色圖標(biāo)
          if?(mode?===?'mask')?{
          ??return?{
          ????'mask':?`${uri}?no-repeat`,
          ????'mask-size':?'100%?100%',
          ????'background-color':?'currentColor',
          ????'height':?'1em',
          ????'width':?'1em',
          ??}
          }
          //?彩色圖標(biāo)
          else?{
          ??return?{
          ????'background':?`${uri}?no-repeat`,
          ????'background-size':?'100%?100%',
          ????'background-color':?'transparent',
          ????'height':?'1em',
          ????'width':?'1em',
          ??}
          }

          而且最終效果出乎意料的完美!它的效果其實(shí)和我們?nèi)粘=佑|到的一個(gè)工具非常相似 - 系統(tǒng)的原生 Emoji。文本顏色會(huì)根據(jù)上下文而發(fā)生變化,而 Emoji 則保持自己的顏色。

          最終效果展示:

          如果想要查看或者搜索所有可用的圖標(biāo),可以參考我的另一個(gè)開(kāi)源項(xiàng)目 Ic?nes[23]

          使用

          如果你想在項(xiàng)目中嘗試這個(gè)圖標(biāo)解決方案,你可以安裝 UnoCSS[24] 和圖標(biāo)預(yù)設(shè):

          npm?i?-D?unocss?@unocss/preset-icons?@iconify/json

          @iconify/json 包含了所有 Iconify 收錄的圖標(biāo)集(120MB 左右)?;蛘?,你也可以按圖標(biāo)集的方式進(jìn)行安裝以節(jié)省流量和儲(chǔ)存空間,例如,需使用 Material Design 的圖標(biāo),你可以安裝 @iconify-json/mdi,使用 Carbon 的圖標(biāo),你可以安裝 @iconify-json/carbon 等。

          接著配置你的 vite.config.js

          import?{?defineConfig?}?from?'vite'
          import?Unocss?from?'unocss'
          import?UnocssIcons?from?'@unocss/preset-icons'

          export?default?defineConfig({
          ??plugins:?[
          ????Unocss({
          ??????//?但?`presets`?被指定時(shí),默認(rèn)的預(yù)設(shè)將會(huì)被禁用,
          ??????//?因此你可以在你原有的 App 上使用純 CSS 圖標(biāo)而不需要擔(dān)心 CSS 沖突的問(wèn)題。
          ??????presets:?[
          ????????UnocssIcons({
          ??????????//?其他選項(xiàng)
          ??????????prefix:?'i-',
          ??????????extraProperties:?{
          ????????????display:?'inline-block'
          ??????????}
          ????????}),
          ????????//?presetUno()?-?取消注釋以啟用默認(rèn)的預(yù)設(shè)
          ??????],
          ????}),
          ??],
          })

          這就是今天的全部?jī)?nèi)容了。希望你能喜歡這個(gè)來(lái)自 UnoCSS 的圖標(biāo)解決方案,或者能為你提供靈感,用于你自己的項(xiàng)目。

          感謝閱讀,下次見(jiàn) :)

          參考資料

          [1]

          QC-L: https://github.com/QC-L

          [2]

          English Version: https://antfu.me/posts/icons-in-pure-css

          [3]

          重新構(gòu)想原子化 CSS: https://antfu.me/posts/reimagine-atomic-css#pure-css-icons

          [4]

          UnoCSS: https://github.com/antfu/unocss

          [5]

          圖標(biāo)探索之旅: https://antfu.me/posts/journey-with-icons

          [6]

          圖標(biāo)探索之旅后續(xù): https://antfu.me/posts/journey-with-icons-continues

          [7]

          重新構(gòu)想原子化 CSS: https://antfu.me/posts/reimagine-atomic-css-zh

          [8]

          css.gg: https://github.com/astrit/css.gg

          [9]

          @husayt: https://github.com/husayt

          [10]

          需求: https://github.com/antfu/unplugin-icons/issues/88

          [11]

          @userquin: https://github.com/userquin

          [12]

          此 PR 中: https://github.com/antfu/unplugin-icons/pull/90

          [13]

          DataURI: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs

          [14]

          Iconify: https://iconify.design/

          [15]

          一致的 JSON 格式: https://github.com/iconify/collections-json

          [16]

          Base64: https://developer.mozilla.org/en-US/docs/Glossary/Base64

          [17]

          你可能不需要使用 Base64 SVG: https://css-tricks.com/probably-dont-base64-svg/

          [18]

          優(yōu)化 DataURI 中的 SVG: https://codepen.io/Tigt/post/optimizing-svgs-in-data-uris

          [19]

          CSS filters: https://developer.mozilla.org/en-US/docs/Web/CSS/filter

          [20]

          使用 CSS 給 SVG 背景上色: https://css-tricks.com/solved-with-css-colorizing-svg-backgrounds/

          [21]

          在 CSS 背景圖片中為 SVGs 上色: https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images

          [22]

          CSS masks: https://developer.mozilla.org/en-US/docs/Web/CSS/mask

          [23]

          Ic?nes: https://icones.js.org/

          [24]

          UnoCSS: https://github.com/antfu/unocss


          往期推薦


          2021 TWeb 騰訊前端技術(shù)大會(huì)精彩回顧(附PPT)
          面試題:說(shuō)說(shuō)事件循環(huán)機(jī)制(滿(mǎn)分答案來(lái)了)
          專(zhuān)心工作只想搞錢(qián)的前端女程序員的2020



          最后


          • 歡迎加我微信,拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

          • 歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專(zhuān)業(yè)的技術(shù)人...

          點(diǎn)個(gè)在看支持我吧
          瀏覽 76
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚欧成人一区视频 | 亚洲AV无码秘 蜜桃枫花恋 | 婷婷六月天 | 男人的天堂青青草原 | 国产内射免费视频 |