Mega Menu hover event triggered "accidentally" - javascript

I would like to fix my mega menu that I builded a while ago. To build it i used pure css, coz I dont know JS. I was able to find and solve almost all problems with this menu, even on mobile or tablets, but there is still one annoying problem that I cannot solve alone.
When user hovers over main category in mega menu, lower level is showing, then there is another level of menu, also triggered by hover event. Problem is when user tries to go in most direct and straight line to links placed far on the left or right in the lower level menu. Then sometimes other menus are triggered by hovering over other main categories.
I tried to make main div that triggers hover event bigger, but then layout is very ugly, and menu objects are way to far from each other.
I could make click as event, but then i loose main links. Also, I read that I would have to write a lot of custom CSS for all main links, that will use "checkbox". Not the most elegant way. I wrote way to much CSS anyway, there's already a pure "DIV and CSS-inception" in my code :/
Ideal solution would be to use some kind of delay, that would trigger lower levels after lets say 500ms. I tried that with CSS, but its still closing one to immidietlly open other that user just triggered by accident.
Maybe better would be to add some kind of rule in JS that menu will be triggered only if user will hover over link for example for 500ms.? Then if user would go straight to items placed in opposite directions in lower levels, he would not trigger other menus coz "rule 500ms." was not fulfilled. Is it even possible?
Link to the website
I attach my "inception" code just for you guys to laugh :)
/* Main Menu - hover underline */
.menu-item-style {
transition: 0.3s;
}
.mega-menu-main-item:hover .menu-item-style{
color: #8f214b;
text-decoration-line: underline;
text-decoration-thickness: 2px;
text-underline-offset: 40%;
transform: scale(1.15);
}
/* Main Menu */
.sub-mega-menu-container1 {
opacity: 0 !important;
pointer-events: none;
width: 99.2vw;
left: -19.65vw;
}
#media (max-width: 1366px){
.sub-mega-menu-container1{
width: 100vw;
left: -21.1vw !important;
}}
.mega-menu-parent-item1:hover .sub-mega-menu-container1 {
opacity: 1 !important;
pointer-events: auto;
top: 100%;
}
.sub-mega-menu-container2 {
opacity: 0;
pointer-events: none;
width: 99.2vw;
left: -28vw;
}
#media (max-width: 1366px){
.sub-mega-menu-container2{
width: 100vw;
left: -30.75vw;
}}
.mega-menu-parent-item2:hover .sub-mega-menu-container2 {
opacity: 1;
pointer-events: auto;
top: 100%;
}
.sub-mega-menu-container3 {
opacity: 0;
pointer-events: none;
width: 99.2vw;
left: -36.37vw;
}
#media (max-width: 1366px){
.sub-mega-menu-container3{
width: 100vw;
left: -40.35vw;
}}
.mega-menu-parent-item3:hover .sub-mega-menu-container3 {
opacity: 1;
pointer-events: auto;
top: 100%;
}
.sub-mega-menu-container4 {
opacity: 0;
pointer-events: none;
width: 99.2vw;
left: -44.70vw;
}
#media (max-width: 1366px){
.sub-mega-menu-container4{
width: 100vw;
left: -50.05vw;
}}
.mega-menu-parent-item4:hover .sub-mega-menu-container4 {
opacity: 1;
pointer-events: auto;
top: 100%;
}
.sub-mega-menu-container5 {
opacity: 0;
pointer-events: none;
width: 99.2vw;
left: -53.05vw;
}
#media (max-width: 1366px){
.sub-mega-menu-container5{
width: 100vw;
left: -59.6vw;
}}
.mega-menu-parent-item5:hover .sub-mega-menu-container5 {
opacity: 1;
pointer-events: auto;
top: 100%;
}
/* Sub Menu - Products */
.big-sub-menu-container1 {
opacity: 0;
pointer-events: none;
left: 0;
text-shadow: none !important;
}
.big-menu-parent-item1:hover .big-sub-menu-container1 {
opacity: 1;
pointer-events: auto;
top: 100%;
}
.big-sub-menu-container2 {
opacity: 0;
pointer-events: none;
left: -100%;
text-shadow: none !important;
}
.big-menu-parent-item2:hover .big-sub-menu-container2 {
opacity: 1;
pointer-events: auto;
top: 100%;
}
.big-sub-menu-container3 {
opacity: 0;
pointer-events: none;
left: -200%;
text-shadow: none !important;
}
.big-menu-parent-item3:hover .big-sub-menu-container3 {
opacity: 1;
pointer-events: auto;
top: 100%;
}
I appreciate all the help.

