0

Let's say I have HTML like so:

<div class="foo">
    <div>Stuff</div>
</div>

And some CSS like so:

.foo > div { display: none; }
.foo:after { /* rules */ }

I would like to be able to do something like

.foo:after:hover > div { display: block; }

to have the user hover over the generated content element and show the child div. Does anyone know how to do this? My attempts so far have been fruitless. Thanks.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Jason
  • 51,583
  • 38
  • 133
  • 185

4 Answers4

2

This question seems to be the opposite of Can I target a :before or :after pseudo-element with a sibling combinator?

In your case, you cannot apply pseudo-classes to pseudo-elements. This also means you cannot choose to apply styles only when a pseudo-element is on :hover but not its generating element. Instead, you can only select a pseudo-element depending on the pseudo-class states of its generating element, and only when this generating element is the subject of the selector.

Also, as mentioned, pseudo-elements are not part of the DOM. Therefore, similarly to how you cannot reach pseudo-elements relatively to real children within the same generating element as shown in my answer to the above question (explanation in the above link):

a[href^="http"] img ~ :after

You cannot select real elements relatively to pseudo-elements within the same generating element:

.foo:after > div

So to sum up, the reason why the following selector won't work:

.foo:after:hover > div

Is twofold:

  1. Pseudo-elements cannot have pseudo-class states, making :after:hover invalid.

  2. The subject of the selector here is not .foo, but div, so :after cannot apply to .foo. Consequently, attempting to select a real element as the subject of a selector after applying a pseudo-element to another selector doesn't make sense.

If you really must not display your div on .foo:hover, but on another child element, then your only way around this without using JavaScript is to make another real element under .foo that comes before the div (not after):

<div class="foo">
    <div></div>
    <div>Stuff</div>
</div>

This is because there is no previous sibling selector; the adjacent sibling selector, which you can use in place of :after > is only for selecting the next sibling:

.foo > div:first-child + div { display: none; }
.foo > div:first-child { /* rules */ }
.foo > div:first-child:hover + div { display: block; }
Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • Thank you for this very thorough, correct answer. I had arrived at this conclusion independently yesterday, but you have filled in a lot of blanks as to why this is the case. Thanks :) – Jason Jul 24 '12 at 17:09
1

You can't interact with generated content, as it's not present in the DOM (it can be accessed, but, so far at least, it's read-only); the only option you have is to use :hover on .foo itself:

.foo:hover > div { }

You could, of course, style the generated content differently on :hover:

.foo:hover::after { }

But, I suspect, that probably isn't any part of what you want to do.

Also, your selector as written: .foo:after:hover > div I think, would try to style the div child of the generated content; which it can't have.

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • i figured this was the case, but was hoping it wasn't. thanks – Jason Jul 23 '12 at 23:01
  • I suspect that, as generated content matures, it'll become present in, and accessible via, the DOM in a read *and* write capacity (and to CSS too), but, sadly, not yet. Sorry I couldn't bring better news =/ – David Thomas Jul 23 '12 at 23:02
  • I've added an answer with an explanation as to why all this doesn't work, as well as an HTML/CSS-based workaround. (I also stole a bit of your use of words just for kicks.) – BoltClock Jul 24 '12 at 08:30
0

You were close. Just ditch the :after portion.

http://jsfiddle.net/QERPq/

UPDATE: http://jsfiddle.net/QERPq/2/ Basically, this says that when you hover over this item, to select the next item (* = catchall) and display it.

Chad
  • 5,308
  • 4
  • 24
  • 36
  • i don't want to ditch the `:after`. that's the part i want to hover over. – Jason Jul 23 '12 at 23:00
  • again, i want the `:after` portion. your fiddle doesn't have any generated content :\ – Jason Jul 23 '12 at 23:08
  • Oh, I get the feeling I missed it again. You want to hover over the "morecontent" area, and display the div inside .foo? – Chad Jul 23 '12 at 23:09
  • Assuming morecontent is generated. – Chad Jul 23 '12 at 23:10
  • i want to hover over the generated content and have the sibling div of the generated content's parent to appear. – Jason Jul 23 '12 at 23:16
  • I still don't think I'm entirely understanding what you're asking, but I generated content, with a child, and hovering over that child displays the normal content. http://jsfiddle.net/QERPq/3/ – Chad Jul 23 '12 at 23:20
  • 2
    @Torr3nt: That is not the CSS definition of "generated content"; that is just using JS to add new elements to the DOM, which has nothing to do with CSS. See the [spec](http://www.w3.org/TR/CSS21/generate.html) to understand what CSS generated content is. – BoltClock Jul 24 '12 at 08:31
0

Try this solution: http://jsfiddle.net/QERPq/4/.

It may or may not be what you are after.

HTML:

<div class="foo">pre-hover stuff</div>

CSS:

.foo > div {
    display: none;
    font-size: 200px;
}
.foo:after {
    content: '';
    display: block;
    position: absolute;
    left: 100px;
    top: 100px;
    width: 100px;
    height: 20px;
    background: yellow;
}
.foo:hover:after {
    display: block;
    content: 'Stuff';
    width: 40px;
    height: 40px;
    background: red;
}
uınbɐɥs
  • 7,236
  • 5
  • 26
  • 42
  • i'm looking to hover over the `:after` and have it show the parent's child div – Jason Jul 23 '12 at 23:33
  • @Jason See the updated fiddle [here](http://jsfiddle.net/QERPq/5/). If either the main `div` or the generated content are hovered over, the child `div` will display. – uınbɐɥs Jul 23 '12 at 23:35
  • ok, but i don't want the div to show when the parent is hovered, just the generated content. – Jason Jul 23 '12 at 23:37
  • @Jason Well that makes it very tricky. Does it *have* to be generated content? – uınbɐɥs Jul 23 '12 at 23:43
  • @Jason - Okay, I solved it. There has to be an overlay `div` - see another updated fiddle: http://jsfiddle.net/QERPq/7/. – uınbɐɥs Jul 23 '12 at 23:45