@nuxt/iconで快適なアイコンのレンダリングを実現する
こんにちは、 ryoです。
こちらはNuxt / UnJS Advent Calendar 2024の22日目の記事です。
皆さんは何らかのアイコンを表示する際、どのように実装していますか?今もimgタグを利用していますか?
ですが、imgタグだと
- 色が変更できない
- 大きくすると粗くなる
- HTTPレスポンスのサイズが大きくなる
- 相対パスの指定が面倒
- SSRができない
というような課題にぶち当たることがよくあります。(ありますよね?)
アイコンはSVGを利用しましょう。そして、@nuxt/iconならSVGをより簡単に快適に扱うことができます。
@nuxt/icon とは?
@nuxt/iconはNuxt Modulesの1つで、導入することでIconifyが提供する200,000個以上のアイコンをすぐに利用できるようになります。
制作者は Nuxt, Vite, Vue のコアチームメンバーである Anthony Fu 氏です。
セットアップ
Nuxtのプロジェクトに@nuxt/iconを導入するのはとても簡単で、以下の2ステップです。
npmインストール
npm i -D @nuxt/icon
configに指定
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
]
})
以上で、利用する準備が整いました。早速、SVGを表示してみましょう。
Iconifyを使う
IconifyからVue.jsを利用してみます。
実装はとても簡単で、Iconタグを用います。
<Icon name="uil:vuejs" style="color: blue" size="2em" />
<Icon name="uil:vuejs" style="color: pink" size="2.5em" />
<Icon name="uil:vuejs" style="color: red" size="3em" />
<Icon name="uil:vuejs" style="color: black" size="3.5em" />
<Icon name="uil:vuejs" style="color: green" size="4em" />
- name : Iconify上でのアイコン名を指定する
- style : CSSで色の見栄えの編集が可能になる
- size : 任意のサイズに変更できる(デフォルトは1em)
mode について
spanタグとsvgタグのどちらでレンダリングするかをmodeで切り替えられます。
<Icon name="uil:vuejs" style="color: blue" size="2em" mode="css" />
<span class="iconify i-uil:vuejs icon" aria-hidden="true" style="font-size:2em;color:blue;" data-v-938b83b0=""></span>
<Icon name="uil:vuejs" style="color: blue" size="2em" mode="svg" />
<svg data-v-938b83b0="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="icon iconify iconify--uil" width="1em" height="1em" viewBox="0 0 24 24" style="font-size: 2em; color: blue;"><path fill="currentColor" d="M18.03 2.443h-3.643L12.013 6.4L9.63 2.444l-2.646-.001H.831L12.03 21.558L23.168 2.443Zm-6.005 15.15L4.322 4.443h2.824l4.885 8.406l4.847-8.407h2.81Z"></path></svg>
Vueコンポーネントを使う
components/global/
フォルダ配下に置いたVueコンポーネントを利用して、SVGを表示することもできます。
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="1.53em" height="1em" viewBox="0 0 256 168"><path fill="#00DC82" d="M143.618 167.029h95.166c3.023 0 5.992-.771 8.61-2.237a16.96 16.96 0 0 0 6.302-6.115a16.3 16.3 0 0 0 2.304-8.352c0-2.932-.799-5.811-2.312-8.35L189.778 34.6a16.97 16.97 0 0 0-6.301-6.113a17.6 17.6 0 0 0-8.608-2.238c-3.023 0-5.991.772-8.609 2.238a16.96 16.96 0 0 0-6.3 6.113l-16.342 27.473l-31.95-53.724a17 17 0 0 0-6.304-6.112A17.64 17.64 0 0 0 96.754 0c-3.022 0-5.992.772-8.61 2.237a17 17 0 0 0-6.303 6.112L2.31 141.975a16.3 16.3 0 0 0-2.31 8.35c0 2.932.793 5.813 2.304 8.352a16.96 16.96 0 0 0 6.302 6.115a17.6 17.6 0 0 0 8.61 2.237h59.737c23.669 0 41.123-10.084 53.134-29.758l29.159-48.983l15.618-26.215l46.874 78.742h-62.492zm-67.64-26.24l-41.688-.01L96.782 35.796l31.181 52.492l-20.877 35.084c-7.976 12.765-17.037 17.416-31.107 17.416"></path></svg>
</template>
<script lang="ts">
export default {
name: 'Nuxt'
}
</script>
<Icon name="Nuxt" size="4em" />
Vueコンポーネントとnameを合わせておく必要があります。
また、常に結果はsvgタグでレンダリングされます。(modeは無視される。)
オリジナルのSVGファイルを使う
自社サイトのアイコンや自作したアイコンなどを表示したい場合もあります。
その場合、カスタムコレクションという機能を利用して、SVGを表示することができます。
例として、以下のsvgファイルを表示させたいとします。
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
まずは、任意のフォルダにsvgファイルを格納します。
ここでは ./assets/my-icons
フォルダ配下とします。
assets/my-icons
├── vite.svg
次に nuxt.config.ts
に icon.customCollections
の欄を追加します。
export default defineNuxtConfig({
modules: [
'@nuxt/icon'
],
icon: {
customCollections: [
{
prefix: 'my-icon',
dir: './assets/my-icons'
},
],
},
})
これで準備が整ったので、vite.svgを表示してみましょう。
<Icon name="my-icon:vite" size="4em" />
アイコンが表示されました!
初期値を設定する
app.config.ts
にデフォルトの値を指定することができます。
export default defineAppConfig({
icon: {
size: '4em',
class: 'icon',
mode: 'css',
aliases: {
'vitest': 'logos:vitest'
}
}
})
Iconタグでsizeやmodeを指定しなければ、 app.config.ts
に記載した値が設定されます。
また、aliasesを利用すれば指定したSVGを表示できるようになります。
<Icon name="vitest" />
おわりに
現代のフロントエンドは本当に複雑化していて、アイコン1つ取っても、スケーラビリティ・動的ローディング・SSRなど考慮しなければならない課題が複数あります。
それらの課題に対して最適なアプローチが取れるように、 @nuxt/icon を活用していきたいと思います。
参考
先日の Nuxt Nation 2024 で @nuxt/icon が紹介されていました。
Discussion