Related

Text appear/disappear on top of image with button toggle

In mobile, I'm trying to create a toggle that appears on top of an image, that when tapped on, makes text appear on top of the image too.
I basically want to recreate how The Guardian newspaper handles the little (i) icon in the bottom right corner on mobile.
And on desktop, the the text is there by default under the image and the (i) icon is gone.
So far I've managed to find a similar solution elsewhere online but it's not quite working right as I need it to.
function toggleText() {
var text = document.getElementById("demo");
if (text.style.display === "none") {
text.style.display = "block";
} else {
text.style.display = "none";
}
}
#blog {
width: 100%;
}
#blog figure {
position: relative;
}
#blog figure figcaption {
display: none;
position: absolute;
bottom: 0;
left: 0;
box-sizing: border-box;
width: 100%;
color: black;
text-align: left;
background: rgba(0, 0, 0, 0.5);
}
#blog figure button {
position: absolute;
bottom: 0;
right: 0;
color: black;
border: 5px solid black;
}
<div id="blog">
<figure>
<img src="https://cdn2.hubspot.net/hubfs/4635813/marble-around-the-world.jpg" alt="A photo of a slab of marble for example">
<figcaption id="demo" style='display: none'>A photo of a slab of marble for example</figcaption>
<button type='button' onclick="toggleText()">(i)</button>
</figure>
</div>
Don't use IDs. Your code should be reusable!
Don't use inline JS on* handlers, use Element.addEventListener() instead
Don't use inline style attributes.
Don't use el.style.display === "something" to check for display styles. Use Element.classList.toggle() instead
This straightforward example uses JavaScript to simply toggle a className "is-active" on the button's parent, the figure Element.
Everything else (icon symbol change, caption animation etc...) is handled purely by CSS:
document.querySelectorAll("figure button").forEach(EL_btn => {
EL_btn.addEventListener("click", () => {
EL_btn.closest("figure").classList.toggle("is-active");
});
});
/* QuickReset */ * {margin: 0; box-sizing: border-box;}
img {
max-width: 100%; /* Never extend images more than available */
}
figure {
position: relative;
overflow: hidden; /* overflow hidden to allow figcaption hide bottom */
}
figure img {
display: block; /* prevent "bottom space" caused by inline elements */
}
figure figcaption {
position: absolute;
width: 100%;
bottom: 0;
padding: 1rem;
padding-right: 4rem; /* Prevent text going under the button icon */
color: #fff;
background: rgba(0, 0, 0, 0.5);
transform: translateY(100%); /* Move down, out of view */
transition: transform 0.3s; /* Add some transition animation */
}
figure.is-active figcaption {
transform: translateY(0%); /* Move into view */
}
figure button {
position: absolute;
width: 2rem;
height: 2rem;
bottom: 0.5rem;
right: 0.5rem;
border-radius: 50%;
color: #fff;
background: rgba(0, 0, 0, 0.5);
border: 0;
cursor: pointer;
}
figure button::before {
content: "\2139"; /* i icon */
}
figure.is-active button::before {
content: "\2A09"; /* x icon */
}
<figure>
<img src="https://cdn2.hubspot.net/hubfs/4635813/marble-around-the-world.jpg" alt="A photo of a slab of marble for example">
<figcaption>A photo of a slab of marble for example</figcaption>
<button type="button"></button>
</figure>
The above will work for any number of such elements on your website without the need to add any more CSS or JS.
I see a couple things that could mess this up, one is the fact that there is nothing to make your image adjust to your mobile screen, more-over there is also margin that is there by default, so I suggest these changes to the CSS:
First I'd set box-sizing to border-box and margin to 0, this should be a regular practice by the way.
*{
box-sizing: border-box;
margin: 0;
}
Then select the image and make it adjust to your page as such
#blog figure img{
height: auto;
width:100%;
}
Finally, for some styling you can add some padding to your blog div to make the image slightly smaller on your screen
#blog {
width: 100%;
padding: 35px;
}
This is the Fiddle for it.

