kenhimself kenhimself - 4 months ago 9
jQuery Question

How to make selected triggered divs maintain visibility until other divs are hovered over?

How can I make selected

divs
(paired with
.stayhovered
) that were triggered upon hovering over a
div
maintain visible until the person hover overs a different
div
?

jsfiddle here.

Thank you in advance!

HTML

<div class="show" id="subject01">
<h1>Subject 01</h1>
<div class="targetDiv info01">
<div class="topleft stayhovered">
<b>Subject 01, topleft<br/><u>Maintain hover</u> until subject02 is hovered</b></div>
<div class="topright">
Subject 01, topright<br/>Fadeout when cursor hovers out</div>
<div class="bottomleft stayhovered">
<b>Subject 01, bottomleft<br/><u>Maintain hover</u> until subject02 is hovered</b></div>
<div class="bottomright">
Subject 01, bottomright<br/>Fadeout when cursor hovers out</div>
</div> <!-- END | 01 target -->
</div> <!-- END | 01 show -->


<div class="show" id="subject02">
<h1>Subject 02</h1>
<div class="targetDiv info02">
<div class="topleft">
Subject 02, topleft<br/>Fadeout when cursor hovers out</div>
<div class="topright stayhovered">
<b>Subject 02, topright<br/><u>Maintain hover</u> until subject01 is hovered</b></div>
<div class="bottomleft">
Subject 02, bottomleft<br/>Fadeout when cursor hovers out</div>
<div class="bottomright stayhovered">
<b>Subject 02, bottomright<br/><u>Maintain hover</u> until subject01 is hovered</b></div>
</div> <!-- END | 02 target -->
</div> <!-- END | 02 show -->


CSS

/* hoverover text placement */

body {
font-family: helvetica;
font-size: 13px;
background-color: #FAFAFA;
}

.topleft, .topright, .bottomleft, .bottomright {
position: fixed;
}

.topleft {
top:2%;
left:2%;
}

.topright {
top:2%;
right:2%;
}

.bottomleft {
bottom:2%;
left:2%;
}

.bottomright {
bottom:2%;
right:2%;
}


/* Feature Typography */
.featuretitle, .featureinfo, .rotate {

}
.featuretitle {

}
.featureinfo {

}
/* FEATURE DETAIL */
.featuredetail {
font-family:'Courier New', Courier, monospace;
font-weight: normal;
letter-spacing: 1px;
text-align: left;
text-transform: uppercase;
font-size: 11px;
line-height: 18px;
overflow-x: hidden;
position: fixed;
bottom: 20px;
left: 20px;
width: 50%
}

/* Subjects */

#subject01 {
left: 30%;
top: 30%;
position: fixed;
color: #FE5722;
}

#subject02 {
right: 30%;
bottom: 30%;
position: fixed;
color: #3F51B5;
}

/* Feature */
.feature-img-wrap {
display:block;
}
*, *:before, *:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.targetDiv {
position:absolute;
width:100%;
visibility: hidden;
opacity:0;
-webkit-transition: all 250ms linear;
-o-transition: all 250ms linear;
transition: all 250ms linear;
}
.show:hover .targetDiv {
visibility: visible;
opacity:1;
}
.show:hover .stayhovered {
visibility: visible;
opacity:1;
}

Answer

This was quite the challenge, but I think I've got it.

Here's the Fiddle: http://jsfiddle.net/n810v1se/

... and the Snippet:

body {
  font-family: helvetica;
  font-size: 13px;
  background-color: #FAFAFA;
}

.topleft {
  top:2%;
  left:2%;
}

.topright {
  top:2%;
  right:2%;
}

.bottomleft {
  bottom:2%;
  left:2%;
}

.bottomright {
  bottom:2%;
  right:2%;
}


/* Subjects */

#subject01 {
  left: 30%;
  top: 20%;
  position: fixed;
  color: #FE5722;
}

#subject02 {
  right: 30%;
  bottom: 30%;
  position: fixed;
  color: #3F51B5;
}

.targetDiv {
  position:absolute;
  width:100%;
  visibility: hidden;
  opacity:0;
  -webkit-transition: all 250ms linear;
  -o-transition: all 250ms linear;
  transition: all 250ms linear;
}

.topleft, .topright, .bottomleft, .bottomright {
  position: fixed;
  opacity: 0;
  -webkit-transition: all 250ms linear;
  -o-transition: all 250ms linear;
  transition: all 250ms linear;
}

.stayhovered {
  opacity: 1;
}

h1:hover ~ div .topleft,
h1:hover ~ div .topright,
h1:hover ~ div .bottomleft,
h1:hover ~ div .bottomright
{
  visibility: visible;
  opacity: 1;
}

.show:hover .targetDiv {
  visibility: visible;
  position: fixed;
  left: 0px;
  top: 0px;
  height: 100%;
  opacity: 1;
  z-index: -1;
}

.show:hover {
  z-index: 0;
}

.show {
  z-index: 1;
}
<div class="show" id="subject01">
    <h1>Subject 01</h1>
    <div class="targetDiv info01">
        <div class="topleft stayhovered">
            <b>Subject 01, topleft<br/><u>Maintain hover</u> until subject02 is hovered</b></div>
        <div class="topright">
            Subject 01, topright<br/>Fadeout when cursor hovers out</div>
        <div class="bottomleft stayhovered">
           <b>Subject 01, bottomleft<br/><u>Maintain hover</u> until subject02 is hovered</b></div>
        <div class="bottomright">
            Subject 01, bottomright<br/>Fadeout when cursor hovers out</div>
    </div> <!-- END | 01 target -->
</div> <!-- END | 01 show -->


<div class="show" id="subject02">
    <h1>Subject 02</h1>
    <div class="targetDiv info02">
        <div class="topleft">
             Subject 02, topleft<br/>Fadeout when cursor hovers out</div>
        <div class="topright stayhovered">
            <b>Subject 02, topright<br/><u>Maintain hover</u> until subject01 is hovered</b></div>
        <div class="bottomleft">
            Subject 02, bottomleft<br/>Fadeout when cursor hovers out</div>
        <div class="bottomright stayhovered">
            <b>Subject 02, bottomright<br/><u>Maintain hover</u> until subject01 is hovered</b></div>
    </div> <!-- END | 02 target -->
</div> <!-- END | 02 show -->

How it works

The corner elements are within targetDiv, which is hidden by default. It's easy enough to display targetDiv when hovering over its parent, the show class element:

.show:hover .targetDiv {visibility: visible;}

Even though the content within the show-class elements hits every corner of the viewport, the actual width and height of these elements is the width and height of the h1 elements within them. Why? Because their corner elements have fixed positioning. (To see this, add a border to the show class.)

This means that only the h1 elements within show will respond to a hover event.

When the mouse leaves a h1 element, the hover event is canceled, causing targetDiv to disappear. However, we want targetDiv to stay visible until the other h1 element is hovered.

We accomplish this by making targetDiv take up the whole screen when show is hovered:

.show:hover .targetDiv {
  ...
  position: fixed;
  left: 0px;
  top: 0px;
  height: 100%;
}

(targetDiv already has 100% width, so that's not needed here.)

Now when show is hovered, its targetDiv child takes up the entire viewport, causing it to stay hovered.

This works well when moving from subject01 to subject02. But now it's impossible to move from subject02 from subject01. Why? Because when the subject02's show parent is hovered, its content takes up the entire viewport. Since subject02 was declared after subject01, its parent is essentially on top of subject01, making it impossible for subject01 to receive any mouse events.

The solution? Give the show class a default z-index of 1. When it's hovered, change its z-index to 0. That way, it's always behind the other show-class element:

.show {z-index: 1;}
.show:hover {z-index: 0;}

Now to the challenge of keeping the stayhovered elements visible while the other corner elements are not. We do this by adding opacity:1 to stayhovered's default style, and changing the corner elements to opacity:1 only when their previous h1 sibling is hovered:

.stayhovered {opacity: 1;}

h1:hover ~ div .topleft,h1:hover ~ div .topright,
h1:hover ~ div .bottomleft,h1:hover ~ div .bottomright {
 opacity: 1;
}

This seems all well and good. However, now that targetDiv takes up the entire viewport, and it has fixed positioning, it essentially covers the h1 element, making it impossible for the h1 to receive a hover event!

The solution? Add a negative z-index to targetDiv:

.show:hover .targetDiv {
  ...
  z-index: -1;
}

And that's the final piece of the puzzle.

Comments