vtQQ
vtQQ

Reputation: 37

Hover menu problem with transitions and fast mouse movement

Hovering elements on a vertical menu opens a container that lists my images. This is working as intended, it is made with pure css and hover.

The problem appears when I move my mouse too quickly to an upper li element in the menu. It opens its container but then as I move my mouse to the right inside the container, the previous li element opens its container! I go right, so I am not closer to the lower li elements at all. Doesn't make sense for this trigger.

Happens one in 8 times as I move through menus like a user with random speed. So it is tied to how fast I move my mouse. Firefox requires very fast movement to trigger it. Curiously, it never happens for going to lower li items, always an upper menu item, being too fast, it can be 3rd or 4th menu item opening relative to the li I actually hover. If I wait half a second on the li, then it opens its own container.

I suspect the fade animations inside the container elements. Seems I need to wait for them to complete before moving to right.

html:

<header class="header">
    <nav>
        <ul class="nav flex-column">
            <li class="level1 has_children"><a href="#">Dogs</a>
                <ul class="nav extend row">
                    <li class="level2 col-4 fade-in"><a href="#">Dog Food</a></li>
                    <li class="level2 col-4 fade-in"><a href="#">Dog Clothing</a></li>
                    <li class="level2 col-4 fade-in"><a href="#">Dog Toys</a></li>
                </ul>
            </li>
            <li class="level1 has_children"><a href="#">Cats</a>
                <ul class="nav extend row">
                    <li class="level2 col-4 fade-in"><a href="#">Cat Food</a></li>
                    <li class="level2 col-4 fade-in"><a href="#">Cat Clothing</a></li>
                    <li class="level2 col-4 fade-in"><a href="#">Cat Toys</a></li>
                </ul>
            </li>
            <li class="level1 has_children"><a href="#">Birds</a>
                <ul class="nav extend row">
                    <li class="level2 col-4 fade-in"><a href="#">Bird Food</a></li>
                    <li class="level2 col-4 fade-in"><a href="#">Bird Cages</a></li>
                  <li class="level2 col-4 fade-in"><a href="#">Bird Toys</a></li>
                </ul>
            </li>
        </ul>
    </nav>
</header>

css:

.header {
  border-top: 2px solid #FF3F5E;

  float: left;
  width: 100%;
}

.nav {
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: center;
  font-size: 1.3rem;
  width:11%;
}

nav > ul {
  background: #363636;
}

li:hover {
  background: #1d1d1d;
}
li a {
  text-decoration: none;
  display: block;
  color: #fff;
  padding: 11px;
  text-decoration: none;
}

.level1 {
  width: auto;
  float: left;
  text-transform: uppercase;
}

.level2 {
  text-transform: none;
  transition: 300ms;
}



.has_children {
}
.has_children ul {
  visibility: hidden;
  max-height: 0;
  height: auto;
  position: absolute;
  left: 211px;
  opacity: 0;
  width: 100%;
  background: inherit;
  list-style: none;
  background: #1d1d1d;
  height:240px;
  width:400px;
}
.has_children a {
  display: block;
}
.has_children a:hover {
  background: #101010;
}
.has_children > a:after {
  display: inline-block;
  margin-left: 22px;
  content: "";
  vertical-align: middle;
  border-top: 0.5rem solid #FF3F5E;
  border-left: 0.5rem solid transparent;
  border-right: 0.5rem solid transparent;
}
.has_children:hover ul {
  visibility: visible;
  opacity: 1;
  max-height: 500px;

  transition: 100ms;
}

@-webkit-keyframes fadeInMenuItem { from { opacity:0; } to { opacity:1; } }
@-moz-keyframes fadeInMenuItem { from { opacity:0; } to { opacity:1; } }
@keyframes fadeInMenuItem { from { opacity:0; } to { opacity:1; } }

.has_children:hover ul li.fade-in {
  opacity:0;
}

.has_children:hover ul li.fade-in {
    -webkit-animation:fadeInMenuItem ease-in 1;
  -moz-animation:fadeInMenuItem ease-in 1;
  animation:fadeInMenuItem ease-in 1;

  -webkit-animation-fill-mode:forwards;
  -moz-animation-fill-mode:forwards;
  animation-fill-mode:forwards;

  -webkit-animation-duration:400ms;
  -moz-animation-duration:400ms;
  animation-duration:400ms;
}

.has_children:hover ul li:nth-child(1) {
  animation-delay:50ms;
}

.has_children:hover ul li:nth-child(2) {
  animation-delay:100ms;
}
.has_children:hover ul li:nth-child(3) {
  animation-delay:150ms;
}
.has_children:hover ul li:nth-child(4) {
  animation-delay:200ms;
}

.has_children:hover ul li {
  visibility: visible;
}

.extend {
  width:49vw;
  left:353px;
  position: absolute;
  top:0;
  height:335px;
}

li:hover > ul.extend {
    width:520px
    height: 230px;
    position:absolute;
    left: 211px;
    transition: 100ms;
}

https://codepen.io/volkanqq/pen/PrEEXq

Just go from Cats to Dogs then to right, if you are fast enough you will see Dogs turning into Cats!

Upvotes: 0

Views: 1234

Answers (2)

mmshr
mmshr

Reputation: 947

There are a couple of things coming into play here.

For one, you're right, the animations are playing a role. When you change from hovering "Cats" to "Dogs", "Cats" submenu begins the 300ms transition to being hidden while "Dogs" submenu begins the 300ms transition to being visible. During those 300ms, "Cats" submenu is actually on top of "Dogs" submenu. You can visualize the stacking order of the submenus if you remove their visibility: hidden, opacity: 0, and max-height: 0 properties. If you remove those properties, then you can see "Birds" submenu is on top— if you hide it, then you'll see "Cats" submenu. If you hide that, then you'll see "Dogs" submenu.

During that 300ms transition, "Cats" submenu is above "Dogs" submenu, so if you hover the submenu then you are hovering the "Cats" li even though you appear to be coming from "Dogs".

The first thing I did to fix this was add the following:

.level1 > ul {
   pointer-events: none;
}
.level1:hover > ul {
  pointer-events: all;
}

This, by default, takes away the pointer-events from the submenus, and only gives pointer-events to a submenu whose parent li is in the hover state.

This only solves part of the problem, though. The other problem is that you have whitespace between your main nav and submenus. When the mouse passes through this whitespace, the parent li loses its hover state. To fix this, I got rid of that whitespace.

I changed the left property for .has_children ul and li:hover > ul.extend from 211px to 11% (aka the width of the .nav).

Here's a codepen of what I did, hope it helps. If you do need whitespace between the main nav and the submenus, I suggest adding padding-left to the submenus so that you have visual space but in reality the elements are flush with eachother.

Upvotes: 1

Francisco Mar&#227;o
Francisco Mar&#227;o

Reputation: 379

Commenting out transition: 300ms; from .level2 solves the problem.

.level2 {
  text-transform: none;
/*   transition: 300ms; */
}

Upvotes: 0

Related Questions