Stop div overlapping another from size increase

My engagement-filtercontainer div used to sit directly above my engagement-graphcontainer unless it was expanded via button click, in which case it drops down into the graphcontainer overlapping. Now the engagement-filtercontainer has grown in size because of additional content and it overlaps my graph container which contained my svg. I need it to dynamically not do this even if my filter increases in size.
I have some divs that are contained in this order:
<div class="Engagement-Container">
<div class="Engagement-Body">
<div class="Engagement-Graph" id="graph">
<div class="Engagement-FilterContainer"
</div>
<div class="Engagement-GraphContainer"
<svg
class="Engagement-GraphSVG"
xmlns="http://www.w3.org/2000/svg"
version="1.1 ">
</svg>
</div>
</div>
</div>
</div>
Notice that the engagement-filtercontainer and graphcontainer are both within the engagement-graph div, and that my svg is contained within the graphcontainer.
In the below image you can see that the filter now with more content expands into the area (I have hidden with css thats why im showing it in dev mode, ive tried various methods to work around this but I think i need a definitive solution.
The CSS:
engagement-graph(parent div)
.Engagement-Graph {
position: absolute;
width: 100%;
height: 100%;
font-size: 100%;
vertical-align: baseline;
overflow: hidden;
#include tablet() {
width: 65%;
}
}
Engagement-graph-container (contains the svg graph that i want to protect from unwanted overlap)
.Engagement-GraphContainer {
position: relative;
width: 100%;
height: calc(100% - 56px);
top: 0;
background-color: $gray-bg-color;
transition: height $filter-slide-duration, top $filter-slide-duration;
#include tablet() {
background-color: white;
height: 100%;
}
svg {
width: 100%;
height: 100%;
}
&--WithFilter {
height: calc(100% - 480px) !important;
top: 480px !important;
#include landscape {
height: calc(100% - 436px) !important;
top: 436px !important;
}
}
}
Filter-container (that is overlapping)
.Engagement-FilterContainer {
overflow: overlay;
display: table;
position: absolute;
width: 100%;
z-index: 10;
transition: transform $filter-slide-duration;
transform: translateY(-486px);
visibility: hidden;
&--Visible {
transform: translateY(0) !important;
}
#include landscape {
transform: translateY(-436px);
}
}
I wish for the filter to work as usual so when its expanded it will appear into the screen but when it is not, I don't want it encroaching upon the graph, no matter how large it gets. When the filter was smaller it was fine it never came into the screen, so it must not be dynamic in how it is sized.
Thank you if you can help.

What's causing the paint event in this CSS animation?

I'm building an animated menu based off of Smooth as Butter: Achieving 60 FPS Animations with CSS3.
The canonical demo which I'm comparing my code against is: http://codepen.io/Onyros/pen/jAJxkW
This is my demo code:
var navLayer = document.querySelector('.nav-layer'),
open = document.querySelector('.open'),
close = document.querySelector('.close');
function toggleNav() {
navLayer.classList.add('nav-layer__animating');
if (navLayer.classList.contains('nav-layer__visible')) {
navLayer.classList.remove('nav-layer__visible');
} else {
navLayer.classList.add('nav-layer__visible');
}
}
open.addEventListener('click', toggleNav, false);
close.addEventListener('click', toggleNav, false);
navLayer.addEventListener('transitionend', function() {
navLayer.classList.remove('nav-layer__animating');
}, false);
.nav-layer {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
z-index: 2;
pointer-events: none;
}
.nav-layer__visible {
pointer-events: auto;
}
.header {
position: fixed;
top: 0;
left: 0;
background-color: beige;
height: 10vh;
width: 100vw;
z-index: 1;
}
.nav {
position: relative;
height: 100vh;
width: 90vw;
background-color: aquamarine;
z-index: 3;
transform: translateX(-91vw);
will-change: transform;
}
.nav-layer__animating .nav {
transition: all 300ms ease-in;
}
.nav-layer__visible.nav-layer__animating .nav {
transition: all 300ms ease-out;
}
.nav-layer__visible .nav {
transform: none;
}
<div class="nav-layer">
<nav class="nav">
<button class="close">Close</button>
</nav>
</div>
<header class="header"><button class="open">Menu</button></header>
<article>
<p>O hai</p>
</article>
When I run the canonical demo with paint flashing enabled in Chrome DevTools, I don't see any paint events.
When I run my demo, I see a flash of paint when I close the menu.
The event log in DevTools shows that there was a paint on #document and another on nav.nav.
The answer I'm looking for here is: find the CSS property in the canonical demo which is preventing this flash of paint. Or, maybe the difference is in how I've structured my HTML. I think the JS is equivalent, so it's unlikely to be there.
Please provide your methodology, too!

