Can CSS: Not Selector Target: Before and: After Selectors

Can CSS :not selector target :before and :after selectors

As per W3C Spec:

The negation pseudo-class, :not(X), is a functional notation taking a simple selector (excluding the negation pseudo-class itself) as an argument. It represents an element that is not represented by its argument.

A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.

As you can see from the above statements, :not() takes in only a simple selector as argument and pseudo-elements do not fall under the simple selector category. Hence, no, you cannot achieve what you are trying in the way you are trying.

One way to hide the element's default content but get the pseudo-element's content to be displayed would be to set font-size: 0px on the element and then over-ride it to the required size within the pseudo-element's selector like in the below snippet:

a.button:before {  content: "Show Text";  font-size: 16px;}a.button {  font-size: 0px;}
<a href="#" class="button">Hide Text</a>

Do not style pseudo-class :before/:after

There is no need for something like :not(:before). The #main selector does that already. To see this, set a non-inheritable property like border:

#main { border: 1px solid; }

This will draw a border around main. It will not draw another border around the generated content. So the selector targets #main only. Your generated content has a transparent background (default).

The problem is rather that the generated content lives inside an anonymous box inside #main:

+-------------+
| +-----+ |
| | foo | bar |
| +-----+ |
+-------------+

Basically, this is the same situation as

<div id="main">
<span class="before">foo</span>
bar
</div>

You can easily see that it's not possible to add a background to the word bar only, because #main's background will shine through the span. If you use #main:not(.before) as a selector, this will change absolutely nothing.

All you can do is overwrite this by adding a white background to .before. Or insert a span around bar, as suggested in another answer.

Other properties like font are subject to inheritance, so technically the cause of the problem is different, but the solution is the same.

Is there a CSS selector for text nodes?

Text nodes cannot have margins or any other style applied to them, so anything you need style applied to must be in an element. If you want some of the text inside of your element to be styled differently, wrap it in a span or div, for example.

Can I target a :before or :after pseudo-element with a sibling combinator?

You can't target :after since it's content is not rendered in the DOM and it does not manipulate it - for this to work the DOM would have to be re-rendered and CSS can't manipulate it like this.

Check the specification for detailed understanding: http://www.w3.org/TR/CSS2/generate.html#propdef-content

Generated content does not alter the document tree. In particular, it
is not fed back to the document language processor (e.g., for
reparsing).

I suggest you use JavaScript to do the job for you.

Why use * selector in combination with *::before and *::after

See these two JSFiddles:

http://jsfiddle.net/86gc1w6f/
http://jsfiddle.net/gwbp2vpL/1/

Or try these snippets:

CSS:

* {
box-sizing: content-box;
}

p {
position: relative;
width: 200px;
border: 10px solid rgba(255, 0, 0, 0.5);
}

p::after {
position: absolute;
right: -100px;
top: -10px;
width: 100px;
height: 30px;
border: 10px solid rgba(0, 0, 255, 0.5);
content: '';
}

HTML:

<p>
A paragraph
</p>

Changing the box-sizing between content-box and border-box only alters the size of the paragraph, not it's ::after element. As others have noted, this is because they are, as named, pseudo elements and must be targeted separately.

It would appear that * does not target psuedo-elements (which as @Harry points out, is as per the CSS specification)

CSS Selector for adding content through :after / :before when HTML element is missing

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.



Related Topics



Leave a reply



Submit