What is the difference between pseudo-classes and pseudo-elements? - css

What is the difference between div::after {} and div:after {} ? When do we have to use :: over :?
Double colon and single-colon notation is to distinguish between
pseudo-classes and pseudo-elements.
What is the actual meaning of the above statement?

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.

Pseudo-classes :
it is applied automatically by the browser
depending on the position of the element or its interactive state.
For Example :
E:hover Matches elements of type E when the cursor is
hovering over it.
Pseudo-elements :
It is applies styles to content
based on its position in the HTML hierarchy.
For Example :
E::first-letter This applies a style to the first letter of the first line inside a block-level
element E.
So ,
The CSS3 Selectors specification prefixes pseudo-elements with two colons instead of one.
So, :first–letter becomes ::first-letter and :first-line becomes ::first-line.
IE 8 and earlier don’t understand the double-colon prefix, so you need use
the single-colon versions to avoid styles breaking in older browsers.

Related

Can pseudo-elements be used alone in CSS?

According to W3C, the definition of a selector does not cover a pseudo-element:
https://www.w3.org/TR/css3-selectors/#selector-syntax
The above link says:
A selector is a chain of one or more sequences of simple selectors
separated by combinators.
and it also says:
A simple selector is either a type selector, universal selector,
attribute selector, class selector, ID selector, or pseudo-class.
Regarding how a pseudo-element should be used, it says:
One pseudo-element may be appended to the last sequence of simple
selectors in a selector.
and
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.
So does that mean that a pseudo-element can only be a suffix to a "valid" selector and should not be used alone?
does that mean that a pseudo-element can only be a suffix to a "valid"
selector and should not be used alone?
Your conclusion is not true, because the universal selector * can be omitted.
If a universal selector represented by * [...] is immediately
followed by a pseudo-element, then the * may be omitted and the
universal selector's presence implied.
So you can use a pseudo-element alone, e.g. ::before, because under the hood it will be treated like *::before.
::before {
content: 'Hello!';
}

Strange use of CSS ::before, ::after

Saw this bit of CSS in a Sitepoint example (from this article), and can't understand what it's supposed to do. Obviously the first selector applies the box-sizing style to everything, but I don't understand the use of ::before/::after in this case. I know those are used to add content before or after a given element, but what purpose does it serve here?
*,
*::before,
*::after {
box-sizing: border-box;
}
This will force any ::before or ::after element to use the box-sizing property as well, as you can shape them as if they are boxes. The * does not include these pseudo-elements, so *::pseudo will do that for you.
thats the old implementation of :
The double colon replaced the single-colon selectors for
pseudo-elements in CSS3 to make an explicit distinction between
pseudo-classes and pseudo-elements. For backward compatibility, the
single-colon syntax is acceptable for pre-CSS3 selectors. So, :after
is a pseudo-class and ::after is a pseudo-element
the : is used for :before and :after pseudo-elements which together with the content: allow you to put something for example an image or icon etc before/after every selector you specified
So, here you are selecting everything and applying box-sizing property and style before and after it, as * does not include psuedo-elements
The selector means:
apply to all elements, apply to contents before each element, and apply to contents after each element.

Using CSS pseudo and attribute selectors together

Because of a bug in webkit browsers, you can't use attribute and :before/:after classes by default.
The fix doesn't seem to have any effect when using nth-last-of-type selector.
Here's what I'm doing:
.left[class^='col']:nth-last-of-type{
margin-right: 0 !important;
}
Just wanted to check and see if I'm not overlooking something simple.
Your :nth-last-of-type syntax is a bit off — it's either :last-of-type or functional :nth-last-of-type() with a formula an+b as an argument.
The pseudo-classes pertaining to "type" refer to the element type, represented by its tag name. It does not mean "the last element matching the rest of this selector".
If, for example, the last element matching .left[class^='col'] is not the last span element, then :last-of-type will not match. You'll have to modify your HTML to either segregate those span elements from others, or add a class to the last such element, before you can target it with a selector.
WebKit does not have any issues with pseudo-classes and attribute selectors that I'm aware of (or if it did, those issues have long been fixed). It does have issues with pseudo-elements, which I address here, where the fiddle link originates.

