svg-fill-loader

Webpack loader that changes colors in SVG images

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
svg-fill-loader
7200.0.86 years ago6 years agoMinified + gzip package size for svg-fill-loader in KB

Readme

SVG fill loader for Webpack Build Status Coverage Status
Webpack loader that changes colors in SVG images. Useful when you embed SVG in CSS as background image and don't want to produce tons of identical files which only differ in their fill attributes.

Allow to do something like this in CSS:
.icon {
  background-image: url('./image.svg?fill=#fff');
}

And something like this in SCSS/LESS/Stylus/etc:
// _config.scss
$icon-color: #fff;

// styles.scss
@import "_config.scss";
.icon {
  background-image: url('./image.svg?fill=#{$icon-color}');
}

Table of contents
- fill - raw - selector - renderOptions - Using with css-loader - Using with resolve-url-loader - Further SVG handling

Installation

npm install svg-fill-loader --save

Configuration

Loader has two settings levels:
  1. Webpack config.
  2. SVG file import statement (background-image: url('./image.svg')).

Any option defined in webpack config level, can be overridden in file level.

fill (required)

Color to repaint with. Specified in the SVG import statement as a required attribute.
.image {
  background-image: url('./image.svg?fill=red');
}

This will result in that each of the repainted tags will receive the fill="red" attribute; in case you need other attributes, like stroke - feel free to submit an issue about that.

raw (optional, true by default)

By default the loader returns the repainted SVG as-is, which is convenient for further processing with file-loader (e.g. to create a separate file), or url-loader/svg-url-loader (to embed it in CSS code). However, sometimes you might need to get the image as a module (like, for rendering with React). In this case, you'll need to set raw=false:
{
  test: /\.svg/,
  loader: 'svg-fill-loader?raw=false'
}

This can also be done via import statement, but try avoiding this way:
import icon from './icon.svg?fill=red&raw=false';

selector (optional)

CSS selector for nodes to be repainted. Very simple CSS selectors are supported:
  • tag selector: path.
  • id selector: #id.
  • class selector: .class.
  • selectors can be combined via comma: circle, .path, #id.

All presentation SVG tags are used as default selector. You can find them in lib/posthtmlPlugin.js.

Webpack 1.x config example:

It's safe to pass all SVGs through loader, if no fill param presented it just returns original source.
module.exports = {
  module: {
    loaders: [
      {
        test: /\.svg(\?fill=.*)?|$/,
        loaders: [
          'svg-url-loader', // or url-loader
          'svg-fill-loader?selector=path,circle' // `selector` option will be used for all images processed by loader
        ]
      }
    ]
  }
}

Webpack 2.x config example:

module.exports = {
  module: {
    rules: [
      {
        test: /\.svg$/,
        use: [
          'svg-url-loader', // or url-loader
          {
            loader: 'svg-fill-loader',
            options: {
              selector: 'path,circle' // `selector` option will be used for all images processed by loader                 
            }
          } 
        ]
      }
    ]
  }
}

renderOptions (optional)

Overwrites render options - how SVG file will be rendered.

Important notes

Using with css-loader

If you're using css-loader to handle CSS, keep in mind that it will cut away symbols after # when handling imports via url(...), which means that the expression url(image.svg?fill=#f00) will be treated as url(image.svg?fill=), and the loader will not be able to handle the file. As a workaround, you can use %23 instead of sharp (ffffuuuu), or use the encodeSharp loader that is shipped with svg-fill-loader (yey!). Mind the order in which loaders are used:

Webpack 1.x

module.exports = {
  module: {
    loaders: [
      {
        test: /\.svg(\?fill=.*)?|$/,
        loader: [
          'url',
          'svg-fill'
        ]
      },
      {
        test: /\.sass$/,
        loaders: [
          'css',
          'svg-fill/encodeSharp', // <- encodeSharp loader should be defined BEFORE css-loader
          'sass' // but after any other loaders which produces CSS
        ]
      }
    ]
  }
}

Webpack 2.x

module.exports = {
  module: {
    rules: [
      {
        test: /\.svg$/, 
        use: [
          'url-loader',
          'svg-fill-loader' 
        ]
      },
      {
        test: /\.sass$/,
        use: [
          'css-loader',
          'svg-fill-loader/encodeSharp', // <- encodeSharp loader should be defined BEFORE css-loader
          'sass-loader' // but after any other loaders which produces CSS
        ]
      }
    ]
  }
}

Alternative approach using mixin

You can also use mixin for this instead of webpack configuration:
@mixin apply-background-image($url, $color) {
   $base-color: str-slice(inspect($color), 2);
   background-image: unquote('url("' + $url + "?fill=%23" + $base-color +'")');
 }
And use it like this:
$hex-color: #e6e6e6;
.your-class {
  ...
  @include apply-background-image("../your/image.svg", $hex-color);
  ...
}

Using with resolve-url-loader

If you're using resolve-url-loader for rewriting paths in SCSS/LESS/etc, keep in mind that it will remove query string by default for some reason and fill-loader will not be able to handle fill= param. To fix this set keepQuery option in resolve-loader:
{
  test: /\.scss$/,
  loaders: [
    'css-loader',
    'resolve-url-loader?keepQuery', // <- this!
    'svg-fill-loader/encodeSharp', // encode sharp symbol FTW!
    'sass-loader'
  ]
}

Further SVG handling

Don't forget that this loader leaves any further SVG processing to your choice.
You can use:
  • url-loader/svg-url-loader to inline the SVG into CSS.
  • file-loader to save SVG as a file.
  • gtfo-loader to ooops.