Skip to content

[all] Feature detection for CSS property support on certain elements #4498

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

Closed
upsuper opened this issue Nov 8, 2019 · 12 comments
Closed

[all] Feature detection for CSS property support on certain elements #4498

upsuper opened this issue Nov 8, 2019 · 12 comments

Comments

@upsuper
Copy link
Member

upsuper commented Nov 8, 2019

There are properties which are supported on SVG elements, but not HTML element, and vice versa. Some of them become supported in both sets of elements, but there is no direct way to detect such support, and thus authors cannot have website respond to availability of that, which is unfortunate.

I think this is something we need to solve, but I don't have good idea about how this can be solved in a general way.

One possible solution might be to introduce a guideline that when a property is not applied to certain kinds of elements, it must be computed to some default value. That would make it easier to detect via using gCS. Specific behavior can probably be discussed case by case, but it could help if this is taken into consideration during designing.

Also if we do introduce this guideline, we should audit existing properties and change and test accordingly.

WDYT?

@faceless2
Copy link

I'd be a bit cautious here because of this sort of construct:

<body style="text-transform: uppercase; font-family: serif">
 <svg>
  <foreignObject>
   <div>This text is uppercase serif</div>
  </foreignObject>
 </svg>
</body>

Both text-transform and font-family are inheritable, the fact that only the latter applies to SVG elements shouldn't prevent both from inheriting through. That's how I understand it anyway. Also consider that CSS can apply to any namespace, not just HTML and SVG. Namespace-based magic is a bad idea IMHO.

@Loirooriol
Copy link
Contributor

Loirooriol commented Nov 8, 2019

Assuming that a property either applies or doesn't apply to certain kinds of elements seems too simplistic. There are various cases in which some values of a property don't apply to certain kinds of elements, but other values of the same property do.

@upsuper
Copy link
Member Author

upsuper commented Nov 8, 2019

Both text-transform and font-family are inheritable, the fact that only the latter applies to SVG elements shouldn't prevent both from inheriting through. That's how I understand it anyway.

That's a good point. Inherited properties may be a problem if we want to rely on they can be passed through unsupported elements.

Also consider that CSS can apply to any namespace, not just HTML and SVG. Namespace-based magic is a bad idea IMHO.

I'm not calling for a "magic". It's more about something that editors should be taking into consider.

There are existing practices, for example, content property should always compute to normal when applied on an element (rather than a pseudo-element) in CSS 2 (although it's not quite respected).

Also browsers' style engine already has the infrastructure to do all kinds of fixups on computation stage based on element tag / namespace or value of certain properties. One such example is display: contents, which may compute to none on a given list of elements.

Assuming that a property either applies or doesn't apply to certain kinds of elements seems to simplistic. There are various cases in which some values of a property don't apply to certain kinds of elements, but other values of the same property do.

Yeah, I understand that there are complicated cases, thus I mentioned that existing ones may need to be discussed case by case.

@upsuper
Copy link
Member Author

upsuper commented Nov 8, 2019

To make it crystal clear, what made me raise this issue is clip-path, which is a property initially only supported on SVG elements, but later also applied to HTML elements. Nowadays, most modern browsers support this property on both SVG and HTML element, except the legacy Edge, which supports it only on SVG. This makes it practically impossible to do feature detection for this, and we would have to do UA-sniffing, which is unfortunate.

The reason that we need to diverge on this is ... because there are various browser bugs involving, especially WebKit has a relatively poor support for SVG elements on some aspects which my colleague and I have filed several bugs for. So we want to avoid touching SVG elements in some cases but instead using `clip-path` on HTML whenever possible. But this doesn't work for the legacy Edge.

This case makes me think that this is a problem CSS should solve, given the guideline from TAG. But I totally understand that it could be rather hard, and I don't really have a perfect solution for this.

I file this issue basically just want to raise the concern of this problem, and kick off discussion about this.

@emilio
Copy link
Collaborator

emilio commented Nov 8, 2019

Probably not a solution for already existing stuff, but I think when we expand support for one property to a different set of use-cases (like gap for flex containers, the clip-path for HTML content, etc...) we could define new feature queries in @supports or such to allow feature-detecting them.

Though gap-in-flex is feature-detectble via layout queries... I think clip-path may be feature-detectable by elementFromPoint? From a quick test it does affect hit-testing so something like this seems to work:

<!doctype html>
<style>
  body {
    margin: 0;
  }
  div {
    width: 100px;
    height: 100px;
    background-color: green;
    clip-path: inset(50px);
  }
</style>
<div></div>
<script>
  const clipPathInHtmlSupported = document.getElementFromPoint(50, 50) != document.querySelector("div");
</script>

Obviously not amazing, but I think it can work. For new stuff I'd propose using new @supports queries... @supports feature(clip-path-in-html), @supports feature(gap-in-flex)?

@emilio emilio closed this as completed Nov 8, 2019
@emilio emilio reopened this Nov 8, 2019
@emilio
Copy link
Collaborator

emilio commented Nov 8, 2019

Err, obviously didn't want to close it, sorry, wrong button :)

@upsuper
Copy link
Member Author

upsuper commented Nov 21, 2019

Defining a new keyword for each feature would be quite unfortunate, and also easy to be forgotten by spec editors. It would probably be better if there is some more automatic mechanism. But any such mechanism may also need extra work for implementations, so maybe not scalable either...

@AmeliaBR
Copy link
Contributor

This type of ability (detecting CSS property support in context of certain elements) is often requested from authors, so I definitely think it's worth discussing. But I don't see an easy solution.

Authors often want this as an extension to @supports rules, but it is beyond something the parser can test. Building in a fixed set of feature keywords that the browser knows about has previously been tried & failed, because as soon as some browsers return bad results, the entire system becomes meaningless.

Reporting something at computed time is an interesting alternative. As mentioned above by faceless2, it needs to work with the fact that you can set properties on elements where they don't apply for inheritance. So changing the computed value doesn't work.

However, we do already have some properties where we maintain a distinction between computed and resolved values for getComputedStyle, so there is currently a bit of a way to detect that "applies to" distinction for those properties. The question is whether it is useful to expand or generalize that in any way: should there be a direct way to detect if a value is resolvable on a particular element?

As a declarative/at-rule feature, I am not optimistic that there will be a generalizable solution. As Oriol notes, "applies to" isn't always a clear question. Different values for the same property may apply differently; e.g., for filter & mask, browsers have implemented support for different syntaxes at different times for the different rendering contexts (SVG or CSS box). And different rendering contexts aren't just related to markup, it also includes different CSS layout types (gap for flex layout) or pseudo-elements.

It might be more reasonable to have this as a DOM API, similar to getComputedStyle, that you can run on a specific element/pseudo-element & identify which style properties are used or unused.

But in the end, even detecting "unused" styles won't always help authors. What if the style property is used, but not in the way you expect according to the latest specs? It becomes a question of testing for correct rendering. Does this property, on this element, with these other styles in effect, have the layout impact or visual result that the author is expecting? And the only way to approach that is with a Modernizr-style suite of JS tests that read back the rendering results.

@SebastianZ
Copy link
Contributor

And different rendering contexts aren't just related to markup, it also includes different CSS layout types (gap for flex layout) or pseudo-elements.

For reference, that's covered in #3559. To keep things simple, I'd say to keep this issue restricted to properties support on specific elements and discuss cases like that one in the other issue.

It would probably be better if there is some more automatic mechanism. But any such mechanism may also need extra work for implementations, so maybe not scalable either...

It's probably my naive understanding of how implementations work, but they obviously already have a way to distinguish different rendering contexts. Let's take the clip-path property mentioned before as an example. Somewhere in the code there must be a check for whether the property is used for rendering the element or not. So, simply spoken something like "if we're in HTML context, do this, if we're in SVG context do that".

At that point in the code it should be possible to "register" the context and signal back "yes, that property is understood in this context".

Once that mechanism for providing that info at render time is implemented, there wouldn't be anany extra work for implementors as it work work automatically. Though the big disadvantage of this solution is that you'll only know this information once you run through the rendering code at least once. So there is no centralized registration of all the properties beforehand.

Anyway, from an author perspective, this feature detection might look like this:

@supports feature(<custom-ident> in <context>) {
   ...
}

where <custom-ident> would be the property name and <context> would be html | svg | mathml.

That makes it generally usable and avoids the introduction of keywords for specific feature checks.

Sebastian

@tabatkins
Copy link
Member

Yeah, @AmeliaBR really lays out everything I would have said. This falls squarely in the intersection of "not a simple parsing-level question a browser can also without special-casing" and "not particularly well-defined", making it unfortunately pretty bad as a thing to try and expose. :(

@upsuper
Copy link
Member Author

upsuper commented Dec 19, 2019

It might not be particularly well defined for arbitrary property and their "apply to" rules, but I think the situation is probably better on HTML vs. SVG. There are many properties which have been introduced from SVG into HTML, and their support level varies, which is a real pain for authors to detect whether it's usable.

For the issue that this is not a simple parsing-level question, I think as far as we provide a way for detecting, web-platform tests may be added to check that browsers have one behavior or the other.

So I don't think it's really that bad.

@upsuper
Copy link
Member Author

upsuper commented Dec 19, 2019

(I came back again because we hit another this kind of property, paint-order, which isn't supported on HTML element by Chrome, but is supported by Firefox and Safari.)

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

8 participants