nesting inside css :not() selectors

Is it possible to have nested values inside the :not selector? For eg:
:not(div > div)
Whenever I tried it, it does not seem to work.
Perhaps you need to use it another way which I have not figured out?
So far, in all the examples I see, you can only use one value inside this selector.
:not() only accepts one simple selector at a time; this is mentioned in the Selectors 3 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.
The simple selectors in your example would be the two div tokens that you have. Other simple selectors include class selectors, ID selectors, attribute selectors and pseudo-classes. It does not accept more than one simple selector, nor does it accept combinators like > or space.
Depending on which elements you're trying to select exactly, there may not be a way to exclude div > div:
If you only want to select elements that are children of a div, that are themselves not div, use this instead:
div > :not(div)
If you only want to select div elements whose parent element is not a div, use this instead:
:not(div) > div
If you want to use this negation by itself, selecting all other elements, then there isn't a way using just a selector.
The only other viable workaround in CSS that I can think of is to apply styles to the elements you want without the :not() expression, then undo them for div > div. This works for any set of elements you're trying to target; the disadvantage is that not all properties can be easily reset.
Alternatively, if you're using jQuery, which does support :not(div > div) unlike the CSS version, you can place the selector in a script and, for instance, have jQuery apply a class name to those elements then target that class in your CSS.
It should work now thanks to Selectors Level 4 which allows :not() to take a list of complex selectors.
You can now also nest :not()... like :not(:not()) which wasn't allowed in Selectors Level 3. Not sure why you'd want to do that but you can.

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

Is there a reason why this CSS doesn't work?
http://jsfiddle.net/6v5BZ/
a[href^="http"]:after {
content:"";
width:10px;
height:10px;
display:inline-block;
background-color:red;
}
a[href^="http"] img ~ :after {
display:none;
}
.. on this HTML?
Test
<a href="http://google.com">
<img src="https://www.google.com/logos/classicplus.png">
</a>
The idea is to have a pseudo-element on matching anchor tags. But I do not want it to apply to anchor tags that wrap an image. And since I can't target anchors using something like a < img, I figured the maybe I could target the :after pseudo-element by finding an image that it's a sibling of.
Any insight would be greatly appreciated.
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.
You cannot use a combinator to target a pseudo-element relative to elements other than its generating element.
This is because they're pseudo-elements, not actual elements, and combinators only work by establishing relationships between actual elements. A pseudo-element, on the other hand, can only be applied to the subject of a selector (the rightmost compound selector), and this happens only after matching is processed on the real elements. In other words, matching is done first as though the pseudo-element wasn't there, then the pseudo-element, if it's indicated within the selector, is applied to each match.
In your code, the following selector:
a[href^="http"] img ~ :after
Does not actually look for an :after pseudo-element that comes after an img within the a, even though it appears that way as both are rendered as children of the a element.
It can be rewritten into the following:
a[href^="http"] img ~ *:after
Notice the * selector, which is implied. Similarly to how you can omit * before any other simple selectors for it to be implied, omitting * from a pseudo-element also makes it implied to be there. See the spec for details.
Now, even though it appears *:after should still match a:after (since a would match *), it still doesn't work that way. If you remove the :after pseudo-element from the selector:
a[href^="http"] img ~ *
You'll notice that the meaning of the selector changes entirely:
Select any element
that appears as a following sibling of an img
that is a descendant of an a (whose href starts with "http").
Since the img is the last child of the a element in your HTML, there are no following siblings to match, and therefore no :after pseudo-elements can be generated.
In the case of a :before or :after pseudo-element, one might think of matching the pseudo-element's generating element relative to the pseudo-element's "sibling", but as the OP has correctly pointed out, there is no parent selector, so they're out of luck there, too.

Resources