Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need to better define what rules apply to an element in an <svg:use> subtree. #504

Open
emilio opened this issue Jul 16, 2018 · 20 comments
Open
Assignees
Labels
Document structure chapter Use Element Discussions around use element

Comments

@emilio
Copy link

emilio commented Jul 16, 2018

https://svgwg.org/svg2-draft/struct.html#UseStyleInheritance says:

Instead, the shadow tree maintains its own list of stylesheets, whose CSS rules are matched against elements in the shadow tree.

I don't think that's reasonable if the referenced element is in another document, since it means that base URIs should differ and such, and that itself means that the sheets should be reparsed, which is not acceptable.

Instead, what everyone seems to do is that document rules apply to the elements in the <use> shadow tree. Which is itself a bit of a hack. Indeed, everyone but Firefox don't implement selector-matching correctly, and they just seem to return the style of the referenced element.

For example, this should show green, but shows red in WebKit, Edge and Blink:

<!doctype html>
<meta charset=utf-8>
<style>
.inside-use rect {
  fill: green;
}
defs .inside-use rect {
  fill: red;
}
</style>
<p>
  You should see a green square, and no red.
</p>
<svg
  version="1.1"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <g id="square">
      <g class="inside-use">
        <rect width="100" height="100"/>
      </g>
    </g>
  </defs>
  <g id="test">
    <use xlink:href="#square" />
  </g>
</svg>
@AmeliaBR
Copy link
Contributor

