30

I was looking at the Twitter bootstrap framework and I do have a very small question.

I'll see the following section in order to set the box-model to border-box.

*, *::after, *::before { box-sizing: border-box; }

But if you look at the CSS specifications * targets all elements, so why on earth is the *::after and *::before selector being used?

To me, this seems obsolete because the * selector will already tag all elements.

Harry
  • 87,580
  • 25
  • 202
  • 214
Complexity
  • 5,682
  • 6
  • 41
  • 84
  • 14
    The `*` doesn't target pseudo elements – Dan Gamble Jul 09 '15 at 12:19
  • Let's say if I have a `P` element, what will be triggered by `*::after`, thus `p::after`? – Complexity Jul 09 '15 at 12:22
  • 1
    `pseudo classes` !== `elements`, `all elements` === `*`. – Mr_Green Jul 09 '15 at 12:22
  • @Complexity they are both the same thing, difference being `*` targets every element as opposed to just `p` – Dan Gamble Jul 09 '15 at 12:23
  • You mind explaining it with a small example as I don't get it completely? – Complexity Jul 09 '15 at 12:23
  • @DanGamble Then my question remains. I don't see what will be targeted by those pseudo elements. It the *::after needed here? What would happen if I leave it away. Some small example is handy to understand. – Complexity Jul 09 '15 at 12:24
  • This answer may be of some use to you: http://stackoverflow.com/a/24794612/3400962 – Hidden Hobbes Jul 09 '15 at 12:24
  • [Here is a demonstration, @Complexity.](https://jsfiddle.net/ffpsp2v9/) – Pointy Jul 09 '15 at 12:28
  • @Pointy So, why it doesn't work? I don't need `*::after` to target the surprise. Check [this](https://jsfiddle.net/ffpsp2v9/1/) – Patel Jul 09 '15 at 12:31
  • @Patel pseudo-elements inherit some properties from the parent element. – Pointy Jul 09 '15 at 12:31
  • @Pointy Is there some documentation of which properties do they inherit? – Patel Jul 09 '15 at 12:32
  • @Patel I don't know of a single source, but in the W3C specs for CSS properties it is usually stated clearly whether the value is inherited or not. I don't *think* that the rules are different for the `::before` and `::after` cases, but I'm not an expert. – Pointy Jul 09 '15 at 12:34
  • 3
    According to the [W3 recommendation](http://www.w3.org/TR/css3-ui/#box-sizing), the box-sizing is not inherited, that's why it has to be set specifically for pseudo-elements. – Alvaro Montoro Jul 09 '15 at 12:34
  • 1
    @Mr_Green: Neither are pseudo-classes the same thing as pseudo-elements. See my comment on Harry's answer. – BoltClock Jul 10 '15 at 05:34

7 Answers7

23

Does * select all elements?

No, * does not cover pseudo-elements. They cover only real elements that are present in DOM.

From the W3C Spec:

The universal selector, written as a CSS qualified name [CSS3NAMESPACE] with an asterisk (* U+002A) as the local name, represents the qualified name of any element type. It represents any single element in the document tree in any namespace (including those without a namespace) if no default namespace has been specified for selectors.

emphasis is mine


Why does property specified under * selector work for some but no others?

For some properties like color you would get the illusion of * applying to all elements including pseudos because they are properties that a child can inherit from its parent.

box-sizing on the other hand is not an inherited property and hence must be explicitly mentioned on the pseudo elements also.

Note: Though the pseudo-elements are named as before and after they are actually children of the element to which it is attached).


Example to illustrate inheritance:

Have a look at the below snippet and see how the black border is applied only for the real elements. Among the pseudo elements, only the p:after gets the border because it is directly specified on the pseudo-element itself. The div:after gets no border.

* { /* selects all real elements */
  border: 1px solid black; /* not an inheritable property and so pseudos don't get it */
  padding: 10px;
  color: red; /* inheritable property and so pseudos which are children inherit it */
}
div::after {
  content: 'abcd';
  margin: 4px;
}
p::after {
  content: 'abcd';
  margin: 4px;
  border: 1px solid red;
}
<div>abcd</div>
<p>abcd</p>

What are the list of inheritable properties?

You can find more details about the list of properties that a child can inherit from its parent here.

Harry
  • 87,580
  • 25
  • 202
  • 214
  • 2
    You _should_ use `::` for pseudo elements and `:` for pseudo classes. Though IE8 only supports pseudo elements though `:` – Andreas Louv Jul 09 '15 at 12:28
  • 1
    By extension, all simple selectors target real elements only. Pseudo-elements are a completely separate category from elements and their simple selectors altogether. In fact, one of the many differences between a pseudo-element and a pseudo-class is that a pseudo-element is *not* a simple selector. It follows that pseudo-elements have a very different set of grammatical rules from simple selectors, and this is why it is a grave mistake to conflate the two. – BoltClock Jul 10 '15 at 05:30
21

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)

Tom Jardine-McNamara
  • 2,418
  • 13
  • 24
  • Thanks. This is the answer that I'm looking for. Just one additional question and then I'll accept your answer. Am I right to say that I don't need to target `*::after` when I don't have a CSS class in which I'm using `content`? The reason I do think that's true is because otherwise everything on the page are REAL elements that will be targeted by the `*` selector. – Complexity Jul 09 '15 at 12:31
  • 1
    `::before` and `::after` won't render if they don't have a `content` property defined. Is that what you mean? Also worth noting that you could also use `::after {}` without the * to target all `::after` psuedo-elements. As others have noted, older versions of IE require a single colon instead (as defined in the earlier CSS2 spec) – Tom Jardine-McNamara Jul 09 '15 at 12:34
  • Indeed. So that selector is only required when setting content directly through css (so it's not a real element on the page and has no markup in the HTMl file). – Complexity Jul 09 '15 at 12:37
5

You basically answered your own question. ::before and ::after are pseudo-elements. The name even implies that they don't represent true elements.

The selector *, *::before, *::after is meant to match:

  • * All elements present in the DOM
  • *::before The pseudo element ::before relative to all elements present in the DOM
  • *::after The pseudo element ::after relative to all elements present in the DOM

Since pseudo-elements aren't qualified as full elements (<html>, <head>, <body>, etc.) and aren't part of the DOM, they are not matched by an asterisk character. They are only matched when selected in reference to another element. They can't be selected in JavaScript for the same reason. JavaScript only selects elements that it can find in the DOM, which is not true in reference to pseudo elements.

To quote from MDN:

You can use only one pseudo-element in a selector. It must appear after the simple selectors in the statement.

A simple selector is defined by W3C using the following definition:

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

Simple selectors are meant to match elements present in the DOM. A pseudo element must follow a simple selector since it is not part of the DOM itself, and consequently, can not be classified as an element. Since * is a simple selector, specifically the universal selector, pseudo elements in CSS can be chained to it to match all of that particular pseudo element type. Without the pseudo element selector, only a simple selector would remain (*).

Anonymous
  • 11,748
  • 6
  • 35
  • 57
  • The question is, why not just write `::before` or `::after`, just like you'd write `.some-class` instead of `*.some-class`? – Pointy Jul 09 '15 at 12:25
  • The thing with pseudo elements drives me nuts. What are in fact those pseudo elements? What would happen if I don't use the ::after selector? – Complexity Jul 09 '15 at 12:25
  • 1
    @Pointy: I don't think that's the question, judging from this comment by the OP ^ – Cerbrus Jul 09 '15 at 12:26
  • @Complexity the `::before` and `::after` selectors allow for a sort-of "virtual" element to be injected into the beginning or end of another container element. So, `span::before` would let you put content at the front of every span. Note that these make sense because of the `content` CSS property. – Pointy Jul 09 '15 at 12:27
  • @Cerbrus yes I agree - sorry for the confusion – Pointy Jul 09 '15 at 12:27
  • @Complexity They're basically half-elements. In some ways they are elements. In some, they're not. – Anonymous Jul 09 '15 at 12:28
  • @Complexity if you didn't use them then nothing would happen. It's just there to help https://css-tricks.com/almanac/selectors/a/after-and-before/ – Dan Gamble Jul 09 '15 at 12:31
  • @Pointy: To answer your question, there is no difference other than clarity. See the notes at the end of [this answer](http://stackoverflow.com/questions/24794545/universal-selector-and-pseudo-elements/24794612#24794612) (which was brought up in the comments on the question but apparently went unnoticed). – BoltClock Jul 10 '15 at 05:40
4

::after and ::before are pseudo elements and they insert the style after or before the element correspondingly.

For your question with *::after and *::before is used to manage appearing spaces. If you don't, the box-sizing is content-box and you'll see the difference (even can't see by our eyes) in spacing.

You can get more information about box-sizing here.

To me, this seems obsolete because the * selector will already tag all elements.

No. * selector will only select the real selector that are in DOM-Tree.

Here's a picture I made for you using before and after pseudo element can insert element like this:

enter image description here

Pseudo elements are outside the DOM-Tree. So, using * won't select them:

enter image description here

Bhojendra Rauniyar
  • 83,432
  • 35
  • 168
  • 231
  • That doesn't answer my question. I'm using a `*` selector, thus, for every element. Why do I need the after selector then. Isn't the element after not targeted by the * selector? – Complexity Jul 09 '15 at 12:20
  • @Complexity `.myClass::after` doesn't target the element after `.myClass` but targets a pseudo element that you can manipulate. Btw pseudo means: `not genuine; pretended` – Andreas Louv Jul 09 '15 at 12:24
  • The question being asked is why the `*::before` selector has to include the `*`. If it were a simple class, for example, you wouldn't write `*.some-class`, you'd write just `.some-class`. – Pointy Jul 09 '15 at 12:24
  • 1
    @Pointy The question being asked is if why `*` doesn't target `*::before`. Not why `*::before` includes `*` – Andreas Louv Jul 09 '15 at 12:26
  • @dev-null yes yes, sorry for the misunderstanding. (I'm curious about that however :) – Pointy Jul 09 '15 at 12:29
  • @Pointy I just made this for you: https://jsbin.com/juwecegura/1/edit?html,css,output :-) – Andreas Louv Jul 09 '15 at 12:31
  • @dev-null ha ha ok thanks - I figured it would work. – Pointy Jul 09 '15 at 12:33
  • @Pointy: The `*` before is not required but is recommended. You can find more about that [here in the spec](http://www.w3.org/TR/css3-selectors/#universal-selector). – Harry Jul 09 '15 at 12:40
3

Below is the pseudo element structure from CSS-Tricks

Pseudo elements structure

* will target only the element.

*::after and *::before are pseudo elements, not real i.e they are not part of the DOM. They lie in between the content and element, so you could insert any extra content you wish without modifying the markup.

m4n0
  • 29,823
  • 27
  • 76
  • 89
2

* targets all elements.

::before and ::after are pseudo elements so aren't targeted by the * so to target these as well you use the code you used in the OP.

You can do a site without using pseudo elements at all it's just there for the people that do use them so they have a consistant box-model and don't start scratching their heads when they go to use a ::before or ::after and it's calculated differently.

Dan Gamble
  • 3,965
  • 1
  • 24
  • 44
2

The reason is *::before and *::after are pseudo-elements. They are not indeed elements thats the reason they are called pseudo.

They are not selected by * because it selects only elements. Thats why you cannot select them

Abhinav
  • 8,028
  • 12
  • 48
  • 89