Re: [parameters] Outline for recasting SVG Parameters on top of CSS Variables

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