Re: [csswg-drafts] [selectors] Styling Content in <img> Elements (#3730)

Some background for everyone:

Styling/modifying embedded SVG has been discussed in many contexts.  Here's an overview of some of the main approaches that have been proposed.  I'll add my thoughts/suggested next steps in a separate post.

## SVG Parameters

The [SVG Parameters spec](https://www.w3.org/TR/SVGParamPrimer/), edited by @shepazu, was published by the SVG WG as an official WD in 2009.  Parameters, in this sense, are aspects of an SVG file that are designed to be set by the external web page — it could be something like a fill color, or text content (for a fancy button/icon label), or an aspect of geometry (for a dashboard/data viz widget).

For SVG embedded as an `<object>`, the parameters would be set using the `<param>` element. For other types of embedded SVG, the proposal suggested using URL query strings:

```html
  <object type="image/svg+xml" data="icon.svg">
    <param name="param1" value="value1" />
    <param name="param2" value="value2" />
  </object>
  <img src="icon.svg?param1=value1&param2=value2" />
```

A new `<ref>` element in SVG would have allowed SVG authors to declare the available parameters and their default values.  Those values would then be used throughout the SVG file using cross references to the ref element id.

## SVG Parameters + CSS Variables

In 2014, @TabAtkins worked with Doug to come up with [a new spec that integrated with SVG parameters CSS custom properties](https://tabatkins.github.io/specs/svg-params/): the parameters would be custom props.  You could pass values to an image used in CSS with a URL modifier:

```css
.foo {
  background-image: url("http://example.com/image.svg" param(--color var(--primary-color)));
  /* pass the value of the --primary-color variable from the outer document
      in as the initial value of the --color value inside the SVG file */
}
```

I believe the plan was that `<object>` and `<param>` could still work as in the original proposal, but the URL notation for `<img>` elements was switched to use hash fragments (similar to [SVG view fragments](https://svgwg.org/svg2-draft/linking.html#SVGFragmentIdentifiers)), to avoid the [caching issues from using query strings](https://lists.w3.org/Archives/Public/www-svg/2014Nov/0001.html).
 
```html
<img src="icon.svg#param(--text-color%20blue)param(--bg-color%20white)” />
```

Inside the SVG, the passed-in values would be accessed using `var()` notation, assuming increased conversion of SVG geometric attributes to CSS properties and eventual support for CSS generated content in SVG text.  Default values for the custom properties could be set using standard CSS mechanisms, although Tab also suggested [in the initial email discussion](https://lists.w3.org/Archives/Public/www-svg/2014Nov/0000.html) that SVG could still have a dedicated element for declaring available variables and setting their defaults.

## Context value keywords

An alternative approach is the idea of `context` values: Special keywords that could be used in most SVG properties to refer to values from the outer "context".

Context values were initially proposed for SVG markers (e.g., arrowheads), so that they could match with the color of the fill/stroke of the line/shape they are marking.  Because you often want the fill of the marker to match the stroke of a line, [`context-fill` and `context-stroke`](https://www.w3.org/TR/2018/CR-SVG2-20181004/painting.html#SpecifyingPaint) would be dedicated keywords that could be used in either property. A more generic `context-value` keyword was proposed for use in any SVG property (similar to `initial` or `revert`, but it would grab the value from the outer context).

Context keywords were included in the [initial OpenType SVG specification](https://www.w3.org/2013/10/SVG_in_OpenType/#render). The idea was that the SVG glyphs could correctly map distinct fill and stroke values set on the text in the document using the font.  Length-based values (like stroke-width) were supposed to be automatically scaled to the changed coordinate system of the font.

I'm not sure how many SVG-OpenType implementations supported them, and to what degree.  The context keywords have [been dropped from OpenType](https://docs.microsoft.com/en-us/typography/opentype/spec/svg#svg-specification):

> Previous versions of this specification allowed use of context-fill and other context-* property values, which are defined in the draft SVG 2 specification. Use of these properties is deprecated: conforming implementations may support these properties, but support is not required or recommended, and use of these properties in fonts is strongly discouraged.

We will probably be deferring the context keywords from SVG 2 because of a lack of implementations, (and quite frankly, a lack of clarity about implementation details), but the underlying use cases still need to be solved.

## `-moz-context-properties`

And finally, we have the [`-moz-context-properties`](https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties) approach, that @Emilio noted.  This property is supported in the Firefox UI (but not in web content, as far as I know), to allow an SVG embedded as an image to be styled from the outer document.  It applies not only to `<img>` images, but also background images and so on.

It works a little differently than the context keywords: you set `-moz-context-properties` on the element (e.g., `img`) in the outer document, to a list of CSS property names (regular or custom properties).  The value of those properties on that element are then passed through as the default/root values for the embedded SVG.

```css
-moz-context-properties: fill, stroke;
```

So, this approach is different from the others in that the embedded SVG never explicitly "asks" for a value from the outside; it just receives it through inheritance.  Which is how it works with inline SVG icons created with `<use>`, and (as I understand it), the main reason behind this property was to have use-element-like style inheritance without having to inline all the SVG icons.

But it doesn't work well for style properties other than those that normally inherit, and doesn't work for cases like having the fill of a shape in the icon match the stroke color set on the external document.  And it gets a little confusing in that the same properties can apply to many images (content images, background images, etc.) without a way to specify which ones you're trying to modify.  And the properties you're passing through also apply to the element you're setting them on, so e.g., text on that element would also get the same fill/stroke values (if and when fill and stroke for CSS text is implemented).

## "Deep" selectors (as in the original post for this issue discussion)

I've never seen this discussed before for styling embedded SVG, but the idea of using selectors to cross a document tree boundary was [originally proposed for shadow tree styling](https://www.w3.org/TR/2014/WD-css-scoping-1-20140403/#deep-combinator).  Using a dedicated selector, the outer-document stylesheet could identify individual elements inside the nested document and apply arbitrary styles to them.

This again would mean that the customization is entirely in control of the outer document, but even more so: the SVG file would not need to be designed to work with parameters/variables, and it would not need to rely on inheritance.

However, the downsides are the same as for the shadow-tree `deep` selector (which have been discussed at length elsewhere): it breaks the normal encapsulation model of the content, creating a dependency between the outer stylesheets and the DOM structure of the embedded content.

-- 
GitHub Notification of comment by AmeliaBR
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/3730#issuecomment-473036930 using your GitHub account

Received on Thursday, 14 March 2019 20:00:16 UTC