qrac / minista

Static site generator with 100% static export from React and Vite.
https://minista.qranoko.jp
161 stars 13 forks source link

Iconコンポーネントでstyle付きのSVGを使うと、クラス名でバッティングして正しく表示されなくなる #123

Open FuCrowRabbit opened 1 month ago

FuCrowRabbit commented 1 month ago

Iconコンポーネントでstyle付きのSVGを使うと、クラス名でバッティングして正しく表示されなくなる

Adobe Illustratorで書き出されたSVGは、.cls-1など似たようなクラス名を付けられることが多く、そのまま使うとスタイルがマージや上書きされ、正しく表示されなくなる事があります。

icon1.svg (赤四角)

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
    <defs>
        <style>.cls-1 { fill: #f00; }</style>
    </defs>
    <rect class="cls-1" width="20" height="20"/>
</svg>

icon2.svg (緑四角)

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
    <defs>
        <style>.cls-1 { fill: #0f0; }</style>
    </defs>
    <rect class="cls-1" width="20" height="20"/>
</svg>

TSXでの呼び出し

import { Icon } from 'minista';

export default function () {
  return (
    <>
        <Icon iconId="icon1" />
        <Icon iconId="icon2" />
    </>
  );
}

↓ ビルドを行う ↓


出力されるicons.svg(整形済)

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <style>.cls-1 { fill: #f00; }</style>
        <style>.cls-1 { fill: #0f0; }</style>
    </defs>
    <symbol id="icon1" viewBox="0 0 20 20">
        <rect class="cls-1" width="20" height="20"/>
    </symbol>
    <symbol id="icon2" viewBox="0 0 20 20">
        <rect class="cls-1" width="20" height="20"/>
    </symbol>
</svg>

結果

<use href="/assets/images/icons.svg#icon1"></use> <!-- 緑四角が表示される(赤四角のはず) -->
<use href="/assets/images/icons.svg#icon2"></use> <!-- 緑四角が表示される -->
qrac commented 1 month ago

@FuCrowRabbit なるほどー。これはSVGに含まれているクラス名をUID的なもので付け直す処理が必要な感じですかね? 単色のSVGしか試していなかったので、色ありでも試してみます。

qrac commented 1 month ago

@FuCrowRabbit こちらを検証してみたところ、確かにIllustratorから出力したままのSVGだとスタイルタグが面倒なことになりますね。 解決するにはスタイルタグをインラインスタイルに変換するのがベターで、主にSVGOなどの圧縮ツールで変換できるようです。

v3には圧縮ツールが入っていないので、ImageOptimなどで圧縮したSVGを用意いただくと理想の形になります。 v4ではSVGOを依存に加えて事前処理をするようにしてみます。

FuCrowRabbit commented 1 month ago

@qrac ありがとうございます。 インラインスタイルに変換するアイデアで解決が出来そうです。

ちなみにデザイナーに確認したところ、単色SVGの時でも場合によっては発生する事があるそうです。 それは、サイズ調整のために透明な矩形でアイコンを囲うテクニックを使った時になります。 その透明な矩形が塗りつぶされてしまう事があるようでした。

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
  <defs>
    <style>
       .cls-1 { fill: none; }
       .cls-2 { fill: #222; }
    </style>
  </defs>
  <path class="cls-2" d="<!--表示したいアイコン-->"/>
  <rect class="cls-1" width="20" height="20"/>
</svg>  
qrac commented 1 month ago

@FuCrowRabbit こちらのすべての問題をv4で解決しました!

そのほか、すでに完成しているSVGスプライトも混ぜてマージできる機能も実装しました。