The draft spec for CSS4 pseudo-selectors still state that ::before
and ::after
must have a content
property with a value that is not none
, and while this might have made sense back in 2011, this seems a very strange requirement to preserve. Especially given that user-select: none
now exists, and ::before
/::after
no longer need to be used as a hack to inject unselectable text anymore, it seems very odd to still require that content
property.
Something like the following CSS should, reasonably speaking, "just work":
div.someclass {
/* some styling */
}
div.someclass::before {
width: 1em;
height: 1em;
border-radius: 1em;
background: url(...), papayawhip;
}
The fact that content: " ";
is still necessary in a new CSS revision seems a missed opportunity to streamline some quirks. Can https://drafts.csswg.org/css-pseudo-4/#generated-content be changed to finally make content
as optional as any other CSS property?
The reason for this restriction is to avoid having to create ::before
and ::after
pseudo-elements for every element. Removing it without a reasonable alternative would substantially increase the performance (at least one of speed and memory, and perhaps both) overhead of the feature.
Hm, but wouldn't the fact that the CSS says there is a ::before
or ::after
allow whichever DOM engine is being used to just build one "as needed", in exactly the same way as they're doing right now when they see those properties in combination with content
?
After all, with the content
property currently required, there is a one-to-one mapping: whether the engine checks for "pseudo-selector + content
property" or just "pseudo-selector", the result is the same: given that no pseudo-element gets built without content
right now anyway, ignoring the property and just looking at ::before
and ::after
yields the same functionality, with the same number of pseudo-elements created, at the same moments in time?
(I would be incredibly surprised if there is production CSS out there that uses :before
and :after
without a content property, and then doing something like using JS to toggle that property value by manipulating either the stylesheet's textContent, or by directly manipulating the associated CSSRule object, and not know full well that's a super bad hack)
The problem today is that detecting whether a box is needed for a ::before
or ::after
is a very quick check of just two properties (content
and display
). What you're proposing would require either checking some arbitrary number of properties (to look for anything that would cause a non-default rendering), or just always creating a box.
Also, I think it's quite common to style ::before
and ::after
quite generally with the assumption that those styles only apply to the pseudo-elements that are brought into existence by the content
property.
I'm not sure I follow - instead of checking for content
and display
, you'd check for ::before
and display
(or ::after
and display
). Is that more work? Yes, by one string, which increases complexity by 100%, but also by a single string check. I don't see a performance hit here? (except maybe once you hit thousands of DOM elements, but at that point, ::before
or ::after
is not going to be your bottleneck)
As for the common style: well, sure, but that's literally because that's what the spec has said it'd do since it got added. Just because it's expected doesn't mean it can't be made nicer =)
@Pomax when @dbaron says
Also, I think it's quite common to style ::before and ::after quite generally with the assumption that those styles only apply to the pseudo-elements that are brought into existence by the content property.
He means the change will break websites. A big part of the living specs is to not break things. I for one know I have code out in the wild that would break if this was changed.
I'm not sure I follow - instead of checking for content and display, you'd check for ::before and display (or ::after and display). Is that more work? Yes, by one string, which increases complexity by 100%, but also by a single string check. I don't see a performance hit here? (except maybe once you hit thousands of DOM elements, but at that point, ::before or ::after is not going to be your bottleneck)
So to put a concrete example, this would mean that a page with 2000 elements (which is not a lot, for example in this website document.all.length
returns 3059
) and the rule *, *::before, *::after { box-sizing: border-box }
(which is quite common) causes the engine to create 4000 pseudo-elements instead of zero (since display
is inline
by default).
That's not cool.
No it's not, but I can also say I've literally ever seen a rule like that before, so it would be nice if there were actual figures that could be put on "what people actually use" to see whether it safe or not to change this. If that rule showed up in our CSS, pretty sure any of the eng. team would reject the PR going "please don't set properties on *
".
(This is when a working github code search would be great. Can't search all codebases for content: " "
, which would be super helpful in this case)
In addition to all the above performance-based arguments, this change would straight up be a breaking behavior change in nearly every site, because it would cause all boxes to have two additional children, a change which is very visible if the box is using flexbox or grid, among other things.
I'm going to go ahead and close this bug, as there's no possibility for us to consider this.
Most helpful comment
The problem today is that detecting whether a box is needed for a
::before
or::after
is a very quick check of just two properties (content
anddisplay
). What you're proposing would require either checking some arbitrary number of properties (to look for anything that would cause a non-default rendering), or just always creating a box.Also, I think it's quite common to style
::before
and::after
quite generally with the assumption that those styles only apply to the pseudo-elements that are brought into existence by thecontent
property.