- From: Amelia Bellamy-Royds <amelia.bellamy.royds@gmail.com>
- Date: Sat, 1 Nov 2014 19:35:24 -0600
- To: "Tab Atkins Jr." <jackalmage@gmail.com>, www-svg <www-svg@w3.org>
- Cc: Doug Schepers <doug@schepers.cc>
- Message-ID: <CAFDDJ7zDPCYqtqM2CL+S7X7YVVL_vca-1yqkFO7Py=wP-Obfeg@mail.gmail.com>
I've been playing around with using CSS variables to customize inline SVG icons [1], so it would be great to have a way to pass in those values to SVG accessed in other ways. It would also be nice to have a more generic SVG parameter system. Some comments on Tab's rough outline: ____________________________________________________________________ <html> > <img src="foo.svg?--text=red"> > </html> Using a URL query string will disable file caching (for the same SVG file accessed multiple times with different parameters) since the browser would not be able to distinguish this from a request for a different file from the server. It could also potentially cause problems interacting with server-side query parameters. For <object> embeds there is the <param> element, but that doesn't help with images accessed as <img> or within CSS. Target fragment strings (such as are used for views) are closer to what is needed, in that they define a desired client-side processing of a file. However, there would need to be some clarification on how they interact with internal links. It's normal to have a view switch when you click on an internal link, but you wouldn't want customized styles to disappear. A parameter fragment would need to be clearly distinguished from a regular target fragment, and user agents that supported parameters would need to preserve the parameters when the target was changed. E.g., a single # followed by a token could be a target fragment, but a double ## (or a #! or similar) would introduce client-side parameters. In order to leave open the possibility of other types of client-side parameters, I've further grouped the CSS variable declarations into a single parameter-value pair below, but the benefits and limitations below apply either way. body { background-image: url( "/bg-pattern.svg##CSS-initial=--thickness:5px;--gradient1:orange;--gradient2:lightyellow" ); /* open file "/icons.svg", and set the CSS rule "--thickness:5px; --gradient1:orange; --gradient2:lightyellow" as if it was on the parent of the root element. */ } li.good-thing { list-image: url( "/icons.svg#thumbs-up##CSS-initial=--thickness:3px;--fill-color:rgb(40,40,40)" ); /* open file "/icons.svg", display it using :target styles for the fragment with id="thumbs-up", and set the CSS rule "--thickness:3px; --fill-color:rgb(40,40,40)" as if it was on the parent of the root element. */ } Such a scheme: - would still be a valid URL in browsers that do not support the scheme; - would effectively be ignored in those browsers since the parameter fragment will be interpreted as a target pointing to an invalid XML id; - would ensure that two files that differed only in parameters would be recognized in all browsers as pointing to the same file. However, you would lose support for regular target fragments in older browsers if you used both a target fragment and a parameter fragment in a URL, as in the icon example code above; the target would be parsed as random gibberish not matching any id. (Following an internal link after the file has been opened wouldn't be a problem; the new target fragment would just replace the unrecognized parameter fragment.) The scheme above could be easily extended to customize all default CSS properties, not just custom variables. ____________________________________________________________________ <svg> > <defs> > <meta name="var" content="--text black"></meta> > </defs> > <text style="fill: var(--text)">Hello World!</text> > </svg> > This example assumes the existence of a <meta> element in SVG, but > it's not strictly necessary; I'll explore some alternate syntaxes for > declaring your vars later. ... > If adding <meta> to SVG isn't acceptable, there are other options. > For example, an attribute on the root element could work: > <svg vars="var(--text, black)">...</svg> > It would accept a space-separated list of var() functions, declaring > the var name and optionally the default value for each var to be > accepted. > Theoretically, we could avoid this pre-declaring entirely, but I don't > think it's a great idea. I don't think I like the idea of using an XML element to define a default for a CSS variable. It really messes up the separation of responsibilities if you're using external stylesheets! I'm not sure it's necessary to pre-declare anything. Any variables specified would just become part of the initial CSS properties for the root element. Fallback values can already be declared at the time the variable is used. If you wanted to set global fallbacks, you could use CSS syntax like :root { --my-var-internal: var(--my-var, fallbackValue); } and then use `--my-var-internal` within the actual code. Not ideal, but workable. A nicer solution would be to change the CSS variables spec itself to state that when you use a CSS variable inside the property declaration for that variable, it equates to the inherited value for that variable (similar to how em units work in a font-size declaration); the current spec says to treat that as an invalid circular dependency [2]. Not sure if that's too big a change to make at Last Call stage (Perhaps the CSS Variables spec editor can weigh in on that one!). It wouldn't break any stylesheets that weren't already broken, but it might be a hassle for implementations! ____________________________________________________________________ Currently this is only usable in CSS properties. If SVG wants them to > be usable in attributes, it can define that all attributes accept > var() as well. (Note that var() is allowed *anywhere* in a CSS > property value; it can be preceded or followed by arbitrary other > values, including more var() functions. You also can't tell whether > the resulting value is valid until after substitution. CSS has some > special rules to handle this, since it can no longer reject invalid > properties at parse time, if they include a var(). SVG will have to > adopt similar rules.) There wouldn't need to be for any special rules for run-time rejection for XML-only SVG attributes, since these don't cascade. (The special rules for invalid CSS properties using var() are needed so that you don't have to maintain the entire cascade for each element, just the calculated value with var(), and if that doesn't work use the initial or inherited value as if the property wasn't set on that particular element). Without a cascade to worry about, the result of an invalid declaration with var() would be the same as if the invalid value was directly set on the attribute, i.e. normal error rules would apply or a default value would be used. For presentation attributes, the cascade/validation rules would be the same as for CSS. For actually using CSS variables in XML attributes, the obvious/easiest syntax is to use the CSS var() function, but then the questions would be: - Would var() only be allowed as an alternative to the complete attribute value, or could it be used for a single token within a string, as in CSS? - How would you distinguish an embedded CSS function within a free-text string attribute? - What attributes could variables substitute into? - Would var() only work for custom CSS properties, or could you use it to grab the inherited value of regular CSS properties like background-color or line-height? *(Another thing that might be nice to have in the general CSS variables specification.)* I would argue that discussion of the appropriate places to use var() in attribute values should be coordinated with discussion about implementing the calc() and possibly the attr() functions in SVG. It might also be worth discussing whether there should be a way to declare CSS variables as presentation attributes, or if inline style declarations are sufficient. This is always something that could be added in later. ____________________________________________________________________ Finally, would there be a way to set text content from variables? This would be great for many types of customization, but particularly internationalization. One option would be to simply allow the CSS `content` property (normally only used for before and after pseudoelements) to override the child content of any SVG element. In contrast, the 2009 SVG parameters proposal suggested adding a XML attribute to text elements that could contain a parameter access function, with the parameter value replacing child content.[3] (A comment in the draft asks whether it should also be supported in <title>, to which I would say most definitely! Localized tooltips are just as important as localized visible text.) That should be enough to get a discussion started... ABR [1]: http://codepen.io/AmeliaBR/thoughts/customizable-svg-icons-css-variables [2]: http://dev.w3.org/csswg/css-variables/#cycles [3]: http://www.w3.org/TR/2009/WD-SVGParam-20090616/#sec-content-value-attr
Received on Sunday, 2 November 2014 01:35:53 UTC