w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.46k stars 658 forks source link

[css-images] [css-gcpm] Overloaded definitions of element() #1981

Open kosek opened 6 years ago

kosek commented 6 years ago

Hi,

I have noticed that the following two modules define element() function/notation in the completely different way:

https://www.w3.org/TR/css-images-4/#element-notation https://www.w3.org/TR/css-gcpm-3/#funcdef-element

I see that css-images define element() for use in properties that can reference image whereas css-gcpm currently uses element() for content property. But using same function name for different purposes and with different function arguments is very confusing for CSS authors.

Each function should be named differently or their behaviour should be unified.

Jirka

SebastianZ commented 6 years ago

This name conflict is already filed as issue 6 in CSS Images 4.

Sebastian

SebastianZ commented 6 years ago

So far I see five different (mostly non-exclusive) solutions for this conflict:

1. Define running elements in HTML

Instead of CSS, running elements could be defined within HTML, e.g. via a <running> element, as they have some associated semantic.

Doing so would allow to style them without the need for the running() and element() functions currently defined in the CSS GCPM Module.

Example:

<running position="top-center">
  <h1>My awesome title</h1>
  <h2>With a great subtitle</h2>
</running>
@page {
  @top-center { color: #808080; }
}

2. Rename the element() function in the CSS GCPM Module

If defining the element outside of CSS is not an option, another solution would be to simply rename the element() function within the CSS GCPM Module. It could even be called running(), so definition and usage would be consistent.

Example:

@page {
  @top { content: running(header); }
}

h1 { position: running(header); color: #808080; }

3. Merge the element() functionality defined in the CSS Images Module into image()

As the use case within CSS Images is to use the element as an image, it may also make sense to incorporate the syntax of the element() function into the image() function. Doing so, the syntax of the <image-src> value used in image() could be extended to look like this:

<image-src> = [ <url> | <id-selector> ]

Example:

  background-image: image(#header);
}

h1 { position: running(header); color: #808080; }

4. Let one definition of element() serve both use cases

Only define element() once, e.g. just let it take <id-selector>s. This would make the running() function redundant, because the element would be identified by the selector instead of a custom identifier.

Example:

@page {
  @top-center { content: element(#header); color: #808080; }
}

5. Define the element within the margin at-rule instead via content

Instead of defining the contents of the page margins via the content property they could be defined as value for the margin at-rule.

Examples:

@page {
  @top-center #header { color: #808080; }
}
@page {
  @top-center "My awesome title" { color: #808080; }
}

Sebastian

kosek commented 6 years ago

I will let WG and editors to decide what is the best way to fix this.

Just for the record element() in GCPM spec has been used earlier than in CCS Images and has more shipping implementations already. So it makes more sense to rename it in CSS Images to something like element-snapshot() or whatever.

It's good that issue is mentioned in the spec text, I have missed it, I have only searched GitHub issues before filling new one.

SebastianZ commented 6 years ago

Just for the record element() in GCPM spec has been used earlier than in CCS Images...

That's correct. The element() function was first mentioned in a GCPM Working Draft back in 2006, while the first mention in CSS Images was in a 2011 Working Draft. Having said that, this doesn't have any influence on which syntax to decide on.

...and has more shipping implementations already.

As far as I can see on MDN and caniuse and my own tests, the only existing implementation of this is in Firefox and that one is prefixed. And that -moz-element() function uses the CSS Images syntax. There are no implementations of the unprefixed version yet, so everything is still open for discussion.

But you're right that also the definition within CSS Images could be renamed. Thinking further about that, I've added a fifth solution, which suggests to merge the syntax of the element() function into image(). In my eyes, that would actually be a very clean solution, because image() is already meant to reference or create images.

Sebastian

kosek commented 6 years ago

MDN/Caniuse are not good sources for checking implementation status of GCPM module. Browsers have poor printing support but GCPM and unprefixed element() function is already implemented in various formatting engines, e.g.:

https://www.antennahouse.com/product/ahf64/ahf-css6.html#css3-functions https://www.princexml.com/doc/functions/#css-functions

faceless2 commented 4 years ago

Another solution would be to merge element() with url(), rather than with image().

In all these cases the functionality is exactly the same as what's proposed with element().

It seems weird that while I can fill: url(#patternid) in SVG, in CSS I would have to do background-image: element(#patternid) to achieve the same thing (as suggested by an example in css-images-4).

And what about mask: element(#maskid)? It's a synonym for url(#maskid)?

cdoublev commented 3 years ago

I found this issue after searching for the reasons why as a front-end dev, I can use url(svg-path#fragment) for almost any property accepting a url(), but not url(#svg-child-element) except for some properties (where url refers to a resource versus. an image?) as demonstrated by @faceless2.

While searching for those reasons, I discovered element() and image(), resulting in more confusion. element() doesn't seem to provide anything more than url() for images, and the extra features of image() seem also superflous.

SebastianZ commented 3 years ago

@faceless2 wrote:

Another solution would be to merge element() with url(), rather than with image().

Obviously you only refer to the definition within CSS Images 4, not the one in CSS GCPM 3.

That idea sounds intriguing and I really like it, though reusing url() also has a downside. It's not feature-detectable because URLs with anchors are already valid. I.e. background-image: url(#x); is parsed by user agents, and therefore an author cannot use @supports (background-image: url(#x)) { ... } to check whether the user agent supports using an element as an image or not.

Sebastian

SebastianZ commented 3 years ago

@cdoublev wrote:

and the extra features of image() seem also superflous.

The extra features come "for free" because image() also takes images referenced via url(). So, in that regard it makes sense to merge element() into url().

Though I just realized another little downside of merging it into url(). element() (or selector(), see #5811) might allow different selectors than just ID selectors in the future. Those can't be expressed via url().

Sebastian

cdoublev commented 3 years ago

Thanks, I hadn't noticed that image() can take a url().

I'm not sure that selecting an element via other types of selectors would be an upside. An image value referencing an element will always resolves to a single (~= unique, like an ID) target, while other selectors are more often used to select multiple targets.

SebastianZ commented 3 years ago

@cdoublev wrote:

I'm not sure that selecting an element via other types of selectors would be an upside. An image value referencing an element will always resolves to a single (~= unique, like an ID) target, while other selectors are more often used to select multiple targets.

You might be surprised that even ID selectors can match multiple elements, see https://jsfiddle.net/SebastianZ/qumshra7/. So the algorithm behind that feature already needs to take that into account and pick the first matched element. The spec. currently mentions this as "The ID is first looked up in the elementSources map". This basically means the logic works similarily to document.querySelector() in JavaScript to pick just the first matched element.

But anyway, I am not completely against reusing url() for this purpose, though as I wrote earlier, the main downside is the missing feature detectability via @supports, which means you can't provide a fallback without JavaScript if it doesn't work in a user agent.

Also note that both solutions are non-exclusive.

Sebastian