Moving the whole page to left and then right

i am looking for this kind of template . Moving the page to left and then page to right. Can anyone tell me how can i make this or is there any javascript example similar to this.
Create two <div>s, put them next to each other, make them take up the whole window, and change them as needed.
HTML:
<div class="left">left</div>
<div class="right">right</div>
CSS:
body {
margin: 0;
}
.left {
background-color: green;
bottom: 0;
left: 0;
position: fixed;
top: 0;
transition: width 1s;
width: 0;
}
.left.active {
width: 200px;
}
.right {
background-color: red;
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
transition: left 1s;
}
.right.active {
left: 200px;
}
JS (width jQuery):
$('.right').on('click', function() {
$('.left').toggleClass('active');
$('.right').toggleClass('active');
});
And here's a fiddle.
Using .toggle(effect,options,duration) method to moving the page to left to right.
// Set the effect type
var effect = 'slide';
// Set the options for the effect type chosen
var options = { direction: 'right' };
// Set the duration (default: 400 milliseconds)
var duration = 700;
$('#Id').toggle(effect, options, duration);
Taken via this link
If you want it to animate smooth on all devices you should use css transitions and transforms. Hiding and showing would be as basic as toggling a class then.
The example in jsfiddle
<style media="screen">
.wrapper {
width: 100%;
overflow: hidden;
}
.menu {
height: 100vh;
width: 100px;
background: #ABC;
color: white;
position: absolute;
left:0;
transition: transform 0.3s;
transform: translateX(-100px);
}
.content {
transition: transform 0.3s;
}
.active .menu {
transform: translateX(0);
}
.active .content {
transform: translateX(100px);
}
</style>
<button class="toggle">Toggle</button>
<div class="wrapper">
<div class="menu">
My menu
</div>
<div class="content">
My content
</div>
</div>
<script type="text/javascript">
document.querySelector('.toggle').addEventListener('click', function(event) {
event.preventDefault();
document.querySelector('.wrapper').classList.toggle("active");
});
</script>
NB! Supported from IE10. IE 9 will support without the animation and you probably should add the needed -ms-, -webkit-, -moz-, etc prefixes to support the older browsers if needed for transition and transform properties.
Also I advise not animating body or html with this method and put the content of page in the wrapper (in .content in the examples case). Moving body and html directly may lead to unpleasant surprises later.

Sub navigation disappears when I click on it in responsive view

I've created a sub navigation and when I click on it (using my jquery code), it scrolls down and i can hover over the links but they dont appear at all.
I tried looking into what could be causing the problem such as the color or background but I can't find out where i went wrong. I was messing around with the visibility and display of the element but I don't think theres a problem there, although I'm unsure.
To isolate where the problem of the code may lie, here is the sub navigation code:
ul {
padding: 0;
position: absolute;
top: 33px; right: 16px;
width: 150px;
display: none;
opacity: 0;
visibility: hidden;
#include transition('all .2s ease-in-out');
li {
display: block;
width: 100%;
a {
width: 100%;
display: block;
background: lighten(#27344C, 10);
color: #FFF;
padding: 0;
padding-right: 14px;
#include transition('all .2s ease-in-out');
}
}
li:hover {
a { background: lighten(#27344C, 5); }
}
}
I think the problem may actually be the javascript on this line when i edit the css styles:
$('#profileToggle').on('click', function() {
$('#profileList').slideToggle().css({'visibility': 'visible', 'display': 'block'});
$(this).addClass('active');
});
Here is the JSFiddle: http://jsfiddle.net/8xat4v97/1/
(starts line 112 of the scss code)
As with what #BillyNate had said,
the opacity is set to 0 for some reason in my sub navigations.
Removing this line fixed the issue! Thanks :)

Categories