2

It's strange that I couldn't find anyone else reporting this problem; that makes me think perhaps I am doing something wrong.

I have a <style> tag within an SVG that contains a :hover pseudo-class, it works properly when the SVG is directly embedded into the HTML, but when I put it within a symbol and reference it with a <use> tag, the styles inside the <style> tag are not applied.

SVG Directly-embedded:

<svg width="400" height="110">
  <style>
    #myRect:hover {
      fill: red;
    }
  </style>
  <rect id="myRect" width="300" height="100" />
</svg>

Defined in a symbol, and referenced via the <use> tag.

<svg style="display: none">
  <symbol id="rectangle">
      <style>
        #myRect:hover {
          fill: red;
        }
      </style>
      <rect id="myRect" width="300" height="100" />
  </symbol>
</svg>

<svg width="400" height="110">
    <use href="#rectangle"></use>
</svg>

Why is this happening?! Seems like a weird behavior, am I missing something?!

UPDATE: As Temani Afif mentioned in the comments, this problem exists only in Chrome, Firefox seems to work as expected. (Haven't tested on any other browsers)

Arad Alvand
  • 8,607
  • 10
  • 51
  • 71

2 Answers2

3

An alternative using CSS variables that can cross the shadow with inheritance:

use[href*="rectangle"]:hover {
  --f:red;
}
<svg style="display: none">
  <symbol id="rectangle">
      <rect style="fill:var(--f)"  width="300" height="100" />
  </symbol>
</svg>

<svg width="400" height="110">
    <use href="#rectangle"></use>
</svg>

Works without inline style:

use[href*="rectangle"]:hover {
  --f:red;
}
<svg style="display: none">
  <symbol id="rectangle">
    <style>
      rect {
        fill:var(--f);
      }
    </style>
      <rect  width="300" height="100" />
  </symbol>
</svg>

<svg width="400" height="110">
    <use href="#rectangle"></use>
</svg>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Clever solution +1. But it would be inconvenient for more complex styles and animations. – Arad Alvand Nov 01 '20 at 15:18
  • @Arad I think you can also use it with complex styles. I used inline styles but you can keep the use of external styles (see the updates) – Temani Afif Nov 01 '20 at 19:13
3

This is actually an interesting case, and while Temani Afif gave the right solution, I think it is worth a few more words in a separate answer.

First off, the question is not where the <style> tag sits. It could really be anywhere. The real question is raised by the :hover selector.

<svg style="display: none">
  <symbol id="rectangle">
      <style>
        #myRect {
          fill: blue;
        }
        #myRect:hover {
          fill: red;
        }
      </style>
      <rect id="myRect" width="300" height="100" />
  </symbol>
</svg>

<svg width="400" height="110">
    <use href="#rectangle"></use>
</svg>

The previous SVG 1.1 spec had a short paragraph that said "CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree", but the SVG 2 spec dropped that sentence.

It now has a lot to say about how style inheritance works for <use> elements. but all of it concerns the question: "If there are style rules for the corresponding element (the <symbol>), how are they applied to the shadow instance (what is inside the <use>)?"

But one question I really could find no answer to is: If a pseudo-class state applies to a shadow host, can the shadow instance elements also have that state? Or, to state it more clearly: If a pointer hovers over a <use> element, does it also hover over the elements inside the shadow tree?

There are no obvious answers in CSS Selectors or CSS Scoping, to name the other two relevant specs. And while Temani Afif alludes to the second one (and what was proposed when ::shadow was removed), this is not the same: nobody tries to select into the shadow tree, it is just that the rule selects a corresponding element.

That is where Firefox answers "yes" and Chrome answers "no". Which one is the bug? Interestingly, I could not find a bug report in either of the bug trackers.

ccprog
  • 20,308
  • 4
  • 27
  • 44
  • 1
    *If a pointer hovers over a element, does it also hover over the elements inside the shadow tree?* --> I would say yes because it works with Custom Elements: https://jsfiddle.net/pq2fLg7n/ so I would vote for a bug on Chrome – Temani Afif Nov 01 '20 at 19:17
  • I didn't actually know that the problem was in fact the `:hover` pseudo-class, not the ` – Arad Alvand Nov 02 '20 at 00:38
  • 1
    The problem is that it drastically changed between [svg1.1](https://www.w3.org/TR/SVG11/struct.html#UseElement) and [svg2](https://svgwg.org/svg2-draft/struct.html#UseElement). Previously the rule was "CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree", now it is "The cloned content inherits styles from the ‘use’ element and can be the target of user events". – Kaiido Nov 07 '20 at 14:09