406

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

I'm trying a:before:hover, but it's not working.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jitendra Vyas
  • 148,487
  • 229
  • 573
  • 852

7 Answers7

571

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.

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 33
    It should be pointed out that that puts the hover on the parent element - which causes the decoration to be applied even if the ::after pseudoelement is not under the mouse, as long as its parent is. – SamGoody Jun 26 '12 at 09:23
  • 7
    It should also be noted that there are a number of things that *don't* respond to this because of the way the layout rules are specified – e.g. `text-decoration`. – Chris Krycho Apr 21 '13 at 00:16
  • 1
    @Chris Krycho: Indeed - I actually happen to have an explanation for this specific issue with regard to pseudo-elements [here](http://stackoverflow.com/questions/11474780/hoverbefore-text-decoration-none-has-no-effects/11481121#11481121). Of course, it's worth clarifying that the issue itself has no connection with pseudo-class/pseudo-element *selectors*, but is as you point out, a layout issue. – BoltClock Apr 21 '13 at 03:00
  • 3
    Sinlge colon (:) designates pseudo-classes and double colon (::) designates pseudo-elements. So it should be a:hover::before – mikkelbreum Jun 05 '13 at 20:45
  • @mwb: Of course, assuming IE8 support is not needed. This answer was posted several months before Selectors 3 even became a recommendation, and I'm not inclined to change it given that IE8 is still significantly used. – BoltClock Jun 05 '13 at 20:52
148

Write a:hover::before instead of a::before:hover: example.

T.Todua
  • 53,146
  • 19
  • 236
  • 237
sandeep
  • 91,313
  • 23
  • 137
  • 155
  • 2
    @mikkelbreum do you have a reference to prove that? – shea Mar 02 '14 at 02:36
  • 3
    @bungeshea: That is CSS3 syntax. See the comments under my answer (as well as my recent edit). It's a little inaccurate to call it "the" correct syntax though because both single and double colons are permitted for CSS1/2 pseudo-elements. I would call it the *recommended* syntax instead, because the only reason to continue using the legacy syntax today is for supporting IE8 and older. – BoltClock Jan 13 '15 at 18:07
  • @mikkelbreum @sheabunge more info on CSS2 `:after` vs CSS3 `::after` https://developer.mozilla.org/en-US/docs/Web/CSS/::after (single `:` has better support) – travis Mar 08 '15 at 05:17
  • it is not working for underline :( http://jsfiddle.net/porzechowski/u5dhthvq/ Please add also display: inline-block; http://jsfiddle.net/porzechowski/u89fo4oq/ – plusz Mar 21 '17 at 17:05
9

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: "ಕನ್ನಡ";
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nagendra Rao
  • 7,016
  • 5
  • 54
  • 92
  • 1
    This is a lovely answer. In fact, it inspired me to [extend your fiddle slightly](http://jsfiddle.net/YSgKL/784/) by boosting the font-size of the span text to 24px to match the replacement text, added 3 non-breaking spaces before and after the replacement text so that they occupy the same width, and styled `a:hover::before` with `text-decoration: underline`, which causes the underline to pick up the red color of the replacement text. – Dave Land Aug 11 '16 at 02:43
  • The syntax highlighter does not like it (near "`color: red;`"). What is the reason? – Peter Mortensen Nov 28 '21 at 01:44
8

Try to use .card-listing:hover::after, hover, and after using ::. It will work.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
subindas pm
  • 2,668
  • 25
  • 18
6

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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
shree_2433
  • 77
  • 1
  • 1
2

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bbrinx
  • 846
  • 8
  • 14
-1

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">
    <a href="#"><span>Google</span></a>
  </div>
  <div class="test2">
    <a href="#"><span>Apple</span></a>
  </div>
</body>

</html>

Note: The hover:before switch works only on the .test1 class

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Stefan Gruenwald
  • 2,582
  • 24
  • 30