Closed darsain closed 8 years ago
@darsain can you please provide more details on how combined svg should look like in this case or maybe you have a link to an article? It would be also interesting to know browser support.
If you only need <g>
instead of <symbol>
, then you can rename them with gulp-cheerio until we find a better solution for gulp-svgstore.
var gulp = require('gulp');
var svgstore = require('gulp-svgstore');
var cheerio = require('gulp-cheerio');
gulp.task('default', function () {
return gulp
.src('src/*.svg')
.pipe(svgstore())
.pipe(cheerio(function ($) {
$('symbol').each(function () {
this.tagName = 'g';
});
}))
.pipe(gulp.dest('dest'));
});
To make this work in CSS:
background: url('images.svg#chart');
You need to structure images.svg
in a way that enables SVG fragment identifiers. There are 3 ways I know of:
You'd use this when all images are the same size.
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<defs>
<style>
.img { display: none }
.img:target { display: inline }
</style>
</defs>
<g id="chart" class="img">
<rect x="6" width="4" height="16"/>
<rect x="12" y="4" width="4" height="12"/>
<rect x="0" y="8" width="4" height="8"/>
</g>
<!-- more "g" tags -->
</svg>
You'd use this when every image has different size.
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<style>
.img { display: none }
.img:target { display: inline }
</style>
</defs>
<svg viewBox="0 0 16 16">
<g id="chart" class="img">
<rect x="6" width="4" height="16"/>
<rect x="12" y="4" width="4" height="12"/>
<rect x="0" y="8" width="4" height="8"/>
</g>
</svg>
<!-- more "svg > g" tags -->
</svg>
This one is sub-optimal. When mismatching target element to image size ratio, you might see other sprites peeking from sides. You'd have to make big gaps between images, but that's ugly and not bulletproof.
It is also more annoying to write build scripts for. But here it is anyway:
<svg xmlns="http://www.w3.org/2000/svg">
<view id="chart" viewBox="0 0 16 16"/>
<view id="plus" viewBox="16 0 16 16"/>
<g transform="translate(0 0)">
<rect x="6" width="4" height="16"/>
<rect x="12" y="4" width="4" height="12"/>
<rect x="0" y="8" width="4" height="8"/>
</g>
<g transform="translate(16 0)">
<mask id="m" x="0" y="0" width="1" height="1">
<circle cx="8" cy="8" r="8" fill="white"/>
<line x1="8" y1="3" x2="8" y2="13" stroke="black" stroke-width="2"/>
<line x1="3" y1="8" x2="13" y2="8" stroke="black" stroke-width="2"/>
</mask>
<rect width="16" height="16" mask="url(#m)"/>
</g>
</svg>
Currently, SVG fragment identifiers in CSS backgrounds work only in FF and IE, and will work in Chrome as soon as crbug.com/128055 is fixed.
Isolated working example implementation with all 3 solutions above here: svg-fragment-identifiers.zip
@darsain why do you need a tool for this if it is not supported in Chrome?
Something like this make it work with 2nd example. I don't say it is a good solution though, will have to reconsider it when chrome adds support for this method.
var gulp = require('gulp');
var svgstore = require('gulp-svgstore');
var cheerio = require('gulp-cheerio');
gulp.task('default', function () {
return gulp
.src('src/svg/*.svg')
.pipe(svgstore())
.pipe(cheerio(function ($) {
$('svg').prepend(
'<defs>'+
'<style>' +
'.img { display: none }' +
'.img:target { display: inline }' +
'</style>' +
'</defs>'
)
$('symbol').each(function () {
var $node = $(this);
this.tagName = 'svg';
$node
.html(
'<g id="' + $node.attr('id') + '" class="img">' +
$node.html() +
'</g>'
)
.removeAttr('id')
});
}))
.pipe(gulp.dest('dest'));
});
@w0rm to be honest, before I started researching this, I thought that Chrome did support that. Was quite surprised that it doesn't.
But still, would be nice to have this available when support hits stable.
@darsain do you have any objections regarding closing this issue as wonfix?
@w0rm yes, as this is gonna be extremely useful in near future. I have nothing against putting this on low priority until Chrome adds support, but straight wontfix? :(
@darsain I'd prefer to keep it closed, and then re-open the ticket if needed.
@darsain thanks! I'd like to treat tickets in the "action is needed" manner.
Just ran into this, too. Pretty surprising that Chrome is behind on this. Maybe the SVG implementations are not ready for today after all :)
angular/material's md-icon/$mdIconProvider requires g
instead of symbol
because it doesn't use the use
tag to display icons. This is a current use case (unlike the above discussion if it's not out of date) for a very popular framework. An option like element: "symbol|g"
would be great. Would you accept a PR with this change?
@zbjornson it may not play well with the current logic that extracts elements from <defs>
of each file and combines in <defs>
section of the result file. Also it would require test cases including visual tests. If you're willing to do this, then sure.
Was this closed because someone else made the change? If not I'm planning to do it next weekend.
@zbjornson closed because I don't need this feature. Feel free to open PR if you want this!
@zbjornson out of curiosity, why don't you use this library https://github.com/jkphl/gulp-svg-sprite? I think it supports every possible case to bundle svgs
Hmm thanks for pointing out that repo, will take a look. Have been happily using yours for almost a year and only recently needed to switch element types. If it doesn't work I'll make a PR here, thanks.
@zbjornson my library is very opinionated about bundling svgs, instead of implementing all possible methods, I did some research and focused on the method that I liked best.
https://github.com/w0rm/compare-sprite-methods — playground with different bundling methods https://tech.zalando.com/blog/creating-bulletproof-svg-icons/ — blogpost about usage with fallback http://unsoundscapes.com/slides/2015-03-19-creating-bulletproof-svg-icons/ — slides from a meetup
An option switch so we could choose between transforming files into
<symbol>
or<g>
.<symbol>
is awesome for icons, but doesn't work for CSS backgrounds.<g>
is awesome for CSS backgrounds.In other words, this doesn't work with
<symbol>
, but does with<g>
: