I am trying to do some transition/transform effect as you can see on this site, where the navigation switches halfway the page and kinda transfers into the other one.
I've created a jsfiddle, with two navs, the .mobilenav is the one that should be changed upon scrolling, and the .desktopnav is the one which slides out as you can see. But now I was wondering how I can make recreate that transition. (The changing nav is done in JQuery with a if, else statement and ($(window).scrollTop() > 500)
I've simulated that nav pretty close in my fiddle, with some simplifications of course: https://jsfiddle.net/pttsky/0anpeLj0/
There are couple of key concepts:
There is actually only one nav to which we add .full class to indicate state change.
There is a container of nav, actual nav and its child li elements
Each of above listed has own CSS transitions and animations that change their positioning, opacity and backgrounds.
Talking deeper on changing nav from collapsed to full-width like on that site.
The container block slightly pulling upwards the nav. It becomes non-transparent, which gives an illusion that border-radius disappeared from the nav, but actually if we'd animated border-radius, that would be ugly.
.nav-container {
display: block;
position: fixed;
width: 100%;
z-index: 2;
top: 0;
padding: 25px 25px 15px;
-webkit-transition: .8s;
transition: .8s;
}
.full {
background: #fff;
padding-top: 15px;
}
The child elements, except MENU link, have max-width: 0 by default. When menu is hovered, or when it is in full-width state, elements have max-width: 200px, and MENU has reversed behaviour:
.nav-main .item {
display: block;
float: left;
max-width: 0;
opacity: 0;
-webkit-transition: .8s;
transition: .8s;
/* limit width */
overflow: hidden;
line-height: 3em;
}
.nav-main .toggle {
max-width: 200px;
opacity: 1;
-webkit-transition: .6s .4s;
transition: .6s .4s;
}
.full .nav-main .item {
max-width: 200px;
opacity: 1;
}
.full .nav-main .item + .item {
margin-left: 12vw;
}
.full .nav-main .toggle {
max-width: 0;
opacity: 0;
-webkit-transition: .1s;
transition: .1s;
}
When changing state, all items of nav seems like fade out then fade in. I've added the appropriate animation to the whole nav:
/* nav full-width */
#keyframes blink {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
.full .nav-main {
animation: blink .8s;
}
Alternatively to Device's answer, you could also use css transitions on one nav to get the same effect, instead of using two navs.
By switching the class on the nav you can trigger the transition and place the navigation in its correct place.
JS:
$(document).ready(function() {
var nav = $('.desktopnav');
$(window).scroll(function() {
var scrolltop = $(window).scrollTop();
if (scrolltop > 500 && !nav.hasClass('scrolled')) {
nav.addClass('scrolled');
}
else if (scrolltop <= 500 && nav.hasClass('scrolled')) {
nav.removeClass('scrolled');
}
});
});
CSS:
.desktopnav {
/* ... snipped, unchanged ... */
transition: all 0.2s ease-out;
}
.desktopnav>ul {
transition: all 0.2s ease-out;
}
.desktopnav>ul>.dropdown {
/* ... snipped, unchanged ... */
transition: all 0.2s ease-out;
}
/* ... snipped unchanged styles for the unscrolled menu ... */
.desktopnav.scrolled {
top: 0px;
right: auto;
left: 0px;
width: 100%;
}
.desktopnav.scrolled>ul {
margin-top:0px;
background: #fff;
}
.desktopnav.scrolled>ul>.dropdown {
border-radius: 0px;
}
.desktopnav.scrolled>ul>.dropdown .dropdown-content {
max-width: 1000px;
float: none;
display: inline-block;
vertical-align: middle;
margin-left: 19px;
}
https://jsfiddle.net/q80k0y7v/1/
Related
This question already has answers here:
Maintaining the final state at end of a CSS animation
(5 answers)
Closed 5 months ago.
I have a page with a lot of interactivity going on. Clicking a button here changes the text and image over there... that kind of stuff. Just about everything is controlled by click handlers adding or removing CSS classNames to show or hide the appropriate content. Almost all of the animation is achieved with CSS transitions. Pretty straight forward.
But I have one element that requires a keyframe animation. Its default state is to be hidden until it's time for it to enter the UI... at which point it needs to have this CSS keyframe animation applied and stay in the last state the animation had it in.
For the sake of this example, let's just say that when Block A becomes visible (by clicking the button), the element in question, Block A1, needs to fade in (remember in my actual use case, the animation is more complicated and can't be achieved using transitions... it requires a keyframe animation) and then remain with the properties it had in the last frame of the animation: in this case opacity: 1 after the animation runs.
Right now, the only way I'm able to do this is to use javascript to set the opacity after the animation runs. This works but I can see it getting really messy/complicated when elements now have a style attribute overriding the styles set in the CSS rulesets. You can see this start to happen when you click the button again to hide the block and then AGAIN to show it... Block A1 is still set to opacity: 1 so the animation ha no effect after the 1st time around.
Is there a better way to do this?
const $btn = document.querySelector('button');
const $block = document.querySelector('.block-a');
const $blocka1 = document.querySelector('.block-a-1');
$btn.addEventListener('click', function() {
$block.classList.toggle("is-visible")
})
$blocka1.addEventListener('animationend', function() {
console.log('done');
this.style.opacity = 1;
})
body {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
button {
font-size: 32px;
margin-bottom: 24px;
cursor: pointer;
}
.block-a {
width: 25vw;
height: 50vh;
background-color: red;
padding: 20px;
color: #fff;
transform: translateY(150%);
transition: all .25s linear;
}
.block-a.is-visible {
transform: translateY(0);
transition: all .1s ease-in;
}
.block-a-1 {
font-size: 32px;
font-weight: bold;
color: white;
background-color: blue;
padding: 10px;
opacity: 0;
}
.block-a.is-visible .block-a-1 {
animation: fadeIn 2s linear 2s;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<button>Do Block 1</button>
<div class="block-a">
<span class="block-a-1">Block A-1</span>
<h1>Block A</h1>
</div>
You can maintain the last animation frame using:
animation-fill-mode:forwards;
https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode
const $btn = document.querySelector('button');
const $block = document.querySelector('.block-a');
$btn.addEventListener('click', function() {
$block.classList.toggle("is-visible")
})
body {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
button {
font-size: 32px;
margin-bottom: 24px;
cursor: pointer;
}
.block-a {
width: 25vw;
height: 50vh;
background-color: red;
padding: 20px;
color: #fff;
transform: translateY(150%);
transition: all .25s linear;
}
.block-a.is-visible {
transform: translateY(0);
transition: all .1s ease-in;
}
.block-a-1 {
font-size: 32px;
font-weight: bold;
color: white;
background-color: blue;
padding: 10px;
opacity: 0;
}
.block-a.is-visible .block-a-1 {
animation: fadeIn 2s linear 2s;
animation-fill-mode:forwards;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<button>Do Block 1</button>
<div class="block-a">
<span class="block-a-1">Block A-1</span>
<h1>Block A</h1>
</div>
Set the animation property animation-fill-mode to forwards or add it to animation like animation: fadeIn 2s linear 2s forwards;
I am trying to to create a fixed header for one of my projects using react. The background color of the Header should be transparent when the web page is opened but on scrolling it down, it should change its color to black. I have managed to make the transition smooth while changing the background color from transparent to black (when I scroll down) however, I am unable to make the transition smooth when the background color changes from black to transparent (when I scroll back up).
Here is my Code :
import React from 'react';
import Navbar from '../Navbar/Navbar.js';
import logo from '../images/nsut_logo.png';
class Header extends React.Component {
constructor() {
super();
this.state = {
header: false
};
this.handleScroll = this.handleScroll.bind(this);
}
componentDidMount(){
window.addEventListener("scroll", this.handleScroll);
}
handleScroll(event) {
if (window.pageYOffset > 0) {
this.setState({ header: true });
}
else{
this.setState({ header: false });
}
}
render() {
return (
<header onScroll={this.handleScroll}>
<div className={this.state.header ? "Header-Site-Title-Active" : "Header-Site-Title"}>
<img className = "Header-logo" src={logo} />
<div className="Department-Name">
<h1 >
<b>Department Of Computer Science And Engineering</b>
<br/>
</h1>
<h3>
Netaji Subhas University of Technology
</h3>
</div>
<Navbar />
</div>
</header>
);
}
}
export default Header;
Here is my CSS File:
header{
top: 0;
padding-bottom: 1%;
position: fixed;
z-index: 5;
height: 17vh;
}
#keyframes bgChangeDown {
0% {background-color: none;}
100% {background-color: black;}
}
#keyframes bgChangeUp {
0% {background-color: inherit;}
100% {background-color: none;}
}
.Handle-Site-Title {
height: 100px;
width: 100vw;
top: 0;
animation-name: bgChangeUp;
animation-duration: 2s;
animation-iteration-count: 1;
transition: ease-in 1.5s;
animation-fill-mode: forwards;
}
.Header-Site-Title-Active {
height: 100px;
width: 100vw;
top: 0;
animation-name: bgChangeDown;
animation-duration: 2s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
transition: ease-in 1.5s;
}
.Header-logo{
height:100px;
padding: 5px 10px 0 5px;
margin: 0;
display: inline;
float: left;
}
.Department-Name{
margin: 0;
margin-bottom: 5px;
height: 100px;
float: left;
display: inline;
color: white;
}
.Department-Name h3{
margin-bottom: 15px;
margin-top: -17px
}
.hamburger{
position: fixed;
cursor: pointer;
margin: 5px;
right: 5%;
top: 5%;
}
.line{
width: 30px;
height: 3px;
background: white;
margin: 5px;
}
.sidenav {
height: 100%; /* 100% Full-height */
width: 0; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1; /* Stay on top */
top: 0; /* Stay at the top */
right: 0;
background-color: black; /* Black*/
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 60px; /* Place content 60px from the top */
transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
}
.sidenav-active {
height: 100%; /* 100% Full-height */
width: 250px; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1; /* Stay on top */
top: 0; /* Stay at the top */
right: 0;
background-color: black; /* Black*/
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 60px; /* Place content 60px from the top */
transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
}
/* The navigation menu links */
.sidenav a, .sidenav-active a {
padding: 8px 8px 8px 32px;
text-decoration: none;
font-size: 25px;
color: white;
display: block;
transition: 0.3s;
}
/* When you mouse over the navigation links, change their color */
.sidenav a:hover, .sidenav-active a:hover {
color: #f1f1f1;
}
/* Position and style the close button (top right corner) */
.sidenav .closebtn, .sidenav-active .closebtn {
position: absolute;
top: 0;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
#media screen and (max-height: 450px) {
.sidenav {padding-top: 15px;}
.sidenav a {font-size: 18px;}
}
I am still learning React so feel free to suggest a new approach as well.
The classes that you're applying in your React component are Header-Site-Title-Active and Header-Site-Title but in your CSS your bgChangeUp animation is assigned to the Handle-Site-Title class, not Header-Site-Title:
.Handle-Site-Title {
height: 100px;
width: 100vw;
top: 0;
animation-name: bgChangeUp;
animation-duration: 2s;
animation-iteration-count: 1;
transition: ease-in 1.5s;
animation-fill-mode: forwards;
}
.Header-Site-Title-Active {
height: 100px;
width: 100vw;
top: 0;
animation-name: bgChangeDown;
animation-duration: 2s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
transition: ease-in 1.5s;
}
Further to this, this effect may be more easily achieved using CSS transitions:
.Header-Site-Title {
...
background-color: transparent;
transition: background-color ease-in 1.5s;
...
}
.Header-Site-Title-Active {
...
background-color: rgba(0,0,0,black);
...
}
I made a div with 2 elements inside: an image and an another div (about). The image is hiding the about div.
Is that possible to make elements which are in the about div clickable when the image disappear with a hover property ?
Thanks in advance !
Also, here's my code but the elements aren't clickable
#logo {
opacity: 1;
visibility: visible;
margin-top: 12.5px;
-webkit-transition: opacity 600ms, visibility 600ms;
-o-transition: opacity 600ms, visibility 600ms;
-moz-transition: opacity 600ms, visibility 600ms;
transition: opacity 600ms, visibility 600ms;
}
.blue_border:hover #logo {
opacity: 0;
visibility: hidden;
}
.blue_border {
width: 625px;
height: 625px;
background-image: url("./border.png");
background-repeat: no-repeat;
background-position: 50%;
}
#about {
z-index: -1;
position: relative;
margin-top: -605px;
width: 600px;
height: 600px;
border-radius: 100%;
background-color: #25B8EE;
}
<div class="blue_border">
<img id="logo" src="./logo.png" />
<!-- Img is "on" the about div" -->
<div id="about">
I want to be clicked :-(
</div>
<div class="la-ball-scale-multiple">
<div></div>
<div></div>
<div></div>
</div>
</div>
I don't think I understand it completely, but you cannot click under another element but you can use CSS display: none attr or you do this in a fake way. You can listen to the top element for this and check other conditions on javascript.
As mentioned in the comments, you may can use the pointer-events: none on the overlay to cause it to not receive click events, and allow them to pass through.
function whoWasClicked(e) {
console.log(`${e.target.id} was clicked!`);
};
document.querySelector('#lowerElement').addEventListener('click', whoWasClicked);
document.querySelector('#upperElement').addEventListener('click', whoWasClicked);
#lowerElement {
background-color: rgb(128, 128, 128);
min-width: 25vw;
height: 100px;
text-align: center;
position: absolute;
top: 37vh;
left: 37vw;
z-index: 1;
}
#upperElement {
min-width: 25vw;
height: 100px;
text-align: center;
line-height: 50px;
position: absolute;
top: 37vh;
left: 37vw;
z-index: 2;
pointer-events: none;
}
<div id="lowerElement">Click Me</div>
<div id="upperElement">Overlay</div>
With my current code, I think the z-index: -1; in #about is the problem: #blue_border is an image background and it's upper my "about" div... So I'm trying to find a way to replace that background.
Edit:
Okay. I figured out that the element with z-index: -1; will never be clickable the way I want to.
So I decided to reverse everything: the logo has now the property z-index: -1; and the about div (which is upper now) is hidden until the hover trigger. I also changed my background image by a border.
My code now :
/*Under #about and visible*/
#logo {
z-index: -1;
}
.blue_border {
width: 600px;
height: 600px;
border: 15px solid #71d1f4;
border-radius: 100%;
/*background-image: url("./border.png");
background-repeat: no-repeat;*/
background-position: 50%;
}
/*Hidden first*/
#about {
opacity: 0;
visibility: hidden;
position: relative;
margin-top: -605px;
width: 600px;
height: 600px;
border-radius: 100%;
background-color: #25B8EE;
-webkit-transition: opacity 600ms, visibility 600ms;
-o-transition: opacity 600ms, visibility 600ms;
-moz-transition: opacity 600ms, visibility 600ms;
transition: opacity 600ms, visibility 600ms;
}
/*Unhidden on hover*/
.blue_border:hover #about
{
opacity: 1;
visibility: visible;
}
I didn't changed my html
Thanks anyway guys. It was my very first question and I'm glad that some of you already answered me !
I'm trying to make my navigation transition the width from 0% to 20% when you click the 'hamburger' icon. It works when I open the navigation, but not when I close it.
Here is some of the CSS
.nav-toggle.active + nav {
width: 20%;
transition: all 500ms ease-in-out;
visibility:visible;
}
nav {
height: 2em;
width: 0%;
line-height: 2em;
position: absolute;
left: 5%;
top: 4.5%;
background: rgba(144, 198, 149, 1);
border-radius: 5px;
text-align: center;
visibility: hidden;
}
I've also tried the same thing without the 'visibility' property.
Here is the http://codepen.io/anon/pen/wawRYX with the hamburger icon, for more of a visual.
nav only transitioned when it had the class .active, when you removed the class, you removed the transition. <nav> must have a transition in its style:
nav {
height: 2em;
width: 0%;
line-height: 2em;
position: absolute;
left: 5%;
top: 4.5%;
background: rgba(144, 198, 149, 1);
border-radius: 5px;
text-align: center;
visibility: hidden;
transition: all 500ms ease-in-out;
-moz-transition: all 500ms ease-in-out;
-webkit-transition: all 500ms ease-in-out;
}
JSFiddle Demo
The reason why it was only transitioning when .active class was applied was because you only had the transition applied to the nav and nav bar when .active was applied. Add the transition property to both nav and the nav bar so that the transition will happen with and without the .active class.
Here is an updated codepen.
I have following markup for my nav-menu and menu icon to toggle it.
☰
<nav id="navigation">
Blog
Projects
Showcase
Social
About
×
</nav>
In which all menu items stack up vertically when viewing in Smartphone in portrait mode (I use CSS media queries).
Following is the initial style of menu items.
nav {
position: fixed;
top: 0;
padding-top: 60px;
}
nav .nav-item {
display: table;
margin-top: 10px;
padding: 2px 10px 2px 10px;
width: auto;
font-size: 2.5em;
text-align: left;
margin-left: -230px; /* Keep menu items off-screen by default. */
z-index: 1000;
-webkit-transition: margin-left 0.2s ease;
-moz-transition: margin-left 0.2s ease;
-o-transition: margin-left 0.2s ease;
transition: margin-left 0.2s ease;
}
/* Show Menu on :target or via JS */
nav:target .nav-item,
nav.open .nav-item {
margin-left: 0;
transition: margin-left 0.2s ease;
}
And now I toggle open class on nav-menu upon click of a.toggle-menu, this works fine and as expected in Chrome Canary 34 (DevTools device emulator) on Desktop, Firefox 26 running on Android 4.2, but it is giving unexpected behaviours in Chrome 31 on Android, as well as any other browser on Android (that uses WebView).
What's happening is when page is loaded for first time, and I tap on Menu icon, it shows Nav-menu with transition, and tapping again on Close hides it, but when I tap again the same menu icon, it doesn't show up, but if I double-tap on page (which usually zooms-in the page 1 level), nav-menu appears (without any transition, like it was already present there), and then tapping on close hides it, and this behaviour continues until I reload the page again.
Note that I'm currently using jQuery 2.0.3 for event handlers, and this problem persists with both ways of showing/hiding of menu, with JS, without JS.
Any help will be appreciated.
Try:
nav {
position: absolute;
top: 0;
padding-top: 60px;
}
nav .nav-item {
display: block;
margin-top: 10px;
padding: 2px 10px 2px 10px;
width: auto;
font-size: 2.5em;
text-align: left;
margin-left: -230px; /* Keep menu items off-screen by default. */
z-index: 1000;
-webkit-transition: margin-left 0.2s ease;
-moz-transition: margin-left 0.2s ease;
-o-transition: margin-left 0.2s ease;
transition: margin-left 0.2s ease;
}
/* Show Menu on :target or via JS */
nav:target .nav-item,
nav.open .nav-item {
margin-left: 0 !important;
}
So after lot of tinkering over the issue, I found that real problem with WebKit, was that I had position: fixed; given to parent nav, ideally it should work, but somehow it didn't, neither in Chrome for Android or any other WebKit-based Browser running on Android.
So I simply removed position from parent nav and instead gave it to .nav-items which are actual menu items, obviously I had to give different top values for each nav-item but it worked like a charm! So updated CSS looks something like below;
/* This is no longer needed */
/*
nav {
position: fixed;
top: 0;
padding-top: 60px;
}
*/
nav .nav-item {
position: fixed;
display: table;
padding: 2px 10px 2px 10px;
width: auto;
font-size: 2.5em;
text-align: left;
margin-left: -230px; /* Keep menu items off-screen by default. */
z-index: 1000;
-webkit-transition: margin-left 0.2s ease;
-moz-transition: margin-left 0.2s ease;
-o-transition: margin-left 0.2s ease;
transition: margin-left 0.2s ease;
}
/* Need all this madness just for WebKit. */
.nav-item.nav-blog {
top: 70px;
}
.nav-item.nav-projects {
top: 140px;
}
.nav-item.nav-showcase {
top: 210px;
}
.nav-item.nav-social {
top: 280px;
}
.nav-item.nav-about {
top: 350px;
}
.nav-item.nav-close {
top: 420px;
}
/* Show Menu on :target or via JS */
nav:target .nav-item,
nav.open .nav-item {
margin-left: 0;
}