Open GCSBOSS opened 3 years ago
@GCSBOSS you did great, thanks for the proposal.
We did work on a multiple pseudo-element proposal around the same time as the 2012 blog post, but it was abandoned due to some objections people raised and lack of implementer interest. https://opensource.adobe.com/css-pseudo-elements/docs/css4-pseudoelements.html is one of the iterations, but I have not yet found the resolution we made to stop working on it.
@astearns Thanks for your reply. I would like to see some arguments. Hope more people show up here 😄
Edited with alternative syntax suggestion.
Some of the history: https://lists.w3.org/Archives/Public/www-style/2012Aug/0771.html
For reference, an old spec draft allowed multiple ::before
and ::after
https://www.w3.org/TR/2003/WD-css3-content-20030514/#inserting0
It would be interesting to see some of the specific issues you need to solve with multiple pseudo-elements. The ones I've heard from developers recently often relate to CSS Grid, and the fact you can't style (adding backgrounds, borders and so on) grid areas without adding an element. Those are probably better fixed by allowing styling of grid areas.
So, my question is whether the use cases you have are best solved with multiple pseudo-elements, or might they be better solved in some other way.
@rachelandrew Had this minutes before writing this issue.
::before
::after
off topic: By the way, scrim type of functionally would benefit from some ::behind type of pseudo element.
I believe most of these use cases are not well suited for semantic html elements.
I'd also welcome to be able to stack multiple content generating pseudo-elements. There are definitely some situations in which you'd need them to style an element to avoid having to add extra DOM just for styling. Though having said that, many use cases can already be achieved by different CSS features or other pseudo-elements.
@GCSBOSS wrote:
* A button has an icon (icon-font pattern) on the `::before` * a ripple effect in the `::after`
Ripple effects can also be done using the CSS Painting API. See https://codepen.io/iamvdo/pen/RwWVzar.
* now I need an overlay animation on top of the whole thing.
Depending on the use case this might be achieved by animating the filter
property instead of using a pseudo-element.
* One might also wanna add any other styling/animation details to the same element
Exactly this requires concrete use cases which cannot be achieved by existing CSS features, or at least not without hacks.
* Maybe a scrim for modal functionally
off topic: By the way, scrim type of functionally would benefit from some ::behind type of pseudo element.
By "scrim" I assume you mean a backdrop. There is already a ::backdrop
pseudo-element, which is meant to be used for that.
@rachelandrew wrote:
It would be interesting to see some of the specific issues you need to solve with multiple pseudo-elements. The ones I've heard from developers recently often relate to CSS Grid, and the fact you can't style (adding backgrounds, borders and so on) grid areas without adding an element. Those are probably better fixed by allowing styling of grid areas.
Which is discussed in #4416, btw. Also related to this are #499, #2748, and #5080.
Sebastian
@SebastianZ Thanks for your input 😃 !
Ripple effects can also be done using the CSS Painting API. See https://codepen.io/iamvdo/pen/RwWVzar.
It is an exciting API and probably way better performance. But coding CSS is so much simpler than js/canvas math D:
Depending on the use case this might be achieved by animating the filter property instead of using a pseudo-element.
I totally missed that. I guess there are just so many hours one can keep staring unblinkingly at a stylesheet. Thank you!
Edit: Though after a few attempts I could not reproduce a proper overlay-like flash over element contents without using another element/pseudo-element.
By "scrim" I assume you mean a backdrop. There is already a
::backdrop
pseudo-element, which is meant to be used for that.
I believe that feature has some specific fullscreen behavior entangled in it. So maybe not fit for at least part of the use cases.
@GCSBOSS You're welcome! 😃
Ripple effects can also be done using the CSS Painting API. See https://codepen.io/iamvdo/pen/RwWVzar.
It is an exciting API and probably way better performance. But coding CSS is so much simpler than js/canvas math D:
I assume most authors will not reinvent the wheel and just pick one of the existing solutions for that. That means, as CSS author you'd just add the paint worklet to your page and then only have to define the custom properties. And the JS/canvas solution is also more flexible as it can start the ripple effect at the cursor position.
Though there are pure CSS solutions for this as well, using a pseudo-element to achieve the effect, like http://mladenplavsic.github.io/css-ripple-effect/. And I can see the point of doing this with only using CSS.
Depending on the use case this might be achieved by animating the filter property instead of using a pseudo-element.
I totally missed that. I guess there are just so many hours one can keep staring unblinkingly at a stylesheet. Thank you!
Edit: Though after a few attempts I could not reproduce a proper overlay-like flash over element contents without using another element/pseudo-element.
It would surely help to clarify the need for multiple pseudo-elements if you posted the example code for what you want to achieve. Just show how you get the effect now and how it would be simplified if multiple pseudo-elements were available.
By "scrim" I assume you mean a backdrop. There is already a
::backdrop
pseudo-element, which is meant to be used for that.I believe that feature has some specific fullscreen behavior entangled in it. So maybe not fit for at least part of the use cases.
While it's currently defined in the Fullscreen API specification, it also works for the <dialog>
element. There's also a note about that in the specification. Also have a look at the example in Codepen (which additionally uses the backdrop-filter
property) to blur the backdrop.
What I want to say with that is that there is already a pseudo-element for backdrop/scrim effects. So this use case does not require stacking of pseudo-elements. And if there are still use cases related to backdrop effects which are not covered by ::backdrop
yet, it should rather be discussed whether this feature can be extended to also cover them.
Having said all that, as I wrote earlier, in the past I also ran into a few situations in which I wished we had multiple pseudo-elements to avoid having to add real DOM elements just for styling. Unfortunately, I don't have a good example for that at hand, though. So people should come up with some real world use cases for them like the one from CSS Tricks in the initial post (which can also be achieved by using the CSS Paint API, btw.).
Sebastian
Yea, adding something like more than one ::before
or ::after
, and even more often a wrapping ancestor (sometimes two) without messing with semantics, just for styling, as well as siblings (::before
and ::after
are children; it could be worked around with display: contents
, but it has issues, e.g. causes loss of a natural parent in the box tree for the children from the document along with those inserted using pseudo-elements). It's so common, and doesn't motivate use of any scripting in a solution! Principle of least power FTW!
And we almost had it with XBL's generic div
element in the XBL namespace http://www.w3.org/ns/xbl
which could be used in templates and then applied to elements with the addition of the binding
property to CSS. A fully declarative solution! Unfortunately, that was the time when browser vendors became particularly unwilling to implement anything specified modularly, not tied into the HTML5 überspec, and they rebooted the work on templates and Shadow DOM within that framework, with an approach based on scripting. Therefore, though unnecessary in many widely applicable, simple use cases (and with advancements in CSS also many not so simple), we're forced to use scripting, to have templates be HTML-only, and to work in a cumbersome way with some strange out-of-document trees, resulting from parsing template
elements by a browser (as opposed to any other user agent).
There's still hope that things might get somewhat better in the next iteration. E.g. @tabatkins reminds from time to time that in his opinion (with which, as should be already obvious, I very much agree) enabling this functionality to be used declaratively remains a worthwhile goal.
I remember the first round of this, with ::outside(). We tried implementing it, it got out of control quite quickly.
I thought it worth reminding everyone about content: contents
(https://drafts.csswg.org/css-content-3/#element-content). I don't know how widely implemented it is, but it can be used to move the DOM tree from an element to its pseudonode:
div {
border: 1px solid blue;
content: none;
}
div::before {
border: 1px solid red;
content: contents;
}
This will shift the DOM subtree from the div
to its ::after
pseudo-element - you're getting two borders around the subtree.
We've implemented this and it's fun to do things like self-captioning images:
img {
content: none;
}
img::before {
content: contents;
}
img::after {
content: attr(alt);
}
But it's a bit of a hack, and falls down quite often - if the image has a border, for example, then the caption will too.
What we find ourselves wanting is a sibling pseudo-element, which creates a sibling to the current node. And in fact we effectively have one of these proposed in CSS already: https://drafts.csswg.org/css-gcpm/#footnote-call, but it's limited to footnotes.
Footnotes are content positioned out of normal flow, but a marker is left in the box tree where it was moved from. The way we implement this is to create a sibling pseudo-element before the positioned content. It's so useful, I don't get why it's restricted to footnotes:
position: running(nnn)
float: left
, but that winds up on the next page due to fragmentation.In all these cases you might want to leave a call(*) in the paragraph referering to that content somehow, but you can't do this with a ::before or ::after on the floated content, because that would be moved with the content. Being able to do something like this:
figure {
float: right;
counter-increment: figure;
}
figure::call {
content: "Figure " counter(figure) ": " attr(title);
}
would open up all sorts of possibilities, particularly when combined with content: contents
.
@SebastianZ
I'll try and post some real-life examples soon.
Only to iterate on the <dialog>
matter. abUsing the ::backdrop
for anything other than a dialog would mean creating HTML elements for styling purposes, which defeats the purpose. Especially because <dialog>
is not even a thing anymore (at least it was not, the last time I read about it).
Disclaimer
I imagined this would have been proposed three gazillion times by now. Though I haven't found anything meaningful on the internet. Therefore here we go.
Proposal
I propose a language feature to allow authors to define an arbitrary number of pseudo-elements similar to
::before
and::after
.Benefits
I'm surely missing some good benefits here.
Problems
I am not really sure. Certainly, you people have great experience in spotting CSS proposal loopholes. Thank you!
Syntax
Here goes the first syntax that comes to mind.
Alternative Syntax
Maybe we can use names and define order in the properties.
Maybe we can just ignore ordering altogether and focus on using existing
z-index
andorder
behavior where applicable.References
I'm gonna quote this old article because yes.
PS.: It's the first time I post in here, so please, let me know (and sorry) if I'm doing anything wrong.