Open LeaVerou opened 9 months ago
Another piece of relevant prior art (though on the simpler side rather than the more complex side) is the context-fill
and context-stroke
keywords in SVG2, which are implemented in Gecko. (Also see Gecko bug 1058040 and Chromium bug 367737.)
There's no reason to use the with
keyword; the url functions already have a syntax for additional parameters, and it can be just context()
, like
content: src("icon.svg", context(currentcolor))`
/* or maybe */
content: src("icon.svg", with(currentcolor))`
I think this is a good idea, but it could benefit from hewing more closely to my Params proposal:
src("icon", with(currentcolor red, font-size 20px))
.<img src="icon.svg">
.Maybe we can just merge this into the Params proposal, so you have a set of predefined non-dashed param names you can use, in addition to using dashed idents to set variables.
(Then we can also make the value after the dashed param name optional, defaulting to taking the value of the same-named variable on the element, for cases where that name matches up.)
I think this is a good idea, but it could benefit from hewing more closely to my Params proposal:
- You might want to set the currentcolor/etc to a specific value, not just what's defined on the element. So the function should allow an optional value after each keyword. So like
src("icon", with(currentcolor red, font-size 20px))
. and Maybe we can just merge this into the Params proposal, so you have a set of predefined non-dashed param names you can use, in addition to using dashed idents to set variables.
The main motivation for this proposal was for it to be a quick win, something that can be implemented more easily than the full-blown params proposal. As long as tying it to the params proposal doesn't negate that, I think it’s a good idea to integrate them more closely to avoid the cognitive overhead on users of having to learn two distinct syntaxes for highly related things.
- There should be a way to trigger this via url as well, so you can use it in
<img src="icon.svg">
.
Agreed but this seems like a whole different feature (and far more complicated to define in a way that doesn't clash with existing params).
(Then we can also make the value after the dashed param name optional, defaulting to taking the value of the same-named variable on the element, for cases where that name matches up.)
I love this!
something that can be implemented more easily than the full-blown params proposal.
All that Params does is set the initial value of variables. It's the exact same feature as what you're proposing, just affecting a different set of things, so they should be equally easy or difficult.
Agreed but this seems like a whole different feature (and far more complicated to define in a way that doesn't clash with existing params).
Right, this is work Params has already done, so there's no need to do additional work. Just write <img "icon.svg#param(currentcolor, font-size, --shadow-color blue)">
to pass in the currentcolor and font-size from the element, and set the --shadow-color variable to blue
.
- Tab’s more recent SVG Params based on custom properties
Just to note, CSS Linked Parameters is already on the standards track.
I do like the proposal and agree with @tabatkins' idea of incorporating this into the existing syntax. So this would then look like
content: src("icon.svg", param(currentcolor))
- There should be a way to trigger this via url as well, so you can use it in
<img src="icon.svg">
.Agreed but this seems like a whole different feature (and far more complicated to define in a way that doesn't clash with existing params).
The spec. already describes a way to do that for custom properties. Based on that, this would be expressible via
<img src="icon.svg#param(currentcolor)" alt="">
The main motivation for this proposal was for it to be a quick win, something that can be implemented more easily than the full-blown params proposal. As long as tying it to the params proposal doesn't negate that, I think it’s a good idea to integrate them more closely to avoid the cognitive overhead on users of having to learn two distinct syntaxes for highly related things.
While reusing the same function, implementers could still add them independently from the custom properties syntax.
Sebastian
It seems we agree that this should be part of CSS Linked Parameters, so I adjusted the title and labels.
Sebastian
@tabatkins
something that can be implemented more easily than the full-blown params proposal.
All that Params does is set the initial value of variables. It's the exact same feature as what you're proposing, just affecting a different set of things, so they should be equally easy or difficult.
My understanding was that there were some concerns around security about the general case of allowing any page to set arbitrary CSS variables on any resource.
To the extent that those concerns are problematic, I think setting the default color and font of arbitrary SVG images would be at least as bad, and likely worse. ^_^
If I understand @dbaron correctly, Gecko already extends SVG2’s context element to the HTML host element, i.e. <img>
, which can be styled with CSS.
The context-fill and context-stroke values are a reference to the paint layers generated for the fill or stroke property, respectively, of the context element of the element being painted. The context element of an element is defined as follows:
- If the element is within a ‘marker’, (…)
- If the element is within a sub-tree that is instantiated with a ‘use’ element, then the context element is that ‘use’ element.
- [Gecko extends this to the HTML host element and both values,
context-fill
andcontext-stroke
, become the host’scurrentColor
.]- Otherwise, there is no context element.
This means, the SVG code might need to be changed to use the respective values, context-fill
and context-stroke
, but HTML and CSS would not need to be altered in many cases – whereas both must be specially prepared accordingly for CSS Linked Parameters.
<style>.icon {color: green;}</style>
<img class="icon" src="#icon" />
<img class="icon" src="icon.svg" />
<img class="icon" src="sprites.svg#icon" />
<svg id="icon"><path fill="context-fill" d="M 1744 267, 711 1300, 176 765, 0 941 l 711 711, 1209 -1209 z"/></svg>
<svg><use class="icon" href="#icon"/></svg>
<svg><use class="icon" href="icon.svg"/></svg>
<svg><use class="icon" href="sprites.svg#icon"/></svg>
I didn’t look far enough into the “bug” discussions to understand whether this would also apply to SVGs used from CSS, but I would expect so:
i {color: green;}
i::before {content: url("icon.svg");}
i::after {content: url("sprites.svg#icon");}
I think this is the proper approach, but I understand that this isn’t viable in many scenarios, because the SVG cannot be changed by the CSS author for some reason – but then param()
will likely also fail.
I also wished, SVG and HTML could simply reference a shared CSS stylesheet or reuse some (proposed) Shadow DOM mechanism.
:host(img.icon) path {fill: green;}
img.icon::shadow > svg path {fill: green;}
img.icon >>> path {fill: green;}
img.icon:root(svg) {color: green;}
However, being able to set the initial expansion of predefined keywords from link parameters would be nice as well.
<img class="icon" src="icon.svg#param(context-fill green)"/>
<img class="icon" src="sprites.svg#icon#param(context-fill green)"/><!--?-->
i::before {content: src("icon.svg" param(context-fill green));}
i::after {content: src("sprites.svg#icon" param(context-fill green));}
I really like the idea of integrating this with link-params, but I'm not totally sure I've followed the mechanism that's proposed here.
link-params allow a source document to set a variable in the target document, with the value is passed through to the target document as if the variable were set in a user-agent stylesheet (or any equivalent process resulting in the rules having lower priority than any rules set in the target)
Properties in the source document
------------------
link-parameters: param(--foo x);
Effective new user-agent stylesheet in the target document
------------------
:root { --foo: x }
And if x
is missing in the param()
, it defaults to the value the same variable in the source document; so var(--foo)
If I understand this proposal, the idea is to extend this so if the parameter name is not a custom-ident, it's parsed as a CSS property name and the default value is the source element's computed value of that property.
Properties in the source document
------------------
font-family: serif
link-parameters: param(font-family);
Effective new user-agent stylesheet in the target document
------------------
:root { font-family: serif }
Is that correct? I like it if so, easy to use and no harder to implement than regular link-params. Two questions:
param(color)
not param(currentcolor)
in this case?font-family
that refers to downloaded fonts, the idea is that the target document also inherits any @font-face
rules that define the family?
Problem statement & Motivation
This is an area of the web platform where small improvements could save authors a lot of pain.
Right now, authors frequently want to reuse vector icons with different colors for different parts of their UI (often even changing the color with user interactions). The current ways to do that are:
<use>
element, so that its color can change viacurrentColor
.For example, look at the ways Bootstrap Icons and Font Awesome recommend for embedding. All this complication is done entirely to pass currentColor to the icon!!
While color is the primary use case, there are other context aspects that it would be useful to be able to pass to linked files, such as:
Prior art
There have been several SVG Params specs, but none moved forwards:
<param>
elements in<object>
These are strictly more powerful, and would solve a superset of use cases, but are also far more complex to implement.
Proposal
I want to propose something much simpler: A way to pass aspects of the page’s CSS context to an SVG linked via CSS (and hopefully later backport to HTML
<img>
). We could even start entirely withcurrentColor
, since that’s by far the biggest author pain point.We could extend
src()
with a second argument for passing parameters to the resource being embedded, possibly after awith
keyword (inspired from JS Import assertions).Then, we could either use a series of keywords (where
color
passes currentColor) or acontext()
function that takes a series of keywords.The keywords themselves could be named after CSS properties (e.g.
color
,font
) or values (e.g.currentColor
).I’m proposing extending
src()
only since its parsing is simpler, but we may want to extendurl()
as well (when strings are used for the URL).