简体   繁体   中英

Why can't a certain DOM element have CSS styles

While developing an Angular app I've come across the following issue: an SVG element didn't have styles from its class (even though it was defined in <styles> tag) and what's more peculiar (and the point of the question): Chrome and Firefox DevTools didn't allow adding element styles manually .

Chrome DevTools 未显示 element.styles Note the missing element.styles block in the right pane.

However, if I edit container element HTML and just copy and paste back the markup - it suddenly appears and everything works as expected. So this must happen due to the way the element is added to DOM programmatically. And since this behaviour is identical in both Chrome and Firefox, it is most likely a feature, rather than a bug.

So how can this be achieved purposedly?

PS For those interested in Angular part, here is a GitHub issue that I reported for this case (also contains a reproduction repo): https://github.com/angular/material2/issues/15727

So I've found the answer myself. TL;DR : element was created with document.createElementNS with an unknown namespace (or empty), which made it an Element , rather than SVGElement . Styles are not defined for base Elements according to the specification.

So obviously the key was to check the type of the element - and both Chrome and Firefox have shown that that SVG is created as a base Element :

元素被创建为基本元素,而不是 HTMLElement 或 SVGElement

The next question was how did it happen. TL;DR for this section: due to a bug in Angular's new experimental compiler (probably) it was added with an invalid namespace and the rest is according to specification.

Search through Angular's source revealed the way it creates elements: createElementNS .

Quick experiment with that function has proven the initial guess that the problem was with the element's interface ( Element ), and it can be reproduced by passing an invalid namespace.

And DOM specification revealed exactly why does that happen:

createElementNS steps :

The internal createElementNS steps...:
...
4. Return the result of creating an element given document, localName, namespace , prefix, is, and with the synchronous custom elements flag set.

Creating an element is defined as follows:

To create an element, given a document, localName, namespace, and optional prefix, is, and synchronous custom elements flag, run these steps:
...
4. Let definition be the result of looking up a custom element definition given document, namespace , localName, and is.

Looked up definition turns out to be NULL in this case:

To look up a custom element definition, given a document, namespace, localName, and is, perform the following steps. They will return either a custom element definition or null:
1. If namespace is not the HTML namespace, return null .

Returning to createElementNS steps from before:

...
7. Otherwise: [definition is null]

  1. Let interface be the element interface for localName and namespace.
  2. Set result to a new element that implements interface , with no attributes, namespace set to namespace, namespace prefix set to prefix, local name set to localName, custom element state set to "uncustomized", custom element definition set to null, is value set to is, and node document set to document.
    ...

And finally, the element interface is defined as follows:

The element interface for any name and namespace is Element , unless stated otherwise.

As for inability to add custom styles, that is due to the missing style property on the base Element . That's probably due to the specification of the style attribute :

All HTML elements may have the style content attribute set. This is a style attribute as defined by the CSS Style Attributes specification.

HTML elements are :

To ease migration from HTML to XML, UAs conforming to this specification will place elements in HTML in the http://www.w3.org/1999/xhtml namespace, at least for the purposes of the DOM and CSS. The term "HTML elements" refers to any element in that namespace, even in XML documents.

However, style property exists in SVGElement , and probably some other base prototypes, so there must be some other specifications that allow that. But I thought that's out of scope of my original question.

And that concludes my research.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM