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

SVG2 spec means elements within a <use> tag can not be targeted for styling #367

Closed
peter-mouland opened this issue Nov 15, 2017 · 32 comments

Comments

@peter-mouland
Copy link

peter-mouland commented Nov 15, 2017

spec: https://www.w3.org/TR/SVG2/struct.html#UseStyleInheritance
CodePen Demo: https://codepen.io/peter-mouland/pen/pdEMWZ/

Recently, I have tried to create a number of SVG's and reuse those SVG's within the same document via the <use> tag. These 're-used' svgs need to have different styles applied to them, and to the elements within.

Following the SVG1 spec this worked as expected. You can see a CodePen Demo1 of this working with Chrome 62. This also works when using CSS custom properties (see CodePen demo2)

Following the SVG2 spec no SVG's are viewable. View the same demo on Firefox 56, which has implemented the SVG2 spec (See discussion3). This is also no longer achievable using CSS Custom Props (see CodePen demo2).

Using the demo as an example for the SVG2 spec, is there another way I am able to achieve this in browsers implementing SVG2? Or is this an area that requires some more thought?

Links:

additional info email to w3c: 21 Nov 2017

I think this would classify as a breaking change between the 2 specs (according to feedback gathered from a number browser venders). I'm not sure if it was intended, or an unfortunate side-effect, either way, I just want to style my inline-svg's with as little duplicate code as possible 🤔

I hope you are able to follow my ramblings and either update the spec to allow re-used SVG's to have custom styling applied, or perhaps document another solution to this problem. Thanks for any help!

@AmeliaBR
Copy link
Contributor

You're correct that this is technically a breaking change in the spec. However, it was a section of the spec that was never consistently implemented in web browsers. The note and example in the spec explains what changed and why (to be consistent with web components shadow DOM, and to avoid many current bugs with interactive and animated styles).

The workaround is to avoid CSS selectors that depend on the position of the original element within the original DOM (like svg.class path.inside-symbol). The paths in the cloned copies of the symbols will not match these selectors, because they are no longer descendants of the svg.class.

If you want the styles to persist in the clones, you can put the classes on the symbol or path elements directly, since those classes would be copied to the clone. Here's a version of your pen that does that, and therefore works in Firefox:

https://codepen.io/AmeliaBR/pen/4ccc55d55673d8467850bd9ce55be6f1?editors=1100

I also fixed the Safari problem, which wasn't related to style matching. Safari does not yet support the href attribute without the xlink prefix.


All that said: if other browser developers / spec editors want to propose a different spec that is closer to how SVG 1.1 (and most current browsers) work, that's still an option. But then we'd need to clarify how things like animations and interactive pseudoclasses work (which is currently a mess of inconsistency cross-browser).

@peter-mouland
Copy link
Author

Thanks a lot for taking a look at that (and for spotting the xlink oversight!).

With your update, the restyling working across all browsers. It also works perfectly with CSS Custom Props and only a single SVG Symbol which is ideal (rather than one symbol per style).

https://codepen.io/peter-mouland/pen/MOpeJw

Thanks again

@bureau-of-information
Copy link

bureau-of-information commented Dec 9, 2017

We just found our way to this thread after the breaking change killed our site in the newest versions of Firefox. I'd like to express my dismay at this change to the spec and strongly ask/suggest/beg/implore that it be reconsidered in the SVG 2 spec.

The V1 approach was significantly better. The V2 approach essentially violates the underlying premise and value of CSS, largely eliminates the value of <use>, and, I would argue, makes it impossible to do interesting and complex things with SVG.

I can see why the implementation would be significantly simpler, but the new approach has the potential to largely undermine SVG as a useful tool, and 100% of the browsers already had working implementations of the SVG 1 approach (albeit not quite standardized).

CSS was intended to allow you to style objects based on their context. Unless I'm missing something, the new 'improvement' is styling a template statically and then reinstantiating the styled element. If we've learned anything in the last decade, it's that styling elements based on their context is a good thing. CSS was such a big hit because we could now put the same HTML in two places and have it do wildly different things based on styling rules. It largely fulfilled the dream of separating structure from style.

SVG2 appears to eliminate this possibility for SVG elements that are instantiated with <use>, which kills the usefulness of <use>, which then leads to having to repeat code everywhere just so you can style it. This is demonstrated in the codepen solution. The structure of the chevron is repeated twice just to get two different styles.

To use a mediocre analogy of cookie cutters and cookies, SVG 2 appears to allow us to only style the cookie cutters but not the cookies. And if you've ever decorated cookies, you know that the interesting part is that each cookie shares a structure but can be decorated with different styles on a per cookie basis. We might have a cookie cutter for a star, and a moon, and a little man (structure). But from those three cutters, we then instantiate many cookies and with unique icing and M&M decoration (style).

With SVG 2, now we appear to have to create 1000 cookie cutters. Further, having them adjust based on the dynamic nature of web pages is now impossible. This is truly a step backward. For styling to be useful, you need to be able to style each individual element based on its position and context in the DOM. If styling has been handicapped to the point that it can't cross the shadow DOM barrier, it's no longer useful since we can't use the DOM context to determine the style.

Cookies that appear in a "Christmas" div should have red and green stripes and cookies that appear in an "Easter" div should have pink and blue stripes, and sometimes pink and yellow stripes if the cookie has been marked as "selected" by the user.

Without complex selectors that cross the DOM boundary, <use> is reduced to acting like a server-side include. Yes, if I want 1000 cookies, 500 of which are identical to one template and 500 of which are identical to another (the chevron example), then the SVG 2 spec makes sense. But this is not the common or interesting case.

If I've missed something and there's a way to style an individual sub-element within a <use> instantiation based on where that <use> appears in the DOM, then forgive my passionate plea. But if SVG 2 just made basic CSS styling based on context impossible, then please (!!) reconsider, particularly given that it was already implemented and working in every major browser.

@dholbert
Copy link
Member

dholbert commented Dec 9, 2017

Here's a sample testcase for what @markofca is trying to achieve. (EDIT: sorry, this testcase isn't actually so good[1])

Is there any way to <use> the #target element there, and customize styles in the different <use> clones? (The testcase attempts to do that, and it works in all browsers except for Firefox 56+ which have implemented the new spec text.)[1]

[1] Actually, this testcase isn't quite as smart as it thinks it is, in Chrome/Edge at least. I intended for the <use> clone to depend on its own .outer ancestor to become lime, but that ancestor actually doesn't influence its color at all. It becomes lime in Chrome/Edge simply because it clones the computed styles of #target, or something like that. So it's entirely dependent on what rules match its target in those browsers.

@AmeliaBR
Copy link
Contributor

AmeliaBR commented Dec 9, 2017

(reopening issue for further discussion, although I think we're talking about a few different things here)

@AmeliaBR AmeliaBR reopened this Dec 9, 2017
@bureau-of-information
Copy link

bureau-of-information commented Dec 9, 2017

Thanks for reopening. It's likely that my concern does mix different issues and apologies if my terminology isn't quite right, but @dholbert summarizes my issue well: How can you target a subelement within an SVG clone for styling?

Another use case to help add context to the problem: building a game in which the characters and opponents are complex SVG (let's say a couple pages of path elements per character). These characters have N different visual attributes (health, strength, uniform color, etc) that vary each with M different potential values. The values change depending on the scenario and the state of the character at any time. You have P opponents in a battle whose N x M values are changing individually.

In SVG 1, the implementation is easy. You create one character, clone it P times, and then add / remove classes to the clones to configure the N x M values dynamically.

In SVG 2, the implementation is basically "sprites". You have to create N x M versions to clone at the outset to represent EVERY possible state and then dynamically and somehow seamlessly swap in different versions to show different states. This is largely impossible and unwieldy for any interesting values of N and M. So, instead, you end up creating P elements, each with the two pages of code repeated, so you can style them dynamically. That is, you can either have the value of <use> (repeating structure) or the value of CSS (styling elements individually), but not both at the same time.

@peter-mouland
Copy link
Author

peter-mouland commented Dec 9, 2017

I believe with CSS Custom Properties you can achieve what you need, but this obviously means it won't work in Internet Explorer or Edge < 16, but it does work for SVG spec v1 and v2 browsers. Hopefully supporting 'modern' browsers is enough for you, but i guess it doesn't change the fact about the breaking change, and each element can be styled/themed according to each 'state' as required.

My second link tried to demonstrate this technique: https://codepen.io/peter-mouland/pen/MOpeJw
This has a single SVG, which is then used multiple times, with the css being applied via custom props to the individual SVG elements:

<svg class="symbol">
  <symbol id="chevron" viewBox="0 0 100 60" >
    <line class='line line--1' x1="50" y1="50" x2="10" y2="10" stroke-width="10" stroke-linecap="round"></line>
    <line class='line line--2' x1="50" y1="50" x2="90" y2="10" stroke-width="10" stroke-linecap="round"></line>
  </symbol>
</svg>
<svg class="a-state" width="4em" height="40px"><use xlink:href="#chevron"></use></svg>
<svg class='another-state' width="4em" height="40px"><use xlink:href="#chevron"></use></svg>
.symbol { display: none; }

/* Set default theme  */
:root { 
  --line-1: brown;
  --line-2: green;
}
/* Set another theme */
.another-state {
  --line-1: red;
  --line-2: blue;  
}

/* Apply Themes */
.line {
    stroke: var(--line-1);
}
.line--2 {
    stroke: var(--line-2);
}

which produces:
screen shot 2017-12-09 at 20 31 46

I think this is what you are trying to get, but i could have misunderstood. Plus i'm not sure if browser support is important to you or if you trying to raise general awareness about the breaking change in the spec... either way hope this helps!

@dholbert
Copy link
Member

dholbert commented Dec 9, 2017

Thanks, @peter-mouland! I think that does indeed provide a solution for this use-case. I posted a simplified standalone testcase incorporating that fix at https://bugzilla.mozilla.org/attachment.cgi?id=8936087 , which works in all modern browser engines (I tested Firefox, Chrome, Safari, Edge).

@bureau-of-information
Copy link

Thanks @peter-mouland and @dholbert. This seems like a possible work-around and is much appreciated!! We'll give it a shot to see if we can get our site working in Firefox again.

It's a bit counter-intuitive that this would work given that you're essentially using the selectors of the object to style the clone by passing through intermediate variables styled on the clone root. In essence we're dodging the boundary rule by sliding in on a custom style on the object. The clone still needs to access the selectors to know how to draw itself. And if it can do that, it seems like we should be able to use CSS in all its generality.

The workaround is a painful way to work. Now, for every attribute you might want to style (= number of SVG sub-elements S x number of styled properties P), you need to create a variable in your template. For all but the most trivial examples, S and P grow very large very quickly.

It's far easier to specify selectors that cross the boundary (SVG 1) than trying to manage a flat namespace of everything you might want to modify (SVG 2 with clever workaround).

@boggydigital boggydigital added this to the SVG 2.1 Working Draft milestone Jun 11, 2018
@boggydigital
Copy link
Contributor

Not blocking updated 2.0 CR publication - assigning 2.1 WD milestone

@css-meeting-bot
Copy link
Member

The SVG Working Group just discussed SVG2 spec means elements within a <use> tag can not be targeted for styling, and agreed to the following:

  • RESOLVED: child content of foreignObject is stripped out of a use element shadow tree clone -- check browsers for exact impl details
  • RESOLVED: No change to spec around use element styling, but focus on getting feedback from implementors about feasibility of current SVG 2 model
The full IRC log of that discussion <heycam> Topic: SVG2 spec means elements within a <use> tag can not be targeted for styling
<heycam> github: https://github.com//issues/367
<heycam> emilio: SVG 1 says you take the style rules from the reference element
<heycam> ... that not only changes the behavior of decendant combinators, but also element specific states
<heycam> AmeliaBR: it wasn't clear in SVG 1, the way it was implemented was the specified style gets copied over, so any style rules directly set on the element get cloned with it
<heycam> ... and then inherited styles are inherited in
<heycam> ... nothing in Web Components shadow DOM that's at all like that
<heycam> ... trying to harmonize with shadow DOM, we defined it so that the style sheet is cloned in the shadow trees
<heycam> ... but that could break some select matching compared with the original element
<heycam> ... what gets fixed is the interactive selectors
<heycam> rniwa: do we know what implementations do?
<heycam> AmeliaBR: Firefox matches SVG 2 spec
<heycam> emilio: Blink and WebKit, in order to resolve style in the use subtree, you match the referenced element
<heycam> rniwa: so the original source element is used for styling
<heycam> emilio: so when you hover over the reference, all the clones get hover styles
<heycam> ... the Firefox behavior is a bit unfortunate, regarding the combinators, but we haven't received many bugs about that
<heycam> krit: how long has it been shipping?
<heycam> emilio: more than 2 years
<heycam> AmeliaBR: Firefox had never implemented the SVG 1.1 spec
<heycam> heycam: right
<heycam> myles: did you have to add special case SVG code?
<heycam> emilio: not really
<heycam> ... in special of the special casing code being on the "compute the style" function, the code checks if the element is in a use shadow tree, then also look at your tree parent scope for rules
<heycam> AmeliaBR: it can probably be represented by the adopted style sheets concept
<heycam> emilio: yeah....
<heycam> ... but to implement it efficiently, you just look up to the parent scope
<heycam> rniwa: conceptually you're copying the rules
<heycam> emilio: yes
<heycam> ... conceptually you just look at the outside use shadow tree
<heycam> AmeliaBR: when this has previously come up, Rossen has been cautious of breaking changes
<heycam> ... but we don't have a sensible spec
<heycam> ... in the existing SVG 1.1 match browsers, there were inconsistencies in terms of interactive styles, animations, whether htings get copied
<heycam> ... so in the details, we don't have a spec to define how those things work in a way that's actually corss browser
<heycam> ... so either way, implementations would have to change if we want truly consistent behavior
<heycam> ... I'm OK with making that be closer to SVG 1.1, but I need a spec proposal for that if people want to do that
<heycam> ... that also takes care of interactions, animations, etc.
<heycam> rniwa: the question to me is which behavior is more compatible with existing content
<heycam> ... also author expectations
<heycam> emilio: regarding author expectations, it's tricky. SVG 1 kind of matches "I'm styling the element I'm cloning"
<heycam> ... so ancestor combinators work
<heycam> ... however it doesn't match expectations of :hover
<heycam> ... the SVG 2 behavior works the other way around
<heycam> ... for authors who are familiar with shadow trees, it probably makes sense
<heycam> AmeliaBR: we have had some bug reports on SVG spec and Firefox about people whose selectors didn't work because they were using these ancestor selectors
<heycam> ... but when you explain how to fix it, it was OK
<heycam> ... the :hover not working, that's a much more intrinsic confusion
<heycam> ... and there's no easy way to explain that
<heycam> rniwa: whatever solution we come up with, it should handle :hover. :focus would even be a bigger problem
<heycam> AmeliaBR: SVG 1 really didn't discuss keyboard focus. but now we have a model, you can have focus in the shadow tree, so your :focus rules should reflect the element that's actually focused
<heycam> rniwa: there's also some niceness in that if we had adopted style sheets, it could be described in that way
<heycam> AmeliaBR: I need to talk to Antti and folks to check what they think
<heycam> s/AmeliaBR/rniwa/
<heycam> AmeliaBR: we should probably poke a Chromium engineer for feasibility too
<emilio> http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=7216 is a testcase that shows the difference of behaviors
<heycam> krit: we've had this issue for a long time, it's been waiting for implementor view for a while
<heycam> emilio: I recall having a WebKit patch for that in the past...
<heycam> emilio: there's a test case I've pasted
<heycam> krit: how does the shadow content know about the viewport size?
<heycam> AmeliaBR: that's the same as regular shadow DOM, it uses the document viewport for MQs etc.
<heycam> rniwa: might want to consider what happens if you support shadow root on an SVG element at some point
<heycam> AmeliaBR: definitely want to support custom SVG elements with shadowRoot
<krit> q?
<heycam> [some discussion about use elements pointing to foreignObject]
<emilio> rniwa: https://github.com//issues/511
<heycam> krit: but in general we agree we don't want foreignObject in the shadow tree?
<heycam> rniwa: yes, that would get hairy
<heycam> ... then you can have SVG, MathML, plugins....
<heycam> RESOLVED: child content of foreignObject is stripped out of a use element shadow tree clone -- check browsers for exact impl details
<heycam> RESOLVED: No change to spec around use element styling, but focus on getting feedback from implementors about feasibility of current SVG 2 model

@bureau-of-information
Copy link

Just saw the recent comments of the SVG Working Group on the thread.

We launched the site that the issue arose in for us, so figured it might be useful to show the use case and what we were trying to accomplish described above in the thread. (Also we use SVG very heavily in a pretty aggressive way throughout the site so thought the app might be interesting to the group.)

Desktop link (site works on mobile also, but easier to see the use case from here):
https://www.tango.live/match/main/701/77/20199/-/d/en

The cheering fan character graphics (and many other elements in the site) are SVG. The character graphic has about 20 customizable elements (face paint, jersey styles, hair style, colors, etc) and 5 different postures (excited, happy, neutral, sad, despondent). The graphic in all 5 postures is styled uniquely for each team and for home versus away.

If you click on the vertical nav buttons to the right of the center column (F, 5', 10', 1H, 2H), you can see variations of the character animate into the UI. If you switch between matches using the top nav, you can see more custom styling for various teams.

We used the work-around suggested and got working implementations in Chrome, Safari, Edge, Firefox, and for a time, IE. But it's a painful approach.

Styling the 'd element and going the SVG 1.1 approach would have eased development considerably.

@dirkschulze
Copy link
Contributor

@markofca Thanks a lot for sharing your experience. I wonder if this perception "SVG 1.1 approach would have eased development considerably" will change over time the more people get used to Shadow DOM. Having familiar concepts across the web platform is a strong argument in favour for the SVG 2 changes.

The CSS WG is working on improving the work with Shadow DOM (https://www.w3.org/TR/css-scoping-1/#shadow-dom) as which will have impact on <use>.

@bureau-of-information
Copy link

bureau-of-information commented Sep 20, 2019

@dirkschulze My 2c (which I believe may be sacrilege and apologies in advance)...

As a developer for 30+ years, I personally don't see the Shadow DOM ever being something that a large number of web developers will ever "get". I barely get it myself.

There feels like a tight coupling between understanding how a browser is implemented and understanding the Shadow DOM. Not many people understand the former, so I don't have a lot of hope that it will be easy, for example, for people whose day job is styling web pages with CSS to grasp the finer workings of the Shadow DOM. This could just be my own difficulty with it.

Partly, I think there is an issue that the terminology for just about everything related to the Shadow DOM is unfamiliar (why is it called a shadow DOM even?). It breaks from traditional computer science terminology, and when we're talking about CSS, we have to recognize that even traditional computer science terminology is probably not widely understood. Developers have common notions of 'class/prototype/template' and 'object/instance', but discussions of shadow DOM introduce a very parallel set of terms for these notions, maybe for good reason, but I'm not so sure.

In my description above, I see myself casting the discussion back into a more familiar paradigm. Maybe it would help (or maybe it's too late?) to think about the naming and concepts so that people learning about the Shadow DOM have some meaningful landmarks. The idea that I instantiate classes into objects and can only style those objects through an interface controlled by the class are readily accessible notions for a first year computer science student.

By contrast, the idea that multiple shadow trees are created with host contexts and distribution lists and shadow-projected content is perplexing. Quickly reading through the link you provided (which I understand is a spec and not a tutorial) makes me nervous. I would really need to sit down and parse it line by line to try to get the gist of it.

In short, I think the value of CSS is, in part, that it's incredibly accessible to a wide range of people. I don't see the Shadow DOM as it's currently presented as ever achieving that. It largely is an implementation detail for browser developers. In some ways, the encapsulation it's providing seems of limited value compared to the complexity it's introducing.

The very notion of CSS is somewhat anti-encapsulation (anyone can modify anything anywhere in the DOM) and the shadow DOM, to the extent that it is used widely and not just as something to aid browser development, breaks that paradigm.

I haven't thought about it as much as I'm sure you guys have, but my gut instinct would be preventing/limiting access across the boundary of the shadow DOM is a mistake. The history of styling shows that early encapsulation (hiding the ability to style scroll bar elements for example) gets undone over time, not the other way around.

I suspect people should be able to style 'instances' freely without limitation. Yes, that bears the potential for abuse, but on the flip side, everyone will understand it because it reflects how CSS works in the 'normal' case. Instantiation in this context is useful (replicating structure without replicating code...). Encapsulation, not so much.

@dirkschulze
Copy link
Contributor

Thanks @markofca. Let's focus on the behavior of<use>. The main developer visible change and the difference between SVG 1.1 and SVG 2 is that elements within the "<use>-tree" can not be targeted via CSS directly. @dholbert's workaround seems to be working for you with inconvenience. Do you see use cases that would no longer work and where there are no workaround?

@bureau-of-information
Copy link

bureau-of-information commented Sep 20, 2019

@dirkschulze I've now mostly digested this doc: https://www.w3.org/TR/css-scoping-1/#selectors4 and my concerns regarding the ability to cross the boundary of the shadow DOM with CSS in both directions is well addressed through the additional selectors. If I'm understanding the IRC log (and would not be surprised if I'm not), <use> will continue to be an exception to this approach. Is there some documentation/discussion available that I can read that would help me get up to speed on why that was chosen as the preferred approach?

I believe we're back to this issue above...

"The workaround is a painful way to work. Now, for every attribute you might want to style (= number of SVG sub-elements S x number of styled properties P), you need to create a variable in your template. For all but the most trivial examples, S and P grow very large very quickly."

Essentially, under the SVG 2 approach, <use> becomes prohibitively difficult to use unless a) you are replicating an SVG element with no intention of independently styling the clones or b) you are replicating an SVG object with a trival amount of pre-designed styling built into the structure of the cloned object using the above work-around.

For complex SVG where an illustrator is exporting from Illustrator and where a game or graphic designer is styling this and customizing many aspects of the clones individually, I think the process would become prohibitively complex for all but the most trivial cases.

As a developer I would end up torn between wanting to use the new selectors for styling anything across the shadow DOM boundary and wanting to take advantage of <use> to avoid repeating large amounts of SVG. The case where you really need <use> is when the cloned object is complex (that is, has many subelements that might need to be styled), and that's precisely where the work-around is prohibitively onerous.

@dirkschulze
Copy link
Contributor

@tabatkins See #367 (comment) Are you aware of additional resources (documentation/issues) for CSS Scoping, Shadow DOM and <use>?

@ThomasBrierley
Copy link

Hi 😃

This change affected over 50 products I helped develop, breaking them in FireFox since 2017. Styling 'use' elements based on the instance-context was relied upon as a fundamental building block in such a way that re-writing them was infeasible.

Out of necessity, I've written an "unpolyfill" to restore partial support for contextual styling of 'use' instance trees (only in the instance-context not the reference-context). Perhaps this will provide some quick relief for others affected by this change:

https://github.com/ThomasBrierley/svg2use-unpolyfill

@markofca has already passionately argued how this change deprives 'use' of it's most powerful utility, which I agree with. I would add: the idea of unifying the spec with the shadow DOM appears to have taken priority over careful weighing of the required omissions individually. The 1.1 spec accommodated styling in many possible ways, but the choice was not simply to retain all or none.

However, I wouldn't be here debating this change at all had SVG 2 respected version declarations or required a new declaration like HTML5 to prevent existing content from breaking. Maybe it was assumed this feature was too obscure or poorly supported to qualify as a breaking change... I can only contest the latter: Styling 'use' instance trees based on instance-context was implemented consistently across all major browsers, all the way back to IE9 (I know, because I had to support it).

Perhaps it's too late to address versioning, but I hope restoring styling in the instance-context is carefully considered for SVG 2.1 (independently of how well it fits the shadow DOM) - This behavior makes 'use' worthwhile, without it, it's capable of little more than visually identical copies. By only retaining one half of the context based styling implementation is also vastly simplified.

@theprojectsomething
Copy link

Where simply filling a coloured <symbol> is an issue (e.g. a logo appearing full colour, fully reversed on e.g. black / white, or partially reversed), this can be resolved by declaring a combo of color attributes within the <symbol> and then setting fill: #{flat-color} | currentColor on the containing <svg> (e.g. https://codepen.io/theprojectsomething/pen/eYYvBLK). Combined with css variables this can provide more than the most basic fallback solution.

@dirkschulze
Copy link
Contributor

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

@george-steel
Copy link

Could you give an example of SVG1 use styles depending on instance context. As fair as I can tell, blink styles only according to target context only (for selectors) with instance context only contributing to inherited styles.

@george-steel
Copy link

One of the big benefits of SVG2 scoping is that allows true instance-context dependent styling using ::part() selectors, just like with WebComponents.

@IanBellomy
Copy link

IanBellomy commented Jun 6, 2020

I'm just being bit by this and am dismayed. Imagine if you found out that now jpegs may render differently in different browsers and your old jpegs may not display the same way moving forward. I'd never go near the format again.

[Edit My comment was rash, but I'm leaving for posterity.]

@longsonr
Copy link

longsonr commented Jun 6, 2020

@IanBellomy That's not really how it was/is... Imagine if all jpegs used to display differently. Someone said, wouldn't it be great if they all rendered the same. A new specification for jpegs got rid of some things that made jpegs difficult/impossible to implement. At some point all jpegs will render the same once everyone implements the new specification but a few old ones written a long time ago that always rendered differently now don't render as the author originally intended but then again on many browsers they never did. For jpeg substitute use elements and you have the history.

@IanBellomy
Copy link

IanBellomy commented Jun 6, 2020

@longsonr That's pretty fair. Though it seems that Safari and Chrome reached a consensus at some point, which is not insignificant. I'll zip up until I read some more though. Appreciate your patience.

@longsonr
Copy link

longsonr commented Jun 7, 2020

@IanBellomy that's not true either. Chrome's implementation is courtesy of it being a fork of Safari.

@IanBellomy
Copy link

IanBellomy commented Jun 7, 2020

@longsonr Apologies if that behavior indeed stabilized before webkit was forked — in which case it indeed does not indicate that two separate parties came to the same conclusion as I suggested.

That said, as a developer trying to make things for people a criteria for significance in this instance is the degree to which consistent appearance and behavior can be achieved across systems. Safari is effectively the only browser that runs on iOS and the main browser for macOS users. Chrome is the default browser on Android devices and has a large share of users on desktop PC. The fact that Chrome and Safari have a consistent behavior means that I can consistently deliver a consistent experience across many different platforms. That fact is not insignificant. Moreover, if that behavior stabilized before webkit was forked, then the existence of some cross-platform consistency has been the case since ~2013, which itself is notable to me.

@ThomasBrierley
Copy link

ThomasBrierley commented Jun 7, 2020

@IanBellomy That's not really how it was/is... Imagine if all jpegs used to display differently. Someone said, wouldn't it be great if they all rendered the same. A new specification for jpegs got rid of some things that made jpegs difficult/impossible to implement. At some point all jpegs will render the same once everyone implements the new specification but a few old ones written a long time ago that always rendered differently now don't render as the author originally intended but then again on many browsers they never did. For jpeg substitute use elements and you have the history.

Sorry this is not quite true either, I think a lot of confusion in this thread stems from the bundling of support for style cascade in the reference-context and instance-context together, when they can be used completely independently. So let me make it clear:

Support for instance-context styling alone was supported by all major browsers since around IE9 (2011). Consistent cross browser support for a feature means it will have been used by devs, it means there is SVG content out there now which is broken which would have worked fine.

Where it gets quirky and inconsistent is support for reference-context styling and combining of the cascades. No one is contesting this fact, and it's unlikely anyone utilised it heavily for this reason because cross browser testing will have revealed those quirks. I am highly suspicious of this decision for nuking both sides of <use> styling support having more to do with the attractiveness of unifying the implementation with the shadow DOM, and so drawing a box around both was convenient if incorrect.

To amend your JPEG analogy, it's as if someone removed progressive encoding, but since it is related to how JPEG compression works they also just removed the JPEG compression algorithm all together... even if the former was difficult to implement, the later was widely implemented and is kinda the whole point of JPEG - in this analogy <use> == JPEG

@IanBellomy
Copy link

IanBellomy commented Jun 8, 2020

Thanks @ThomasBrierley.

To clarify, I was personally surprised by the removal of reference styling, i.e. the use of the fragment's context to determine what it'd look like, by default, when targeted by a use element; though the issues with instance styling are also surprising.

In the case a user wanted a kind of template for reuse-with-tweaks, e.g. an enemy space-ship in a game or a person in a crowd, a symbol contained in defs that can be instanced by use seems to fit the occasion perfectly. This approach also mirrors the template reuse pattern in html.

In contrast, achieving this same end by referencing a fragment inside the document where the fragment may or may not be affected by style cascades seems risky (you'll need to be aware of and understand the priorities of any relevant selectors AND how they interact with instance styling rules), unless the goal was for the instance to appear exactly the way the reference appears in its particular context.

Re-presenting an element as it appears effectively provides a kind of render-to-texture effect that doesn't otherwise exist in a browser absent complex canvas workarounds.

Re-presenting an element as it appears also provides a way to work around z-index limitations in some cases, especially when re-organizing a complex document tree to achieve proper z-order would effect the appearance of the elements. [Aside: Is z-index even in SVG2 anymore?]

(Targeting fragments in other documents would also provide some ability to work around separation of HTML and SVG stacking contexts without relying on foreign object -- but I'm not sure how well that was supported specifically and have only recently considered this use case.)

This kind of exact re-presentation does not seem possible to achieve at all in SVG2. Absent a way to control for version, there's no way implement alternative CSS or JS to get cross platform consistency either. So this feature is presently dead even though SVG2 support is minimal. At least instance styling can be achieved, albeit with a new high-friction approach (though it is still breaking of course).

It seems it's only my recollection though that, at least a few years ago, mixing styles was what was flaky — that reference and instance styling could be used somewhat reliably if relatively independently.... (I've had minimal contact with SVG before maybe 2015 though — I stuck to Flash as long as possible in no small part to avoid the kind of issues discussed here.)

@ThomasBrierley
Copy link

I was personally surprised by the removal of reference styling, i.e. the use of the fragment's context to determine what it'd look like [...] In the case a user wanted a kind of template for reuse-with-tweaks

As a quick and easy tweak I can see how this might be missed, I was thinking more in terms of what is possible in absolutes... Reference context dependence can be avoided with some re-thinking of CSS. However utilizing context-based styling is very powerful because you can make things automatically look entirely (or slightly) different, with minimal CSS - or at least you could, but now it would require much duplication with the same CSS, not merely re-arranging it.

It seems it's only my recollection though that, at least a few years ago, mixing styles was what was flaky — that reference and instance styling could be used somewhat reliably if relatively independently

You may be correct for more recent years, I remember needing to avoid it for older browsers originally though. Relying on the merging of those cascades is definitely the inconsistent part though.

This kind of exact re-presentation does not seem possible to achieve at all in SVG2. Absent a way to control for version, there's no way implement alternative CSS or JS to get cross platform consistency either. So this feature is presently dead even though SVG2 support is minimal. At least instance styling can be achieved, albeit with a new high-friction approach (though it is still breaking of course).

In case you missed it, I wrote an unpollyfill (i.e a pollyfill for SVG v1) that restores instance-context styling:

https://github.com/ThomasBrierley/svg2use-unpolyfill

I wrote this with care to be as performant and minimal as possible, it is well tested and in use throughout all of the products I help develop (in fact i've skipped adding it to application development and injected this straight into index pages server side inside of a condition for firefox useragents).

However I skipped the reference context styling because of the extra complexity and performance penalties it would incur. It would be quite possible to extend this pollyfill with that support, though keeping it dynamic AND performant may be challenging... using Element.currentStyle would be the inroad to that support, although that is non-standard, but supported by FireFox which is the only place this issue currently exists (I do wonder sometimes if it will ever go beyond FireFox, it's been 4 years now).

@IanBellomy
Copy link

IanBellomy commented Jun 9, 2020

Reference context dependence can be avoided with some re-thinking of CSS. However utilizing context-based styling is very powerful because you can make things automatically look entirely (or slightly) different, with minimal CSS - or at least you could, but now it would require much duplication with the same CSS, not merely re-arranging it.

Indeed. When I said that it's impossible that was not quite right — but the absence of reference styling does / could mean significant refactoring, the need to remember the constraints the document needs to follow at some point in the future, and more JS to manage complex trees.

using Element.currentStyle would be the inroad to that support

This is an interesting idea I hadn't thought of! Though in addition to potential overhead, that overhead would grow over time from some users to every user as more agents implemented SVG2...

@ThomasBrierley
Copy link

in addition to potential overhead, that overhead would grow over time from some users to every user as more agents implemented SVG2.

Yes, it's far from ideal, the mutation observers add non-insignificant overhead, it's usable but makes use more expensive.

I wrote the polyfill out of necessity for compatibility rather than a way forward... the sheer number of assets we had utilizing SVG USE were too great to wrangle into the 'new' awkward way of achieving context base styling within the shadow DOM (see higher in this thread).

This is the other problem with this issue: backwards incompatible changes in what is supposed to be a backwards compatible revision...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests