theonlydidymus theonlydidymus - 7 months ago 71
HTML Question

Change parent div background color when hovering text

I've seen some similar posts about this but not one that seems to answer this question.

In an effort to learn CSS animations, I'm trying to do a 100% CSS verion of this site.

The snag I've hit is that I can make it do the "rainbow animation when I hover over the "whitey" div, but I want it to only do this when I hover over the word "rainbow." Is there a way I can set the "whitey" div to 0 opacity while hovering over the text?



#bg {
/*BASIC DIV STYLING*/
width: 500px;
height: 250px;
font-size:50px;
line-height:250px;
text-align:center;
position: relative;
font-family:sans-serif;

/*ANIMATION INFORMATION*/
-webkit-animation-name: example; /* Chrome, Safari, Opera */
-webkit-animation-duration: 10s; /* Chrome, Safari, Opera */
animation-name: example;
animation-duration: 10s;
animation-iteration-count:infinite;
}

/*DISPLAY CONTENT ON A WHITE BACKGROUND*/
.whitey {
background-color:white;
width:500px;height:250px;
}
/*MAKE THE WHITE BACKGROUND DISAPPEAR ON HOVER*/
.whitey:hover{
background-color: rgba(0, 0, 0, 0);
}

/*THE ANIMATION*/
@keyframes example {
0% {background-color: #ff0000;}
10% {background-color: #ff8000;}
20% {background-color: #ffff00;}
30% {background-color: #80ff00;}
40% {background-color: #00ff00;}
50% {background-color: #00ff80;}
60% {background-color: #00ffff;}
70% {background-color: #0080ff;}
80% {background-color: #0000ff;}
90% {background-color: #8000ff;}
100% {background-color: #ff0080;}
}
}

<div id="bg">

<div class="whitey">

<p>
RAINBOW
</p>

</div>
</div>




Answer

Without using JS you the background needs to be a child or sibling element of the the element you want to initiate the animation. In your case an element with some text.

Non-Preferred Solution

There's a couple ways to get the background animation element as a child element of the text element.

  1. Nest an element: <h1>Rainbow<div class="rainbow"></div></h1> or
  2. Create a pseudo element with CSS on the text element.

The way you get the child element "out" of the parent element is through absolute positioning. That will stretch the element out to the edges of the next positioned ancestor element.

.rainbow {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
}
/* or */
h1:before {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;        
}

The issue with using some form of child element is that if you need to position the parent text element then the background doesn't get stretched out like you'd like it to. The parent text element's positioning would create a new context for the absolute positioned child background element to be confined in.

Update: You can use position: fixed; though other position values will not work. Thanks for @Green and our discussion on his answer for this update. This will not work properly either if you used translate on the text element and position: fixed; on the animated background element.

Preferred Solution (Updated)

* Updated so that animation does not get restarted on each hide/show.

So I suggest using a sibling element approach. This will allow you to position the text element without confining the background element, i.e. the center of an element/page.

As your example page uses an element to hide/show the animated background, so can you. Apply the animation right away and use the sibling selector to hide/show the element that hides/shows the animated background.

<h1>Rainbow</h1>
<div class="lid"></div>
<div class="rainbow"></div>
html,
body {
  position: relative;
  height: 100%;
  margin: 0;
}
h1 {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate( -50%, -50% );
}
.lid,
.rainbow {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
.lid {
  background-color: white;
  z-index: -1;
}
.rainbow {  
  animation-name: rainbow;
  animation-duration: 3s;
  animation-iteration-count: infinite;
  z-index: -2;
}
h1:hover + .lid {
  display: none;
}

@keyframes rainbow {
  0%   { background-color: #ff0000; }
  10%  { background-color: #ff8000; }
  20%  { background-color: #ffff00; }
  30%  { background-color: #80ff00; }
  40%  { background-color: #00ff00; }
  50%  { background-color: #00ff80; }
  60%  { background-color: #00ffff; }
  70%  { background-color: #0080ff; }
  80%  { background-color: #0000ff; }
  90%  { background-color: #8000ff; }
  100% { background-color: #ff0080; }
}

Demo JSFiddle, updated.

In both solutions you'd need an ancestor element that fills the whole viewport so your absolute positioned background element does as well.

Comments