Changing Fill value of a inlined SVG

Hello! First post here, congrats to the devs and the community for this awesome project.

I’m new to webpack and I’ve seen that SVGs included in SCSS are automatically encoded in base64 and inlined to CSS

Example:

mask: url('../images/svg/droplet.svg') no-repeat 50% 50%;

to

mask: url(data:image/svg+xml;base64,PD...o=) no-repeat 50% 50%;

That’s Great! Now, i would like to change the Fill property the SVG on the fly, let’s say being able to change color on :hover .

I’ve found some webpack loaders that can do it but i’ve not been able to implement them on sage:

Example : svg-fill-loader
But i was not able to configure it properly because i can’t read the webpack.config.js correctly.

Have anyone already implemented it in their projects?

1 Like

I have the same exact question! Anyone solve this yet?

This library looks like it has pretty detailed instructions re: how to update your webpack config: https://github.com/kisenka/svg-mixer/tree/master/packages/svg-transform-loader

When you say “change the Fill property the SVG on the fly,” I assume you mean “re-write the fill property during the build process”? Because AFAIK there’s no way to modify SVG properties live, in the browser, unless they’ve been inlined into your HTML.

@alwaysblank
I believe he wants to have control over how the svg icon is getting inlined into CSS by webpack and this can be achieved by the webpack loader mentioned above.

You are right that doing that from CSS would mean inlining that SVG into HTML (and I would go that way in most scenarios).

@krishaamer if you want to change svg color on hover please do not use method below but rather inline your csv in HTML


@krishaamer @sinsimon

As @alwaysblank mentioned the docs for implementing the loader are rather straighforward but in case you feel overwhelmed by webpack (same as I was when it became “the thing” some years ago) I will try to give you some direction.

As I do not have sage 9 available for me at the moment I cant test it my idea but just out of my head if you modify webpack.config.js loader rules to be something like:
[ starting at line 97 of the file https://github.com/roots/sage/blob/master/resources/assets/build/webpack.config.js#L97 ]

{
	test:    /\.(ttf|otf|eot|woff2?|png|jpe?g|gif|ico)$/,
	include: config.paths.assets,
	loader:  'url',
	options: {
		limit: 4096,
		name:  `[path]${assetsFilenames}.[ext]`,
	},
},
{
	test: /\.svg(\?.*)?$/, // match img.svg and img.svg?param=value
	include: config.paths.assets,
	use:  [
		{
			loader:  'url-loader',
			options: {
				limit: 4096,
				name:  `[path]${assetsFilenames}.[ext]`,
			}
		},
		{ loader: 'svg-transform-loader' }
	]
},

If you care about svgs loaded from node_modules you should do the same for the following rules in the config.

Please also remember about properly encoding your “#” character mentioned by loader docs like
.img {background-image: url(img.svg?fill=%23f0f)} Otherwise more config modifications are needed to make it work.


Proper solutions should involve some restructurization of config file or usage of multi-loader but I do not want to overcomplicate stuff here

1 Like

@alwaysblank @owi
Thank you guys, with your instructions I did it!

So i did:
yarn add svg-transform-loader

Then i changed the webpack config removing svg from line 97 and 106 and adding this after:

      {
        test: /\.svg(\?.*)?$/,
        include: [
          /node_modules/, 
          config.paths.assets
        ],
        loader: [
          'url', 
          'svg-transform-loader'
        ],
      }, 

Then I added { loader:'svg-transform-loader/encode-query-loader'} and keepQuery: true on scss test for handling the # and ? correctly.

     {
        test: /\.scss$/,
        include: config.paths.assets,
        use: ExtractTextPlugin.extract({
          fallback: 'style',
          use: [
            { loader: 'cache' },
            { loader: 'css', options: { sourceMap: config.enabled.sourceMaps } },
            { loader:'svg-transform-loader/encode-query-loader'},
            {
              loader: 'postcss', options: {
                config: { path: __dirname, ctx: config },
                sourceMap: config.enabled.sourceMaps,
              },
            },
            {
            loader: 'resolve-url', 
              options: { 
                sourceMap: config.enabled.sourceMaps,
                keepQuery: true,  
              } 
            },
            { loader: 'sass', options: { sourceMap: config.enabled.sourceMaps } },
          ],
        }),
      },

now i can use svg as a background image like:

background-image: unquote('url("' + $url + "?fill=" + $color +'")');

as @owi said, my next project i will include them in the html and use the CSS fill property, but this time it was useful to being able to refactor a css mixin that was using CSS mask with svg for adding compatibility for IE and Edge.

4 Likes

Thank you @sinsimon! Your solution did the trick, but I had to change this:

{ loader:'svg-transform-loader/encode-query-loader'},

to this:

{ loader:'svg-transform-loader/encode-query'},

to make it work.