Are :before :after siblings? - css

The purpose of the question is to investigate the possibility of doings something like:
.element:before {
content: 'before';
color: orange;
}
.element:after {
content: 'after';
color: green;
}
.element:after:hover + .element:before {
color: red;
}
<div class='element'> </div>

Pseudo-elements cannot be targeted by sibling combinators because sibling combinators only represent element siblings, not pseudo-element siblings.
So, although the boxes generated by ::before and ::after are siblings of one another in terms of layout, for the purposes of sibling combinators they are not.
It is not possible to write a selector styling an element's ::before pseudo-element when its ::after pseudo-element is hovered. (For that matter, ::after:hover is not valid outside of Selectors 4 either, and no implementations exist.) There are hacks that make use of things like pointer-events but there is nothing that is guaranteed to work on all browsers.

Related

Pseudo-class inheritance understanding

I thought that pseudo-classes inherited properties from their parent element, but in practice it seems the parent element specifically selects all its pseudo-classes, even if they're not specified.
Eg, given the HTML:
ok
and CSS:
#id-selector {
color: green;
}
a:any-link {
color: red;
}
I thought that color: green would only be inherited by the pseudo-class any-link, and thus be overriden by the a:any-link selector since this is a specific selector for the pseudo-class, and specific selectors override inherited properties even if they have a lower specificity. But the output of the above is a green link, indicating that #id-selector is specifically targeting any-link, not it being inherited.
An example of a specific selector with a lower specificity overriding an inherited property with a higher specificity:
HTML -
<div id="id-has-high-specificity">
<h1 class="class-has-low-specificity">Heading</h1>
</div>
CSS -
.class-has-low-specificity {
color: green;
}
#id-has-high-specificity {
color: red !important;
}
here the output is green, which is expected, since the heading is only inheriting from the second rule, but is being specifically selected by the first rule.
I thought this same thing applied to pseudo-classes, in that pseudo-classes inherited from their parent element. But it seems from my first example that they don't, and that rather the parent element specifically selects all its pseudo-classes, even if they're not specified.
Is it the case then that pseudo-classes don't inherit any properties from their parent element, but instead the parent element specifically sets all of its pseudo-classes whenever a rule for it is defined, even if those pseudo-classes aren't specified?
CSS ascertains which selector(s) 'win(s)' following a set of order of precedence rules.
For example, from MDN:
Selector Types The following list of selector types increases by
specificity:
Type selectors (e.g., h1) and pseudo-elements (e.g., ::before).
Class selectors (e.g., .example), attributes selectors (e.g.,
[type="radio"]) and pseudo-classes (e.g., :hover).
ID selectors (e.g., #example).
So in the example given in the question:
ok
and CSS:
#id-selector {
color: green;
}
a:any-link {
color: red;
}
The color does not turn to red because the id selector takes precedence, even though the setting for a comes after in the 'cascade'.
Here's a snippet where the color does change (for this example on a hover):
#id-selector {
color: green;
}
a#id-selector:hover {
color: lime;
}
a:hover {
color: red;
}
</style>
ok
UPDATE
From comments I'm wondering if there is some confusion about pseudo elements (and classes) - they are 'part of' the one element, they are not a child of a 'parent' element.
This snippet has a parent/child and in that case the specificity as assumed in the question works:
#id-selector {
color: green;
}
a:hover {
color: red;
}
<div id="id-selector">ok</div>

How to edit :After-Content() when hovering? [duplicate]

How can I write :hover and :visited condition for a:before?
I'm trying a:before:hover, but it's not working.
This depends on what you're actually trying to do.
If you simply wish to apply styles to a :before pseudo-element when the a element matches a pseudo-class, you need to write a:hover:before or a:visited:before instead. Notice the pseudo-element comes after the pseudo-class (and in fact, at the very end of the entire selector). Notice also that they are two different things; calling them both "pseudo-selectors" is going to confuse you once you run into syntax problems such as this one.
If you're writing CSS3, you can denote a pseudo-element with double colons to make this distinction clearer. Hence, a:hover::before and a:visited::before. But if you're developing for legacy browsers such as IE8 and older, then you can get away with using single colons just fine.
This specific order of pseudo-classes and pseudo-elements is stated in the spec:
One pseudo-element may be appended to the last sequence of simple selectors in a selector.
A sequence of simple selectors is a chain of simple selectors that are not separated by a combinator. It always begins with a type selector or a universal selector. No other type selector or universal selector is allowed in the sequence.
A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
A pseudo-class is a simple selector. A pseudo-element, however, is not, even though it resembles a simple selector.
However, for user-action pseudo-classes such as :hover1, if you need this effect to apply only when the user interacts with the pseudo-element itself but not the a element, then this is not possible other than through some obscure layout-dependent workaround. As implied by the text, standard CSS pseudo-elements cannot currently have pseudo-classes. In that case, you will need to apply :hover to an actual child element instead of a pseudo-element.
1 Of course, this does not apply to link pseudo-classes such as :visited as in the question, since pseudo-elements aren't links.
Write a:hover::before instead of a::before:hover: example.
To change a menu link's text on mouseover (different language text on hover), here is the
jsfiddle example
HTML:
<a align="center" href="#"><span>kannada</span></a>
CSS:
span {
font-size: 12px;
}
a {
color: green;
}
a:hover span {
display: none;
}
a:hover:before {
color: red;
font-size: 24px;
content: "ಕನ್ನಡ";
}
Try to use .card-listing:hover::after, hover, and after using ::. It will work.
Or you can set pointer-events:none to your a element and pointer-event:all to your a:before element, and then add hover CSS to a element:
a{
pointer-events: none;
}
a:before{
pointer-events: all
}
a:hover:before{
background: blue;
}
BoltClock's answer is correct. The only thing I want to append is that if you want to only select the pseudo element, put in a span.
For example:
<li><span data-icon='u'></span> List Element </li>
instead of:
<li> data-icon='u' List Element</li>
This way you can simply say
ul [data-icon]:hover::before {color: #f7f7f7;}
which will only highlight the pseudo element, not the entire li element.
You can also restrict your action to just one class using the right pointed bracket (">"), as I have done in this code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
span {
font-size: 12px;
}
a {
color: green;
}
.test1>a:hover span {
display: none;
}
.test1>a:hover:before {
color: red;
content: "Apple";
}
</style>
</head>
<body>
<div class="test1">
<span>Google</span>
</div>
<div class="test2">
<span>Apple</span>
</div>
</body>
</html>
Note: The hover:before switch works only on the .test1 class

Children :before content inheritance

The title might be a little bit confusing but I wonder why is it impossible for a child element to inherit it's parent ::before content. for example:
HTML:
<div class="foo">
<div class="baz"></div>
</div>
CSS:
.foo::before {
content: 'bar';
}
.foo .baz::before {
content: inherit;
}
I have tried it that way, and even this way:
.foo > .baz::before {
content: inherit;
}
and this one:
.foo::before ~ .baz::before {
content: inherit;
}
...and none of the above worked... Is it possible at all? if not, which options do I have in order to achieve this?
UPDATE
I think I might found a way to do such thing:
.foo {
content: 'bar';
}
.foo > .baz,
.foo > .baz::before {
content: inherit;
}
A ::before/::after pseudo-element cannot inherit from another ::before/::after pseudo-element. A pseudo-element can only inherit from its originating element — this is the element that the pseudo-element is attached to. A pseudo-element cannot even inherit from the parent of its originating element, unless the originating element itself is also inheriting from its parent and the property involved is not content.
In your example, .foo::before can only inherit from the .foo it's attached to, and likewise for .baz::before and .baz. .baz::before cannot inherit from .foo::before, so what you're trying to do is not possible. There does not appear to be a reliable way to ensure that one pseudo-element always inherits from another pseudo-element through CSS alone without enforcing this within the markup itself.

CSS3 transition, target element before hover element

I’m trying to learn a bit more about the CSS3 transitions and “cool stuff”. So I have some nifty animations on my site, and I did some google research that helped me out quite a bit.
I wanted to select an element outside of my hover element. I found out that using the + sign you can target an element that comes after the hover element. A small example (in LESS):
header{
display: inline-block;
div#bg_2{
color:#000;
}
div#container{
float:left;
&:hover{
& + nav {
ul{
opacity: 0;
}
li{
.transition(1200ms, ease-in-out);
margin-left:-100px;
}
}
}
}
nav{
height:30px;
}
}
So this example allows me to give a transition to the element after the hover element. But my question is, is it possible to do the reverse? To target the element before the hover element? In the example, the bg_2 element.
The ! subject selector in the CSS Selectors 4 draft specification would be a way to select a previous element. It proposes that instead of writing .one + .two { … } to style .two, you could write !.one + .two { … } to style .one.
However, ! is currently not implemented in any browser. And the CSS Selectors 4 specification can still change, because it is a draft. Also, the spec currently marks the ! subject selector as being in the “complete” profile, which is meant to be used by JavaScript, but not in the “fast” profile, which CSS must use.
Since you can’t use !, there is currently no way to select what you want with pure CSS.
See also this answer about there being no parent selector, which links to the CSS specifications where you can find all defined selectors.
CSS alone can't currently achieve what you're after. We have sibling selectors (+ and ~), but the element being targeted must come after the first element.*
As a simple example, check out this fiddle. Given this markup:
<p class="one">One</p>
<p class="two">Two</p>
and this CSS:
.one ~ .two { background: red; }
.two ~ .one { background: green; }
You might expect .one to end up green and .two red. In reality, only .two receives a background colour, because the second line is trying to style an element that comes earlier in the DOM.
* + is the adjacent sibling combinator, ~ the general sibling combinator. See this CSS Tricks article for details. They are very similar: + will only target an element that is directly after another specific element whereas ~ will target a sibling that appear anywhere after it.

How can I write a ':hover' condition for 'a:before' and 'a:after'?

How can I write :hover and :visited condition for a:before?
I'm trying a:before:hover, but it's not working.
This depends on what you're actually trying to do.
If you simply wish to apply styles to a :before pseudo-element when the a element matches a pseudo-class, you need to write a:hover:before or a:visited:before instead. Notice the pseudo-element comes after the pseudo-class (and in fact, at the very end of the entire selector). Notice also that they are two different things; calling them both "pseudo-selectors" is going to confuse you once you run into syntax problems such as this one.
If you're writing CSS3, you can denote a pseudo-element with double colons to make this distinction clearer. Hence, a:hover::before and a:visited::before. But if you're developing for legacy browsers such as IE8 and older, then you can get away with using single colons just fine.
This specific order of pseudo-classes and pseudo-elements is stated in the spec:
One pseudo-element may be appended to the last sequence of simple selectors in a selector.
A sequence of simple selectors is a chain of simple selectors that are not separated by a combinator. It always begins with a type selector or a universal selector. No other type selector or universal selector is allowed in the sequence.
A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
A pseudo-class is a simple selector. A pseudo-element, however, is not, even though it resembles a simple selector.
However, for user-action pseudo-classes such as :hover1, if you need this effect to apply only when the user interacts with the pseudo-element itself but not the a element, then this is not possible other than through some obscure layout-dependent workaround. As implied by the text, standard CSS pseudo-elements cannot currently have pseudo-classes. In that case, you will need to apply :hover to an actual child element instead of a pseudo-element.
1 Of course, this does not apply to link pseudo-classes such as :visited as in the question, since pseudo-elements aren't links.
Write a:hover::before instead of a::before:hover: example.
To change a menu link's text on mouseover (different language text on hover), here is the
jsfiddle example
HTML:
<a align="center" href="#"><span>kannada</span></a>
CSS:
span {
font-size: 12px;
}
a {
color: green;
}
a:hover span {
display: none;
}
a:hover:before {
color: red;
font-size: 24px;
content: "ಕನ್ನಡ";
}
Try to use .card-listing:hover::after, hover, and after using ::. It will work.
Or you can set pointer-events:none to your a element and pointer-event:all to your a:before element, and then add hover CSS to a element:
a{
pointer-events: none;
}
a:before{
pointer-events: all
}
a:hover:before{
background: blue;
}
BoltClock's answer is correct. The only thing I want to append is that if you want to only select the pseudo element, put in a span.
For example:
<li><span data-icon='u'></span> List Element </li>
instead of:
<li> data-icon='u' List Element</li>
This way you can simply say
ul [data-icon]:hover::before {color: #f7f7f7;}
which will only highlight the pseudo element, not the entire li element.
You can also restrict your action to just one class using the right pointed bracket (">"), as I have done in this code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
span {
font-size: 12px;
}
a {
color: green;
}
.test1>a:hover span {
display: none;
}
.test1>a:hover:before {
color: red;
content: "Apple";
}
</style>
</head>
<body>
<div class="test1">
<span>Google</span>
</div>
<div class="test2">
<span>Apple</span>
</div>
</body>
</html>
Note: The hover:before switch works only on the .test1 class

Resources