What’s the point of the ::before and ::after pseudo-element selectors in CSS?
The CSS2.1 spec says this about generated content:
In some cases, authors may want user agents to render content that does not come from the document tree. One familiar example of this is a numbered list; the author does not want to list the numbers explicitly, he or she wants the user agent to generate them automatically. Similarly, authors may want the user agent to insert the word "Figure" before the caption of a figure, or "Chapter 7" before the seventh chapter title. For audio or braille in particular, user agents should be able to insert these strings.
Basically the purpose is to minimize pollution of the content structure by "content" that is otherwise more suited as presentational elements, or better to be automated.
What is the purpose of :before :after pseudo selector without content?
/* apply a natural box layout model to all elements, but allowing components to change */
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
This is just a general formatting statement...it's not trying to insert content here so the content
property isn't required.
Pseudo-elements don't fall under the univeral selector *
for box-sizing so the property has to be specifically applied.
Why do the :before and :after pseudo-elements require a 'content' property?
The reason you need a content: ''
declaration for each ::before
and/or ::after
pseudo-element is because the initial value of content
is normal
, which computes to none
on the ::before
and ::after
pseudo-elements. See the spec.
The reason the initial value of content
isn't an empty string but a value that computes to none
for the ::before
and ::after
pseudo-elements, is twofold:
Having empty inline content at the start and end of every element is rather silly. Remember that the original purpose of the
::before
and::after
pseudo-elements is to insert generated content before and after the main content of an originating element. When there's no content to insert, creating an additional box just to insert nothing is pointless. So thenone
value is there to tell the browser not to bother with creating an additional box.The practice of using empty
::before
and::after
pseudo-elements to create additional boxes for the sole purpose of layout aesthetics is relatively new, and some purists might even go so far as to call it a hack for this reason.Having empty inline content at the start and end of every element means that every (non-replaced) element — including
html
andbody
— would by default generate not one box, but up to three boxes (and more in the case of elements that already generate more than just the principal box, like elements with list styles). How many of the two extra boxes per element will you actually use? That's potentially tripling the cost of layout for very little gain.Realistically, even in this decade, less than 10% of the elements on a page will ever need
::before
and::after
pseudo-elements for layout.
And so these pseudo-elements are made opt-in — because making them opt-out is not only a waste of system resources, but just plain illogical given their original purpose. The performance reason is also why I do not recommend generating pseudo-elements for every element using ::before, ::after
.
But then you might ask: why not have the display
property default to none
on ::before, ::after
? Simple: because the initial value of display
is not none
; it is inline
. Having inline
compute to none
on ::before, ::after
is not an option because then you could never display them inline. Having the initial value of display
be none
on ::before, ::after
is not an option because a property can only have one initial value. (This is why the initial value of content
is always normal
and it is simply defined to compute to none
on ::before, ::after
.)
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)
when to use pseudo-classes and when to use pseudo-elements selectors in CSS
The single colon syntax is an older implementation. In general, there are pseudo-elements ::
& pseudo-classes :
, and they are not identical. In this case though, browsers still support the outdated single-colon syntax.
This means that in your example with :before
/::before
, it will not make a difference to the outcome, but in general you should use the double colon syntax, because before & after are pseudo-elements, not pseudo-classes.
Read more on MDN.
Can I use a :before or :after pseudo-element on an input field?
:after
and :before
are not supported in Internet Explorer 7 and under, on any elements.
It's also not meant to be used on replaced elements such as form elements (inputs) and image elements.
In other words it's impossible with pure CSS.
However if using jquery you can use
$(".mystyle").after("add your smiley here");
API docs on .after
To append your content with javascript. This will work across all browsers.
When to use :before or :after
The naming of ::before
and ::after
is not entirely arbitrary, but it only really makes sense when the content of those pseudo elements is displayed inline, just before or just after the content of the element they are attached to.
As soon as you use
position: absolute;
in a pseudo element (which is totally legitimate), it no longer matters whether that pseudo element is named ::before
or ::after
.
It might just as easily be named ::presentational-frill-1
or ::presentational-frill-2
.
What is the difference between pseudo-classes and pseudo-elements?
From https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Pseudo-classes_and_pseudo-elements
Pseudo-class :
A CSS pseudo-class is a keyword, preceded by a colon (:), added to the end of selectors to specify you want to style the selected elements, and only when they are in certain state. For example, you might want to style an element only when it is being hovered over by the mouse pointer, or a checkbox when it is disabled or checked, or an element that is the first child of its parent in the DOM tree.
Examples:
- :active
- :checked
- :nth-child()
- :first
- :hover
Pseudo-elements ::
Pseudo-elements are very much like pseudo-classes, but they have differences. They are keywords, this time preceded by two colons (::), that can be added to the end of selectors to select a certain part of an element.
Examples:
- ::after
- ::before
- ::first-letter
- ::first-line
- ::selection
- ::backdrop
As stated by @stephanmg:
In practice ::before is used as :before and ::after is used as :after
because of browser compatibility. Both are pseudo-elements, but may
look like pseudo classes. This might be confusing if you read CSS
code.
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
You could also pass the content to the pseudo element with a data attribute and then use jQuery to manipulate that:
In HTML:
<span>foo</span>
In jQuery:
$('span').hover(function(){
$(this).attr('data-content','bar');
});
In CSS:
span:after {
content: attr(data-content) ' any other text you may want';
}
If you want to prevent the 'other text' from showing up, you could combine this with seucolega's solution like this:
In HTML:
<span>foo</span>
In jQuery:
$('span').hover(function(){
$(this).addClass('change').attr('data-content','bar');
});
In CSS:
span.change:after {
content: attr(data-content) ' any other text you may want';
}
Related Topics
Remove/Reset CSS Behavior Property
How to Check If a Browser Supports Shadow Dom
How to Add Multiple Linear-Gradients to a CSS Background
Why Does Bootstrap Use '!Important' for Responsive Classes
What Is a Parse Error and How to Fix It
Why Is My Content Showing Outside The Div
Select First Descendant with CSS
HTML: How to Create a Div with Only Vertical Scroll-Bars for Long Paragraphs
How to Position The Bootstrap Carousel Controls to The Extreme Right and Extreme Left
How to Make Padding:Auto Work in CSS
Angular Incorrect Margin-Left Applied to Sidenav Content
How to Use '&' and a Tag on the Same Selector
Why Do Fixed Elements Slow Down Scrolling in Firefox
Browser Handling of CSS "Transparent" in Gradients
Preventing an Image from Being Draggable or Selectable Without Using Js
Horizontal Scroll in Div with Many Small Div's Inside (No Text)