Customizing styles of a SVG document from the outside


#1

Use case

A little while ago I started using SVG for icons and needed to customize the style of specific SVG elements in a referenced SVG document depending on:

  1. Context. Where the icon is used and what the surrounding styles are.
  2. User interaction. Especially hover, focus and active states.

I also needed something that can work for both icons referenced from HTML (e.g. with an <img> element) and from CSS (mostly as a background-image). Currently there are some solutions for HTML, which require inlining the SVG glyphs and using <svg><use xlink:href="…" /></svg>, and nothing for CSS (except SVG stacks which requires carefully planning the different styles in the original SVG file, duplicating elements, etc.).

It would be great to be able to use the power of SVG-with-CSS for referenced SVG documents as well.

Perhaps a solution should be added to the SVG Integration spec effort?

Idea: with CSS vars?

A little while ago I wrote Let’s dream: customizing SVG images with CSS Variables. The idea is that CSS variables defined or inherited on an element would be passed to any SVG document referenced by that element, be it as a src or background-image.

I meant to update that post for the past few weeks but I thought I’d rather present the idea here and ask for your feedback, and see if you might think up alternative solutions.

Why not icon fonts?

A common solution for the use-cases described above and in the above link is icon fonts. Sadly icon fonts are a hack, and have the same kind of accessibility issues as using CSS backgrounds to represent content (especially icon-only buttons or links). There are efforts right now to make icon fonts more usable for designers and developers, but not particularly more accessible (or less hackish).

The total lack of a simple accessibility mechanism such as <img alt="…"> makes icon fonts fundamentally inaccessible (and mapping to vaguely relevant unicode characters is a laughable “solution”… try it with a screen reader).

Example from this very site

If I disable author font-family declarations in my browser (“Allow pages to choose their own fonts, instead of my selection above”), this is what the main menu for this website looks like:

http://fvsch.com/temp/icon-fonts.png [can’t inline the image as a new user]

Icons are implemented with the FontAwesome icon font. This implementation breaks with no sensible fallback if users don’t allow fonts, or if the font file was not loaded for any reason (unreliable and/or slow network anyone?).

With <img src="the_svg_file" alt="…"> instead, we’d still have the icons. And with images turned off, we could have text alternatives reading, e.g.:

[Name] | Notifications | Search | Go To | Account

The main issues with using <img> here with SVG are:

  1. HTTP optimization. For raster images, commonly fixed with image sprites (introducing accessibility issues). For SVG, probably fixed by either HTTP2 or SVG stacks.
  2. Style customizations, which awaits a sensible solution (as far as I know).

Any ideas?


#2

SVG Integration spec: http://www.w3.org/TR/svg-integration/


#3

There’s an old draft that might point towards a (partial) solution: http://www.w3.org/TR/SVGParam/. I have no idea where it is now, but it might be salvageable.

Another option that could be interesting would be to surface the apply-author-styles from the Shadow DOM (http://www.w3.org/TR/shadow-dom/#dfn-apply-author-styles) for instance on img so that you could have styles on the image cascade down into the SVG.

(Just a couple thoughts.)


#4

CSS Variable was indeed seen as possibility to be able to set values from out site of the document. It was seen as a counter proposal for SVG parameters for some time.

It would be interesting for styling SVG Filters for instance:

CSS:

filter: url(#filter)

SVG:

<filter> <feFlood flood-color=“var(–flood)”/></filter>

Other resources like gradients, masks or patterns could be styled as well. However, possible security issues must be checked first.

For your special use case there are new color keywords in SVG that you can use in combination with SVG OpenType fonts. Called context-fill and context-stroke http://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint


#5

Thanks for your input. I haven’t looked at SVG Params in depth yet.

For the sake of dreaming up CSS-centric solutions, I suspect using CSS vars might be abusing the responsibility of CSS variables. Maybe a selector solution could be used instead. For instance if we have a series of <img class="icon" src="some_svg_file" alt="…"> elements, we could pass some styles to the SVG documents like this:

.icon::image-document(.someSelector) {
  fill: red;
  stroke: black;
  stroke-width: 10;
}

And similarly (or with a different pseudo-element/pseudo-class name) for CSS images.

This would work like having a new <style> element in the SVG document with the following styles:

.someSelector {
  fill: red;
  stroke: black;
  stroke-width: 10;
}

To limit complexity, the selector argument could be limited, like with the :not() pseudo-class, and the admitted CSS properties could be limited an explicitly defined subset (all other properties being ignored then).

Just an idea.


#6

The Params spec needs to be rebased over CSS Variables, where the params set custom properties on the root implicitly. Then everything would Just Work©. I’ve discussed this with Shepers already, but he hasn’t gotten around to making any edits.


#7

I wanted to raise a very similar idea indepndently, but then I noticed this post.
My idea was to use a pseudo-element as a root:

.icon::background-image .someSelector {
    fill: red;
    stroke: black;
    stroke-width: 10;
}

which would have a potential benefit of allowing some styles to apply to the background-image itself as well (even if its a non-SVG).

E.g. later on you could allow filter on ::background-image instead of introducing background-filter, etc.


#8

Styling cross-document is a difficult, probably security-conscious thing. Also, that doesn’t address multiple background layers, and doesn’t allow you to do any manipulation of the image (wrap it in a filter() or cross-fade() function, for example), as that would hide it from the selector.

Best is to just get SVG Params to be a real thing, and pass in info that way.


#9

I thought about it a bit more, and I agree that params (especially if integrated with CSS vars) is the best idea, if just for the encapsulation reasons.


#10

SVG Params w/ CSS variables seem to be the way to go indeed. I have two questions:

Is there a way to show interest (especially from web developers) in seeing this spec pushed forward?

Would it be useful to document use cases for styling referenced SVG graphics (which may or — more importantly may not — match SVG Params’ intended feature set)? The RICG folks recently published a document with use cases for Element Queries. Perhaps a similar approach would be helpful here?


#11

It’s not being stopped by lack of interest, just a lack of time on the part of either me (the Variables editor) or Doug Shepers (the guy who wrote the original SVG Parameters spec, pre-Variables). We’ll get to it in time.

Note that only FF has support for Variables right now anyway, so getting Params out sooner won’t actually have much effect.