The lack of browser interop on this and similar cases is related to the changes between SVG 1.1 and SVG 2 (there's a long note & example in the spec describing the difference).

So I don't think the problem is a lack of clarity in the spec. It's a lack of conforming implementations.
Unfortunately, Firefox is the only browser team so far that has made an effort to standardize on the SVG 2 definitions -- and it had never matched the SVG 1.1 definitions in the first place.

The changes were made to be consistent with shadow DOM style handling in general, and to handle previously-undefined issues with dynamic styles (e.g., hover effects). With the decision to move to a closed shadow tree, we can re-incorporate a little bit of "magic" special behavior, but we would still need a clear specification of how to handle all the edge cases. If the other browser teams don't want to adopt the current spec, someone needs to write out an alternative proposal.

@emilio
Copy link
Author

emilio commented Aug 2, 2018

Note that even with a closed shadow tree, you can observe it if you allow <foreignObject> with custom elements inside... I'll file another issue about <foreignObject> and <svg:use>.

@emilio
Copy link
Author

emilio commented Aug 30, 2018

I propose that document rules don't apply to cross-document <svg:use> elements. I think the model can be sound and efficient with that.

@AmeliaBR
Copy link
Contributor

AmeliaBR commented Oct 9, 2018

While discussing this, we also should re-assess the same-document style matching rules.

Firefox now matches the SVG 2 spec in that case (only matching styles with selectors that can match in the cloned shadow tree fragment), but then gets bug reports from authors who are confused why their CSS selectors aren't matching, when they work in other browsers (from June 2017, from October 2018).

We need to either get commitments from other browser teams to move to the shadow DOM model for style matching, or we need to spec the "clone the cascaded style" approach & figure out all the details that SVG 1 never defined.

@css-meeting-bot
Copy link
Member

The SVG Working Group just discussed svg:use subtrees.

The full IRC log of that discussion <krit> topic: svg:use subtrees
<krit> github:https://github.com//issues/504
<krit> AmeliaBR: referencing element in another document and cloning in style rules of the other document (not only inline) is not what browsers implement
<krit> AmeliaBR: when you copy from another document only inline styles would be copied in.
<krit> krit: I am not sure if cloning styles from other documents to get cloned in into the current document is save.
<krit> AmeliaBR: why would it be an issue than anything else?
<krit> krit: it could load own resources
<krit> AmeliaBR: there are rules on loading further resources from loaded exrternal documents
<krit> AmeliaBR: stuff like line block from other files
<krit> AmeliaBR: that are not well defined
<krit> AmeliaBR: later to the issue I question even for the same document clone we do not have consistency with spec definition
<krit> AmeliaBR: clone is a known change from SVG 1.1 to be more consistent with web components but that might not me necessary anymore.
<krit> krit: why
<krit> AmeliaBR: because we closed the shadow dom and author scripts can't access the shadow DOM and this makes it more up to browsers how special internal things work
<krit> AmeliaBR: the other thing that changed: since 2016, web components have the idea of slotted elements sorted out now
<krit> AmeliaBR: elements that have their styles resolved in main document and included in current document is closer to SVG 1 styling cloning works.
<krit> AmeliaBR: this would get us back to the state of SVG 1.1 as far as same document style behaviour goes. Only browser not matching would be FF.
<krit> AmeliaBR: which never matched the spec
<krit> AmeliaBR: I have to talk to emilio if he could chnage the behavior of FF
<krit> AmeliaBR: under the SVG 1.1 you access all styles before you clone it. That assume processing in the external document but that is not what browsers implemented.
<krit> krit: do you think it would be an issue that we isolate styling for external use reference and just allow inline styling
<krit> AmeliaBR: I think browsers are consistent for inline styling
<krit> AmeliaBR: lets say you have a symbol element with an inner style element. Does this require cloning the style? I need to check what browsers do.
<krit> AmeliaBR: I want to be able to use CSS selectors to style "use" content
<krit> AmeliaBR: for external elements browsers usually don't pre-process the style other than they do for same document. So this needs to be tested.
<krit> krit: it sounds like you and Emilio would be the best persons to work on this. I will talk at TPAC with him when I see him.
<krit> AmeliaBR: I'll also try to ping Emilio and ask if FF could follow the other browsers and we get consistency
<krit> AmeliaBR: if you could ask browser implementers to look at this issue (especially web components) would be great.
@AmeliaBR
Copy link
Contributor

I propose that document rules don't apply to cross-document <svg:use> elements. I think the model can be sound and efficient with that.

I'm tempted to agree.

A simpler option would be: any <style> element or <html:link> element that is a child of the cloned element gets cloned (just like any other child elements) & then acts as normal inside the Shadow DOM. That means that authors could use selector-based style rules and other advanced CSS features (media queries, keyframe animations) in their external files. By using a linked stylesheet, they could even share styles between icons in the file without repeating the code in each symbol, although it would require an extra file download. But, no styles need to be processed before cloning, only simple XML parsing.

@css-meeting-bot
Copy link
Member

The SVG Working Group just discussed Styling and Use Element shadow trees.

The full IRC log of that discussion <AmeliaBR> Topic: Styling and Use Element shadow trees
<AmeliaBR> Github: https://github.com//issues/504
<AmeliaBR> Dirk: Amelia & I discussed this with Emilio (who posted the issue) over IRC last week.
<AmeliaBR> ... So, the nature of shadow trees is that style selectors from the main document don't match into the shadow tree. In SVG 2 currently, we say to copy the CSS rules into the shadow tree & then match again. But some rules wouldn't match, because the shadow tree is only part of the original tree.
<AmeliaBR> Dirk: This allows the approach to be more consistent with the rest of the web platform, but it doesn't match Edge/Chrome/Safari current behavior. From discussion, Microsoft in particular was against any change that wasn't backwards compatible.
<AmeliaBR> ... So maybe we can work with people to find a solution that is both consistent with web components and also backwards compatible.
<AmeliaBR> https://svgwg.org/svg2-draft/images/struct/Use-changed-styles.svg
<krit> https://svgwg.org/svg2-draft/struct.html#UseStyleInheritance
<AmeliaBR> That's the example from the spec of a rule that would change between the old or new rules.
<AmeliaBR> Amelia: One thing that has changed since the SVG 2 text was written is we decided to make the use shadow trees closed to author scripts. This gives us room for a little extra magic that can't be defined by regular shadow DOM.
<AmeliaBR> Amelia: The SVG 1 version of cloning the cascaded styles has its own problems. But the break comes specifically from selector matching. So maybe what we need is a little bit of "magic" rules for how selectors match in use-element shadow trees.
<AmeliaBR> ... so if a path element was cloned from somewhere it was a child of a g, then `g > path` would match the shadow path, even though there is no shadow `g`.
<AmeliaBR> ... but interactive selectors like `:hover` would still be assessed on that particular shadow element, not on the original.
<AmeliaBR> Dirk: Is this possible to implement cleanly?
<AmeliaBR> Amelia: It would need special code, but anything that is backwards compatible would need special code, because its unique behavior.
<AmeliaBR> Dirk: Ok. But I think we need a discussion with CSS & web components folks.
@emilio
Copy link
Author

emilio commented Oct 29, 2018

I don't think we could implement the thing described above in Gecko without massive hacks or performance regressions.

@dirkschulze
Copy link
Contributor

@emilio Thanks for the input. Do you see another way how we could keep backwards compatibility as much as possible? (Apply selector matches from outside of shadow tree.)

@dirkschulze
Copy link
Contributor

@tabatkins It would also be great to hear your feedback to <use> based on web components with the minuted issue of selector matches from outside the shadow tree inside into the shadow tree.

@SebastianZ
Copy link

For reference, at https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/SVG_and_CSS there is an example which is applying :hover rules to elements referenced by <use> elements.
I have just fixed that example, because it previously only used direct selectors (which I kept for now, as they worked in older versions of Firefox, but they may get removed), i.e. they matched the elements as if they were placed inside the <use> elements (see mdn/sprints#1987).

From an author point of view, applying all rules as if the elements were not referenced via <use> elements is the expected behavior. It feels awkward when rules that normally apply to elements do not apply to them when they are referenced.

Sebastian

@emilio
Copy link
Author

emilio commented Sep 19, 2019

From an author point of view, applying all rules as if the elements were not referenced via elements is the expected behavior. It feels awkward when rules that normally apply to elements do not apply to them when they are referenced.

That's not the semantics of SVG 1. The semantics of SVG one mean that for this test-case:

<!doctype html>
<style>
  rect {
    fill: red;
  }
  rect:hover {
    fill: green;
  }
</style>
<svg width=300 width=300>
  <g id="canvas">
    <rect width=100 height=100></rect>
  </g>
  <use x=200 y=0 href="#canvas"></use>
</svg>

For SVG 1, you get two green squares when you hover over the square to the right.

For SVG 2, it behaves as you expect.

@george-steel
Copy link

I think that implementing :host-context() would solve a lot of the problems with firefox's approach as it allows selectors that span shadow DOM to be specified.

@emilio
Copy link
Author

emilio commented Oct 21, 2019

:host-context() is pretty bad, generally... see w3c/csswg-drafts#1914.

@george-steel
Copy link

See my comment there for an alternate proposal

@george-steel
Copy link

Another alternative would be to add part attributes to sub-components of a use that need to be styled, exposing them as pseudo-elements of the parent element.

@dirkschulze
Copy link
Contributor

@progers @fsoder @rniwa Any comment from WebKit and Blink?

@fsoder
Copy link

fsoder commented Nov 10, 2019

I think that we (Blink) would ultimately like to implement the semantics specced in SVG2, but given the feedback from authors, it would be good to make sure that their use cases can be addressed in a way that is satisfactory for them.

(This comment would also apply to #367)

@george-steel
Copy link

Implementing the SVG2 semantics could vastly simplify part of the blink animations stack (a fair bit of it is there to clean up clobbered styles on original elements when they get reparented to the clone's parent for styling. The ::part selector can allow selectors traversing shadow dom, simply requiring part attributes to be set on the originals.

@Hanmac
Copy link

Hanmac commented May 30, 2024

I don't know if they are related, but I had a funky problem using <use> with external SVG:

extern.svg

<svg
  version="1.1"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <g id="square">
      <g class="inside-use">
        <rect width="100" height="100"/>
      </g>
    </g>
  </defs>
</svg>

page.html

<style>
.inside-use {
  fill: red;
}
.shape .inside-use {
  fill: green;
}
</style>
<svg viewBox="0 0 100 100" class="shape">
  <use xlink:href="extern.svg#square"></use>
</svg>

Currently, the path .inside-use matches the rect and makes it red.
But it doesn't notice that, I want to access the rect when it's inside the shape class.
Because .shape .inside-use isn't valid for the shadow content.

The goal is to color the different parts (in this example: inside-use) depending on the class of the outer svg tag

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Document structure chapter Use Element Discussions around use element
8 participants