icons icon indicating copy to clipboard operation
icons copied to clipboard

More efficient way to use icons as <svg> that can be color changed with CSS easily?

Open nextgenthemes opened this issue 2 years ago • 4 comments

I am no SVG expert, but it seems to me that.

  • The <img> method does not allow recoloring of the image with CSS color.
  • The <svg><use> method downloads a massive SVG sprite. With 100s of icons that nobody will ever use in one project. Incredibly inefficient. You can not even use a CDN for it because of cross-origin not working in chrome (still?).
  • The icon font method is kind of an outdated and method that is not really semantically sound and also downloads all kinds of icons without a reason for it. Not a fan of icons fonts, for more reasons than just size.
  • Copying the entire SVG for every single icon can be done but if you use the same icons multiple times on a page is also not the most efficient, it also passes on the opportunity as the browser caches single icon SVGs (or a sprite for that matter). It's annoying to work with, having this long SVG strings copied and pasted into some files or having to have server side code injecting it ... I saw JS libs that basically inject icons for you, and you just need to put some small bit of HTML in your code, but why??
  • The not by you documented <svg><image> method does not support coloring with CSS color I think. But that is basically what I would like.

So if I would like to use the <svg><use> method for easy referencing the icons and properly coding them with <svg> I could of course create my own sprite, but it seems too much of a hassle and the required icons may change later.

So my question is, would it not be a great method to basically create a "sprite" that contains just a single <symbol> for every icon, so we can use the <use> method for just the icons we need? With HTTP/2+ HTTP requests do not matter anymore. The browser would download and cache only the icons we need, and we also benefit from the easy recoloring with CSS and having relatively short code to deal with that of course also can be just put into reusable functions where you just pass icon id and some other things.

<svg ...>
  <use href="bs-icons/user.svg#id"/> <!-- just a single <symbol> in there -->
</svg>
...
<svg ...>
  <use href="bs-icons/github.svg#id"/> <!-- just a single <symbol> in there -->
</svg>

Insane 2020 method of coloring SVG with filters. https://stackoverflow.com/a/53336754 I hate it.

Some weird way to color SVGs, seems hacky and stupid to me https://medium.com/@no.steiner/change-svg-icons-color-with-css-only-ba6a4912e6ba (not really looked at it long, may be the same as the above)

nextgenthemes avatar Apr 29 '22 22:04 nextgenthemes

What's really sad is that all you need really is to have a fill="currentColor" on the path and everything works just fine most of the time.

For my part, I created a web component that loads the svg (and therefore is cached later on) and injects the fill="currentColor" attribute which is a sane default. Then, since the svg is injected into the dom, you are free to use css to style it differently if needed. https://github.com/lekoala/last-icon

I don't think there is a way around using a little bit of javascript for this. On the good side of things, it makes the html much much cleaner.

lekoala avatar Jun 02 '22 11:06 lekoala

@lekoala

What's really sad is that all you need really is to have a fill="currentColor" on the path and everything works just fine most of the time.

What you mean. What method? Most of the time?

nextgenthemes avatar Jun 05 '22 21:06 nextgenthemes

@nextgenthemes most of the time = if you need the icon to be same color as your text. this way, even external svg is colored properly. otherwise indeed you need to inject the svg code so that you can apply custom css to change the color.

lekoala avatar Jun 06 '22 10:06 lekoala

We include the easiest ways to use our icons by default, but yes, at this scale with the number of icons we have, your best bet is going to be customizing the sprite for your own needs or leveraging the CDN. I do a custom sprite in the Bootstrap docs—just manual copy-pasta for now. Might be helpful I think to be able to pass a custom list of icons to the build scripts to generate a sprite just for you. Would love suggestions or PRs for that.

Could also include an option to copy the SVG as a symbol instead of an SVG on each page.

mdo avatar Jun 07 '22 17:06 mdo

Is there a way we can extract icons used in html/js during build time (webpack/...), to build a custom SVG sprite AND font file?

Having a best practice for this will make sure continue growing the icons library won't negatively affect page performance for projects using bootstrap icons. While still letting them take advantage of benefits SVG sprite and font file has (styling via css, size auto inherited when used as font, not having to embed source SVG that might improve across releases)

Per 1.10.2: font is now at 128kb (css 10kb with brotli + 118kb woff2), and SVG sprite is 164kb with brotli, both growing steadily per new release (as it should).

andrerom avatar Nov 29 '22 08:11 andrerom

This easy to do from npm.

I checked out the bootstrap icons repo and looked at how they generate their bootstrap-icons.svg file. It's just the svg-sprite package.

Copy the svg-sprite.json from the repo, install the svg-sprite, and then this command lets you create you own bootstrap-icons-custom.svg file that has only the objects you explicitly selected.

image

image

The full npm run command is:

svg-sprite --config svg-sprite.json --log=info --dest=../wwwroot/svg node_modules/bootstrap-icons/icons/list-ul.svg node_modules/bootstrap-icons/icons/heart-fill.svg

Here it takes two svg files and packages them into the bootstrap-icons-custom.svg file and puts it in the --dest folder of your choice. If you want more svg files, just add more files explicitly.

The usage is identical to what the website recommends:

image

And voila, you have only the svg files you want, but you're also able to use fill="currentColor" magic that lets you change colors with CSS.

3dots avatar Feb 01 '23 10:02 3dots