This problem is hard to describe in words, but much easier to visualize, so let's begin with a video, where we are trying to reach the submenu of the "Kurser" item:
Definitely not a new problem, it's described almost ten years ago for instance in this article by NNGroup, where they just call it "the diagonal problem". Yet, even here in 2018 with touch devices all over the place, I still come across websites, where this problem occur on mouse-enabled devices like laptops.
So, I was challenging myself to whether I could solve the problem with just CSS, without using JavaScript.
Here's a video demo of my solution:
You can try it on Codepen (use your laptop, not your phone ;):
Demo of my CSS solution to "the diagonal problem"
The problem perhaps isn't entirely gone, but I would argue that it's mitigated.
The key idea in the solution is to have two invisible triangle-shaped "hover-help" areas on either side of the top-level navigation link temporarily covering parts of the neighbouring links. These hover helps are active, when a top-level link is hovered and can work as transitory "bridges" to the submenus. This in turn prevents accidental, unintended activation of the wrong submenus.
The CSS trick here is to use ::before
and ::after
pseudo elements to create the triangles:
.hover-help:hover::before,
.hover-help:hover::after {
content: "";
position: absolute;
z-index: 1000;
bottom: 0;
height: 80%;
...
}
To avoid the triangles blocking the user's access to other top-level navigation links, a time-out is applied with CSS animation
to remove the triangle after a certain period, e.g. around one second. In the demo I have used CSS clip-path
to "shape" the triangles:
@keyframes subnavHoverHelp {
0% {
width: 100%;
}
99% {
width: 100%;
}
100% {
width: 0;
}
}
.hover-help:hover::before,
.hover-help:hover::after {
...
animation: subnavHoverHelp 1.2s;
}
.hover-help:hover::before {
left: -100%;
clip-path: polygon(100% 0, 0% 100%, 100% 100%); /* creating left-hand triangle shape */
}
.hover-help:hover::after {
right: -100%;
clip-path: polygon(0 0, 0% 100%, 100% 100%); /* creating right-hand triangle shape */
}
A production version of this solution would need some further tweaking and fine-tuning to get the timing and shape of the triangle just right in relation to the actual content.