This won't be possible without the functionality of the :blank
pseudo-class, I'm afraid.1
There are only two possible places you can insert a ::before
pseudo-element in your scenario: in the ul
, or in a li
. Since you want to insert the generated content only when no li
elements are present, that leaves you only with ul
.
Although ::before
and ::after
are inserted before and after an element's descendant elements respectively, you can't target them relative to those descendant elements with a sibling combinator, and pseudo-elements currently do not support structural pseudo-classes. Which means, in other words, you won't be able to say "prevent ul::before
from generating content in the presence of one or more li
elements", nor can you apply the :only-child
pseudo-class to ul::before
.
In a situation where one can use :empty
, it's as simple as
ul:empty::before { content: 'abc'; }
but since you cannot use :empty
for the reasons you have given, if you really cannot prevent the whitespace from being generated (e.g. if the content is coming from a WYSIWYG editor or some other transformation that may result in leftover whitespace) you'll have to add a class to any ul
elements with no children.
1 A recent revision to selectors-4 proposes subsuming the functionality of :blank
into :empty
instead, but that likewise is new and requires the cooperation of implementers.