DroidOS DroidOS - 5 months ago 15
CSS Question

CSS selector for :before pseudo-element when there is one class but NOT another class

I am working with Bootstrap to create a user interface where amongst other things I want to enhance the appearance of radio buttons by ensuring that a checkmark appears prior to the selected radio option. No problem I thought - a simple spot of CSS should do it. So I tried

.active:before{font-family:gftm;content:'\e844';padding-right:0.2em;}


where
gftm
happens to be my own Fontello generated font. This worked but it introduced an unexpected problem. I am also using Bootstrap toggle buttons in this particular application which in their
off
state use the classes
active toggle-off
which ends up showing a spurious and misleading checkmark prior to the button text in its off state. I tried fixing this by modifying my CSS rule

.active:before:not(.toggle-off){font-family:gftm;content:'\e844';padding-right:0.2em;}


which did little other than stop the checkmarks appearing altogether. The solution I am using right now is to follow the rule above with an additional rule

.toggle-off:before{content:'' !important;}


However, I suspect that there is probably a neater way of doing this with just the one CSS rule. I'd be much obliged to anyone who might be able to suggest one that works.

Answer

Your approach is correct and it should produce the required output except for a small mistake that you have made in the selector. The below is how you had written it:

.active:before:not(.toggle-off) {
  font-family: gftm;
  content: '\e844';
  padding-right: 0.2em;
}

but the problem is that pseudo-element selector (:before) must appear at the end and not before the negation pseudo-class.

The below is what W3C Spec says about pseudo-elements and their area of presence:

Only one pseudo-element may appear per selector, and if present it must appear after the sequence of simple selectors that represents the subjects of the selector.

The below is what the W3C Spec says about simple selectors:

A simple selector is either a type selector or universal selector followed immediately by zero or more attribute selectors, ID selectors, or pseudo-classes, in any order.

(emphasis is mine in both the quoted texts)

The negation (:not) is a pseudo-class and so is a simple selector. This means that the :before cannot appear before it.


In the below snippet, you'd see how it works when the pseudo-element is at the end.

.active:before {
  content: 'Pseudo';
  margin-right: 4px;
}
.active:not(.toggle-off):before { /* this will work */
  color: red;
}
.active:before:not(.toggle-off) { /* this won't work */
  background: beige;
}
<div class='active'>Actual</div>
<div class='active toggle-off'>Actual</div>
<div class='toggle-off'>Actual</div>
<div class=''>Actual</div>

Comments