6
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

React.js で SVGファイルのサイズや色をCSSで変える方法

Posted at

前提

  • React.js, webpack
  • ReactでSVGファイルをimgとして読むとスタイルをCSSで変更できない(サイズはできるが色はできない)のでinlineで読む必要がある
  • 複数のサイズや色のために複数のSVGファイルを用意したくない
  • SVGファイルを変換したReact Componentのファイルも作りたくない

概要

  • inline SVGとして埋め込む方法3つ
  • CSSでスタイルを上書きする方法

を紹介
利点としてはSVGをReact Component化せずそのまま使うことで、(デザイナーの用意した)素材を極力そのままにし、ファイル数も増やさずに色を変えることができる

SVGの埋め込み方

1. raw-loader + dangerouslySetInnerHTML の場合

webpack.config.js
        test: /\.svg$/i,
        loader: 'raw-loader',
jsx
import Hoge from '... .svg'
...
<div dangerouslySetInnerHTML={{ __html: Hoge }} />

typescriptならパスを通したglobal型置き場に次のように書く

global.d.ts
declare module '*.svg' {
  const content: string;
  export default content;
}

利点

  • 変換も何もされないので詰まったり失敗しない

欠点

  • dangerously

2. react-svg-loader の場合

https://github.com/boopathi/react-svg-loader/tree/master/packages/react-svg-loader を使う

webpack.config.js
      {
        test: /\.svg$/,
        use: [
          "babel-loader",
          {
            loader: 'react-svg-loader',
            options: {
              svgo: {
                plugins: [
                  { removeViewBox: false }, // to enable overwriteing width/height by CSS
                  { moveElemsAttrsToGroup: false }, // to prevent attribute destruction for overwriting color by CSS
                ],
                floatPrecision: 2,
              },
            },
          },
        ],
      },

ここでsvgoのオプションをdisableしているのは自分の扱うsvgが壊れないように設定した項目だが、扱うsvgによって別のdisableが必要かもしれない

jsx
import Hoge from '... .svg'
...
<Hoge />

typescriptならパスを通したglobal型置き場に次のように書く

global.d.ts
declare module '*.svg' {
  const content: React.ComponentType;
  export default content;
}

利点

  • 巨大ツールでない
  • 噛ませるbabel-loaderを自由に指定できる
    • next.config.js の defaultLoaders.babel とか

欠点

  • 最近メンテされてないっぽくてリリースがない
  • svgoを無効化できない
    • SVGの中身によっては更にsvgoのオプションをdisableしないとスタイルを上手く上書きできないかもしれない

3. svgr の場合

https://github.com/gregberge/svgr を使う以外のコードの部分はreact-svg-loaderと同じなので差分だけ書く

  1. https://react-svgr.com/docs/webpack/ に従う
  2. svgr.config.js を設定する
svgr.config.js
module.exports = {
  svgoConfig: {
    plugins: {
      removeViewBox: false, // to enable overwriteing width/height by CSS
      moveElemsAttrsToGroup: false, // to prevent attribute destruction for overwriting color
    },
  },
};

最適化不要、またはファイルに直接かけておく方針なら、svgoを無効化してしまう

svgr.config.js
module.exports = {
  svgo: false,
};

利点

  • メンテ・リリースが続いている
  • svgoを無効化できる
    • 破壊的変更のせいでうまくいかなかったら無効化で逃げれる
  • star多し
  • webpack以外にも対応

欠点

  • 依存ライブラリがちょっと多そう

スタイルの当て方

埋め込んだSVGやそのラッパーdivに対しCSSで以下のように書けばサイズや色を変えれる

    svg {
      width: 70px;
      height: 70px;
    }
    svg * :not([stroke='none' i]) {
      stroke: red;
    }
    svg * :not([fill='none' i]) {
      fill: red;
    }

ポイントは、SVGの色指定はstrokeとfillがあるので、それらがnoneでない箇所を上書きする点

所感

  • サクッと実現するならraw-loader + dangerouslySetInnerHTML
  • キレイにimportして埋め込みたいなら svgr
  • 2つのツールがデフォルトで使うsvgoのデフォルト設定がSVGを破壊的に変更するので曲者
  • @svgr/cli などを使ってSVG用のReact Componentを作ってPropsで柔軟に中身を変えるのもアリだけど、SVG素材とReact Componentでほぼ重複するのも悲しいし、用意された素材との同期などが少し面倒

参考

6
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?