My mega menu nav has a hovering issue. It activates when hovering over invisible child list items (mousing over from bottom to top, you'll notice the issue on this codepen).
This is the block of CSS that's triggering the hover:
.nav:hover > li > .subnav-block {
opacity: 1;
visibility: visible;
overflow: visible;
}
I'm thinking a JavaScript solution would help out but trying to find CSS fix for this first.
Your sub-navigation menu is taking up space, even though it is not visible. That is why you can see it whenever you are hovering above it. Adding height:0 to your .subnav-block and then setting it back to auto when hovering, should do the trick. Your css should look something like the one below.
.subnav-block {
position: static;
display: block;
width: 100% !important;
top: 54px;
left: 0;
height: 0;
overflow: hidden;
background: gray;
-webkit-transition: all 0.3s ease 0.15s;
-moz-transition: all 0.3s ease 0.15s;
-o-transition: all 0.3s ease 0.15s;
-ms-transition: all 0.3s ease 0.15s;
transition: all 0.3s ease 0.15s;
}
.nav:hover > li > .subnav-block {
height: auto;
visibility: visible;
overflow: visible;
}
UPDATE
If you want to add paddings to your sub-navigation menu, setting the height to 0 won't suffice, and you would need to change both the height and the padding when hovering. There is another way, which Hadi77 mentioned, which is setting the default display to none and then change it to block. Just like the example below.
.subnav-block {
position: static;
width: 100% !important;
top: 54px;
left: 0;
display: none;
background: gray;
-webkit-transition: all 0.3s ease 0.15s;
-moz-transition: all 0.3s ease 0.15s;
-o-transition: all 0.3s ease 0.15s;
-ms-transition: all 0.3s ease 0.15s;
transition: all 0.3s ease 0.15s;
}
.nav:hover > li > .subnav-block {
display: block;
}
UPDATE 2
Since display won't let us use transitions, the other workaround would be using a bit of JS. Since it is not much code, it is solid way to achieve this. We would need to remove the CSS hover in this.
JS
const nav = document.querySelectorAll('.nav > li');
nav.forEach(elem => {
elem.addEventListener('mouseenter', () => {
const subnav = document.querySelectorAll('.subnav-block');
subnav.forEach(sub => {
sub.classList.add('display-block');
setTimeout( () => {
sub.style.opacity = 1;
sub.style.height = 'auto';
}, 100);
});
});
elem.addEventListener('mouseleave', () => {
const subnav = document.querySelectorAll('.subnav-block');
subnav.forEach(sub => {
sub.classList.remove('display-block');
sub.style.opacity = 0;
});
});
});
CSS
.subnav-block {
position: static;
width: 100% !important;
top: 54px;
left: 0;
display: none;
opacity: 0;
height: 0;
background: gray;
-webkit-transition: all 0.3s ease 0.15s;
-moz-transition: all 0.3s ease 0.15s;
-o-transition: all 0.3s ease 0.15s;
-ms-transition: all 0.3s ease 0.15s;
transition: all 0.3s ease 0.15s;
}
.display-block {
display: block;
}
Setting visibility to hidden, is somewhat like making it transparent: The element takes space as it should (display is set to block).
Using display property is what you want. Set it to none when you want the element to be "not displayed" and set it to block to "display it".
Also if you don't want all menus to drop-down together, move the :hover pseudo-selector in .nav:hover > li > .subnav-block to li, so it would become .nav > li:hover > .subnav-block.
Related
I would like to use headroom.js on my site to be able to hide the header as I scroll down and have it reappear as I scroll up. I am using WordPress.
I tried putting the js file in the theme folder and calling it with functions.php, but it didn't seem to work, so instead I am using this plugin: https://twd.wordpress.org/plugins/headroomjs/.
I have the following in the additional CSS:
.headroom {
transition: transform 200ms linear;
}
.headroom--top .x-navbar {
background-color: transparent;
border-bottom: none;
box-shadow: none;
}
.sub-menu ul li{
color: #ddd !important;
}
.headroom--top .x-navbar a{
color: #fff !important;
}
.headroom--top .x-navbar .desktop .sub-menu a{
color: black !important;
}
.headroom--not-top .x-navbar {
background-color: #fff;
}
.headroom {
transition: transform 200ms linear;
}
.headroom--pinned {
transform: translateY(0%);
}
.headroom--unpinned {
transform: translateY(-100%);
webkit-transition: all .3s ease-in-out;
-moz-transition: all .3s ease-in-out;
-o-transition: all .3s ease-in-out;
transition: all .3s ease-in-out;
}
.headroom {
position: fixed;
z-index: 12;
right: 0;
left: 0;
top: 0;
webkit-transition: all .3s ease-in-out;
-moz-transition: all .3s ease-in-out;
-o-transition: all .3s ease-in-out;
transition: all .3s ease-in-out;
}
.masthead {
height:0px;
}
The header color is changing as I scroll down, but it is still fixed, and does not disappear on scroll down. What am I doing wrong?
Thanks!
You either need to apply the classes to your templates or use the plugin.
See documentation to correct your install: http://wicky.nillia.ms/headroom.js/
Specifically add an id or data element to your :
<!-- selects $("[data-headroom]") -->
or
<header id="header">
And enqueue the js to functions php, it should call itself; if not, you need to add its document call in the footer template of your theme.
The WordPress plugin hasn't been updated in 3 years so I don't recommend it but you could give it a look and compare it with your install to fix it..
I have a left menu that slides in when the user clicks on the hamburger. Behind it is an overlay with the following SCSS:
.overlay {
background-color: $glb-nav-80-opacity-white;
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 200;
cursor: pointer;
}
.left-menu {
background: $glb-nav-dark-blue;
position: fixed;
overflow-x: hidden;
overflow-y: auto;
margin: 0;
padding: 0;
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
transition: all 0.3s ease;
a:hover {
color: $glb-nav-white;
}
}
When people click on the hamburger menu, the overlay shows up abruptly. I need it to fade in. How can I do that using CSS?
Here's the HTML:
<div class="overlay"></div>
<div class="left-menu"></div>
When the user opens the page the left-menu has a left position of -284px. Then when people click on the hamburger icon, I add a class to the div that sets its left position to 0.
Instead of adding a class, you can set the opacity using jQuery's .CSS
For example:
$(".overlay").css({opacity:50});
To reset it, use
$(".overlay").removeAttr("style");
Use CSS transitions as you did for the menu:
.overlay {
background-color: $glb-nav-80-opacity-white;
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 200;
cursor: pointer;
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
transition: all 0.3s ease;
}
Use css transitions as you did with the menu, ie:
.overlay {
// other css
-webkit-transition: opacity 500ms ease;
-moz-transition: opacity 500ms ease;
-o-transition: opacity 500ms ease;
transition: opacity 500ms ease;
}
Or, if using SASS: #include transition(opacity 500ms ease);
Note, you can set the timing and style to be what you like, more here: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions
just add transition to the overlayed div
div {
/* -transition: 2 seconds- */
-webkit-transition: width 2s; /* For Safari 3.1 to 6.0 */
transition: 2s;
}
div:hover {
height: 200px;
background: red;
}
<div>transition on hover</div>
So I'm trying to do a pop-out menu, and I have a bit of an issue.
I've applied:
.menu-side, .menu {
-webkit-transition: left 0.2s ease;
-moz-transition: left 0.2s ease;
transition: left 0.2s ease;
}
.menu is set to the body, and menu-side to the pop-out menu. The left of both the menu and body is changed when the pop-out menu is loaded. But for some reason it isn't easing correctly?
The problem is that the initial value of left property is auto.
Therefore, the browser doesn't know how to do the transition from auto to 180px.
To fix it, you must set it to 0 initially:
.menu {
left: 0px;
transition: left 0.2s ease;
}
.menu-open {
left: 180px;
}
.menu {
left: 0px;
transition: left 0.2s ease;
background: red;
position: relative;
height: 200px;
}
:checked ~ .menu { /* .menu-open */
left: 180px;
}
<input id="toggler" type="checkbox" />
<label for="toggler">Toggle</label>
<div class="menu"></div>
Personally I would never animate the body element itself. You should always use a wrapper, the body has some special properties and doesn't always act you would expect a div to act. However, If you manually set left: 0 on the body the transition will work.
body {
left: 0;
}
For the last 3 hours I've been trying to make a simple adjustment to Bootstrap 3's carousel transitions.
I've tried changing the slide speed where this is the only thing that seems to have any effect:
.carousel-inner .item {
-webkit-transition-duration: 2s;
-moz-transition-duration: 2s;
-o-transition-duration: 2s;
transition-duration: 2s;
}
but it hides the 'leaving' content too soon, and I have no clue what property to modify to fix that.
I've also tried changing it to a fade transition with
.carousel-fade .item {
opacity: 0;
-webkit-transition: opacity 2s ease-in-out;
-moz-transition: opacity 2s ease-in-out;
-ms-transition: opacity 2s ease-in-out;
-o-transition: opacity 2s ease-in-out;
transition: opacity 2s ease-in-out;
left: 0 !important;
}
.carousel-fade .active {
opacity: 1 !important;
}
.carousel-fade .left {
opacity: 0 !important;
-webkit-transition: opacity 0.5s ease-in-out !important;
-moz-transition: opacity 0.5s ease-in-out !important;
-ms-transition: opacity 0.5s ease-in-out !important;
-o-transition: opacity 0.5s ease-in-out !important;
transition: opacity 0.5s ease-in-out !important;
}
.carousel-fade .carousel-control {
opacity: 1 !important;
}
And just about every other snippet to do so that I've come across, but every single one always first removed the leaving content, showing a featureless background, before fading in the next. What am I missing? All I need is some plain CSS to override the existing transition details, but I don't know where to look any more.
I think different aspects of bootstrap's carousel plugin give the effects you mention.
Active items have display: block while not active items have display: none
This can be solved by giving all items display: block and then setting the position to absolute with top: 0 and left: 0, resulting in the items overlapping. Setting opacity: 0; makes them invisible by default.
Less:
.carousel-inner > .item {
opacity: 0;
top: 0;
left: 0;
width: 100%;
display: block;
position: absolute;
}
One problem of the position: absolute is that the container does not get a height. The preceding can be solved by setting the position of the first item to relative (it is add the right position already). In Less code, it is as follows:
.carousel-inner > .item {
:first-of-type {
position:relative;
}
}
Bootstrap uses translate3ds to change the position of the item in the space. You won't need these transformations, so reset them. Leveraging Less, code shown below:
.carousel-inner > .item {
transform: translate3d(0,0,0) !important;
}
The CSS transitions are triggered by adding and removing CSS classes with jQuery. The time between these class changes has been hardcoded in the carousel plugin code (Carousel.TRANSITION_DURATION = 600). So, after 600 ms, one item becomes active (having the .active class). That is the reason for the unexpected behavior if your css transition-duration is greater than 0.6 seconds.
The CSS class changes are as follows:
The active item has class .active -> .active.left -> none
The next item has no class -> .next.left -> .active
So the .active.left and .next.left are important (or .prev.right and .active.right when you slide backwards).
Because all images are already stacked, you can use the z-index property to make an image in the stack visible, because we can change the opacity at the same time. You can use the following Less code to fade in the next slide:
.carousel-inner {
> .next.left {
transition: opacity 0.6s ease-in-out;
opacity: 1;
z-index:2;
}
> .active.left {
z-index:1;
}
}
To make sure that the controls are visible as well, use:
.carousel-control {
z-index:4;
}
Putting all together, see the results in this demo, which uses the following Less code:
.carousel-inner {
> .item {
opacity: 0;
top: 0;
left: 0;
width: 100%;
display: block;
position: absolute;
z-index:0;
transition: none;
transform: translate3d(0,0,0) !important;
&:first-of-type {
position:relative;
}
}
> .active {
opacity: 1;
z-index:3;
}
> .next.left,
> .prev.right {
transition: opacity 0.6s ease-in-out;
opacity: 1;
left: 0;
z-index:2;
}
> .active.left,
> .active.right {
z-index:1;
}
}
.carousel-control {
z-index:4;
}
The above code can be compiled with the Less autoprefixer plugin plugin into CSS with the following command:
lessc --autoprefix="Android 2.3,Android >= 4,Chrome >= 20,Firefox >= 24,Explorer >= 8,iOS >= 6,Opera >= 12,Safari >= 6' code.less
which outputs:
.carousel-inner > .item {
opacity: 0;
top: 0;
left: 0;
width: 100%;
display: block;
position: absolute;
z-index: 0;
-webkit-transition: none;
-o-transition: none;
transition: none;
-webkit-transform: translate3d(0, 0, 0) !important;
transform: translate3d(0, 0, 0) !important;
}
.carousel-inner > .item:first-of-type {
position: relative;
}
.carousel-inner > .active {
opacity: 1;
z-index: 3;
}
.carousel-inner > .next.left,
.carousel-inner > .prev.right {
-webkit-transition: opacity 0.6s ease-in-out;
-o-transition: opacity 0.6s ease-in-out;
transition: opacity 0.6s ease-in-out;
opacity: 1;
left: 0;
z-index: 2;
}
.carousel-inner > .active.left,
.carousel-inner > .active.right {
z-index: 1;
}
.carousel-control {
z-index: 4;
}
I was struggling with this and it was driving me insane - on Bootstrap's Introduction page, if you look under Components, it lists Carousel as one of the components requiring JS. I had to add their CSS stylesheet before all other stylesheets, then their Bootstrap / JS plugin bundle right before the closing body tag. Finally fixed the issue. I've linked them below in order, starting with the Introduction page.
https://getbootstrap.com/docs/5.1/getting-started/introduction/
I dont have any idea how to make it work
Css:
.name
{
width: 270px;
height: 77px;
position: absolute;
top: 0px;
left: 600px;
-webkit-transition: top 0.3s;
-moz-transition: top 0.3s;
-o-transition: top 0.3s;
}
.name:hover
{
top: 10px;
-webkit-transition: top 0.3s;
-moz-transition: top 0.3s;
-o-transition: top 0.3s;
font-size: 24px;
}
.photo
{
width: 270px;
height: 310px;
position: absolute;
top: 77px;
left: 600px;
-webkit-transition: top 0.3s;
-moz-transition: top 0.3s;
-o-transition: top 0.3s;
}
.photo:hover,
{
top: 100px;
-webkit-transition: top 0.3s;
-moz-transition: top 0.3s;
-o-transition: top 0.3s;
font-size: 24px;
}
I want when i hold the mouse over the .name which is an image to activate the .photo hover effect and vice versa, any idea?
/* What you want the thing being hovered over to look like */
.name:hover {
top: 10px;
-webkit-transition: top 0.3s;
-moz-transition: top 0.3s;
-o-transition: top 0.3s;
font-size: 24px;
}
/* What you want the thing being hovered over to look like */
.name:hover ~ * {
/* Some styles */
}
In order for this to work, the items that you want to style need to be siblings of the .name element being hovered over. The ~ is a css sibling selector.
I would make a class like
.photo:hover, .photo.hover {
/* CSS */
}
Then toggle class hover on the photo element.
This woul be a javascript solution, not just CSS.
You can try this:
JS
$('.name').hover(function () {
$('.photo').addClass('hover');
}, function () {
$('.photo').removeClass('hover');
});
$('.photo').hover(function () {
$('.name').addClass('hover');
}, function () {
$('.name').removeClass('hover');
});
CSS
.name:hover, .name.hover
.photo:hover, .photo.hover
demo