8

This is a common question. It almost always gets immediately closed as a duplicate of this question: Is there a CSS parent selector?

The duplicate does a good job pointing out that parent elements cannot be targeted with CSS. But it provides little to no guidance for the original question, which may be caught in the XY problem.

In this particular case...

How can the background color of the parent be changed when hovering the child?

...there is at least one CSS solution that may solve the problem.

<div>
  <a href="#">Anchor Text</a>
</div>
Community
  • 1
  • 1
Michael Benjamin
  • 265,915
  • 79
  • 461
  • 583

3 Answers3

10

Using just pointer-events and :hover

Compatibility of pointer-events: caniuse.com. Tested working on IE 11 and Edge, Chrome and Firefox.

  • Set pointer-events: none on the div. The div will now ignore :hover.

    div {
        pointer-events: none;
    }
    
  • Set the parent background to change on hover

    div:hover {
        background: #F00;
    }
    
  • Set pointer-events: auto on the child so that the hover event is triggered only when the child is hovered

    div > a {
        pointer-events: auto;
    }
    

This works because the div is hovered when its child is hovered, and pointer events are activated with auto only on that child. Otherwise the parent ignores its hover pseudo-class.

Example

Note: IE 11 and Edge require the child element to be display: inline-block or display: block for pointer events to work.

div {
  height: 200px;
  width: 200px;
  text-align: center;
  pointer-events: none;
}
div:hover {
  background: #F00;
}
div > a {
  pointer-events: auto;
  display: inline-block;
}
<div>
  <h1>Heading</h1>
  <a href="#">Anchor Text</a>
</div>
misterManSam
  • 22,389
  • 10
  • 63
  • 82
8

Although you can't select parent elements with CSS, you may be able to accomplish the task with another method.

You want the background color of the parent to change when a child is hovered.

Consider using the spread-radius value of the CSS box-shadow property.

By creating a huge spread radius, you can change the color of the surrounding area (which is no different visually than the parent element).

div {
    overflow: hidden;              /* 1 */
}

a:hover {
    box-shadow: 0 0 0 1000px red;  /* 2 */
}

/* non-essential decorative styles */
div { 
  height: 150px;
  width: 150px;
  border: 1px dashed black;
  display: flex;
  justify-content: center; 
  align-items: center;
}
<div>
  <a href="http://www.stackoverflow.com/">Anchor Text</a>
</div>

Notes:

  1. overflow: hidden to limit child's box shadow
  2. the box-shadow values are as follows:

<box-shadow> : <offset-x> <offset-y> <blur-radius> <spread-radius> <color>

  • offset-x ~ horizontal distance from element
  • offset-y ~ vertical distance from element
  • blur-radius ~ makes the shadow increasingly bigger and transparent
  • spread-radius ~ makes the shadow expand (without fading)

In this case, the first three values don't matter.

What you need is for the spread-radius to grow a lot, then have it clipped by the container with overflow: hidden.


And what if there's another element in the container?

<div>
  <h2>Hello</h2>
  <a href="http://www.google.com">Anchor Text</a>
</div>

div {
    overflow: hidden;
}
a:hover {
    box-shadow: 0 0 0 1000px red;
}
div { 
  height: 150px;
  width: 150px;
  border: 1px dashed black;
  display: flex;
  flex-direction: column;
  justify-content: center; 
  align-items: center;
}
<div>
  <h2>Hello</h2>
  <a href="http://www.stackoverflow.com/">Anchor Text</a>
</div>

You can apply a z-index to the sibling.

h2 { z-index: 1; }

And, because the elements happen to be in a flex container in this example, they don't need to be positioned for z-index to work.

h2 { z-index: 1; }

div {
    overflow: hidden;
}
a:hover {
    box-shadow: 0 0 0 1000px red;
}
div { 
  height: 150px;
  width: 150px;
  border: 1px dashed black;
  display: flex;
  flex-direction: column;
  justify-content: center; 
  align-items: center;
}
<div>
  <h2>Hello</h2>
  <a href="http://www.stackoverflow.com/">Anchor Text</a>
</div>
Community
  • 1
  • 1
Michael Benjamin
  • 265,915
  • 79
  • 461
  • 583
6

Another approach if you just want to change the background of the parent element is to fake it with a pseudo-element, consider this structure:

.div1 {
  position: relative;
  padding:2em;
  color:white;
}
a {
  color:white;
  font-family:sans-serif;
}
a:before {
  content:"";
  position:absolute;
  left:0;
  top:0;
  height:100%;
  width:100%;
  background:red;
  z-index:-1;
  transition:background .5s linear;
}
a:hover:before {
  background:purple;
}
<div class="div1">
 <div class="div2">
  <h2>Here Some Title</h2>
  <a href="#">Hover Me</a>
 </div>
</div>
DaniP
  • 36,081
  • 8
  • 59
  • 70
  • 1
    This, of course, relies on the **a** not being positioned ... Good answer :-) – vals Sep 07 '16 at 18:50
  • Yeah @vals in order to work this way you need that and other little things that cna't change, but allows to also use a bg image or gradients and the transitions of course . Thanks. – DaniP Sep 07 '16 at 18:52