Using Javascript if else to trigger css transition when Navbar is open - javascript

I have a hamburger menu button that transforms into a 'X' when clicked using css and javascript. Because my Navbar closes when a selection is made, not just when the menu button is clicked, the menu button stays as a 'X'.
I assume that I will need to use an 'if else' statement to tell the menu button to change instead of on click but I am not sure how to code this.
I have included the css code for the style of the button as well as the javascript that is currently used to make it transform and the javascript for the navbar.
The button code is from this site:
http://callmenick.com/post/animating-css-only-hamburger-menu-icons
And the navbar is from here:
https://www.w3schools.com/howto/howto_js_sidenav.asp
Button CSS Code:
.c-hamburger {
display: block;
position: relative;
overflow: hidden;
margin: 0;
padding: 0;
width: 96px;
height: 96px;
font-size: 0;
text-indent: -9999px;
appearance: none;
box-shadow: none;
border-radius: none;
border: none;
cursor: pointer;
transition: background 0.3s;
}
.c-hamburger:focus {
outline: none;
}
.c-hamburger span {
display: block;
position: absolute;
top: 44px;
left: 18px;
right: 18px;
height: 8px;
background: white;
}
.c-hamburger span::before,
.c-hamburger span::after {
position: absolute;
display: block;
left: 0;
width: 100%;
height: 8px;
background-color: #fff;
content: "";
}
.c-hamburger span::before {
top: -20px;
}
.c-hamburger span::after {
bottom: -20px;
}
.c-hamburger {
background-color: #ff3264;
}
.c-hamburger span {
transition: background 0s 0.3s;
}
.c-hamburger span::before,
.c-hamburger span::after {
transition-duration: 0.3s, 0.3s;
transition-delay: 0.3s, 0s;
}
.c-hamburger span::before {
transition-property: top, transform;
}
.c-hamburger span::after {
transition-property: bottom, transform;
}
/* active state, i.e. menu open */
.c-hamburger.is-active {
background-color: #cb0032;
}
.c-hamburger.is-active span {
background: none;
}
.c-hamburger.is-active span::before {
top: 0;
transform: rotate(45deg);
}
.c-hamburger.is-active span::after {
bottom: 0;
transform: rotate(-45deg);
}
.c-hamburger.is-active span::before,
.c-hamburger.is-active span::after {
transition-delay: 0s, 0.3s;
}
Button Javascript:
(function() {
"use strict";
var toggles = document.querySelectorAll(".c-hamburger");
for (var i = toggles.length - 1; i >= 0; i--) {
var toggle = toggles[i];
toggleHandler(toggle);
};
function toggleHandler(toggle) {
toggle.addEventListener( "click", function(e) {
e.preventDefault();
(this.classList.contains("is-active") === true) ? this.classList.remove("is-active") : this.classList.add("is-active");
});
}
})();
Navbar Javascript:
/* Set the width of the side navigation to 250px and the left margin of the page content to 250px and add a black background color to body */
function openNav() {
document.getElementById("mySidenav").style.width = "200px";
open = true;
}
/* Set the width of the side navigation to 0 and the left margin of the page content to 0, and the background color of body to white */
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
open = false;
}
If someone can help me find the correct code to do this, or has a better idea, I would really appreciate it. I'm quite new to Javascript if you can't already tell.
Thanks!

I didn't quite get what you were up to. Did you mean that you wanted your NavBar to be closed when you click on a button not just only when clicking on the 'X'?
If it was so, in the HTML code, you simply need to add the onclick="closeNav();" to every button. Something like this
<button onclick = "closeNav();"> My Button </button>
Ok. Since you want the button to change into 'X' when the NavBar is open, you need to give your button an ID, then I think we could use the following Javascript condition.
HTML
<button id="myButton" class="c-hamburger c-hamburger--htx">
<span>
::before
"toggle menu"
::after
</span>
</button><!--I copied from the site you provided-->
Javascript
I have edited your sidenav.js
function decide(){
if(open == true){
closeNav();
}else{
openNav();
}
}
/* Set the width of the side navigation to 250px and the left margin of the page content to 250px and add a black background color to body */
function openNav() {
document.getElementById("mySidenav").style.width = "200px";
document.getElementById("myButton").classList.add("is-active");
open = true;
}
/* Set the width of the side navigation to 0 and the left margin of the page content to 0, and the background color of body to white */
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
document.getElementById("myButton").classList.remove("is-active");
open = false;
}

Related

Prevent scroll bar to go up when click mobile nav

I have a mobile nav and I open it using this code in JS file:
var toggleButton = document.querySelector(".toggle-button");
var mobileNav = document.querySelector(".mobile-nav");
var closeButton = document.querySelector(".close-button");
toggleButton.addEventListener("click", function () {
mobileNav.classList.add("slide");
});
closeButton.addEventListener("click", function () {
mobileNav.classList.remove("slide");
});
.mobile-nav {
position: fixed;
transition: 0.4s ease;
transform: translateX(1400px);
}
.slide {
transform: translateX(0);
}
when I scroll down and open mobile nav using slide class the scroll bar goes up, how to fix it? i want it to remain at current place where I open slide menu.
here is project Github page for more codes:
enter link description here
and here is the online website for reprodure the issue, just make browser page smaller than 768px and scroll down then tap hamburger icon to see the issue.
enter link description here
const navSection = document.querySelector(".nav-section");
function openNav() {
navSection.classList.add("open-nav")
}
function closeNav() {
navSection.classList.remove("open-nav")
}
.nav-section{
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
opacity: 0;
transition: 0.25s;
pointer-events: none;
}
.nav-section nav{
display: flex;
flex-direction: column;
position: relative;
transform: translateX(-100%);
width: 20rem;
height: 100%;
background: red;
}
.open-nav{
pointer-events: all;
opacity: 1;
background: rgba(0, 0, 0, 0.5);
}
.open-nav nav{
transform: translateX(0%);
}
.close-nav-btn{
position: absolute;
right: 0;
top: 0;
}
<div class="open-btn">
<button onclick="openNav()">open</button>
</div>
<section class="nav-section">
<nav>
<a>nav 0</a>
<a>nav 1</a>
<a>nav 2</a>
<a>nav 3</a>
</nav>
<button onclick="closeNav()" class="close-nav-btn">close</button>
</section>
Like this maybe?

How to add transitions to a drop down menu?

I have a drop-down menu that makes text appear when clicked. However, when I add transitions to it, nothing happens. It still just shows up without sliding down. I want the transition to show the text gradually from top to bottom as it appears.
This is the CSS:
.drop-down {
display: flex;
flex-direction: column;
text-align: left;
transition: height 0.3s ease-in-out;
transition-delay: 0.1s;
overflow: hidden;
position: relative;
}
.menu is the class name for the button clicked that shows this .drop-down text.
I don't know if I used the transition properly.
Should I have used JavaScript instead? And if not what do I need to change?
JavaScript Code:
const menu = document.querySelector('.menu')
const menuContent = document.querySelector('.drop-down')
menu.addEventListener('click', menuClick, false);
menuContent.style.display = 'none'
function menuClick() {
menuContent.classList.toggle('show');
if (menuContent.style.display == 'none') {
menuContent.style.display = 'block'
} else {
menuContent.style.display = 'none'
}
}
You can do this without javascript.
.drop-down {
display: flex;
flex-direction: column;
text-align: left;
transition: height 0.3s ease-in-out;
transition-delay: 0.1s;
overflow: hidden;
position: relative;
opacity:0;
visibility:hidden;
}
.menu:hover .drop-down{
opacity:1;
visibility:visible;
}

Background transition does not work properly

I'm going to change back ground an element in a setInterval function. the background is getting changed imediately, but I would like to make it transited in couple of seconds.
var act = true;
setInterval(function(){
if (act) {
$("div").addClass("back2")
$("div").removeClass("back")
act = false
} else {
$("div").addClass("back")
$("div").removeClass("back2")
act = true
}
}, 10000)
.back{
width:100px;
height:100px;
background-image:url("https://www.skoobe.de/static/v/7b2334ac8a86ab5d764bc6e94df87df4aa5b4e2adc78c783e73ae2cbaf613745.jpg");
display:block;
transition: .5s ;
}
.back2{
width:100px;
height:100px;
background-image:url("https://www.skoobe.de/static/v/a5c0d3825217f88c4c893e7b630c4f1c5eb4c9bec834e1112383614270b5d583.jpg");
display:block;
transition: .5s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="c">tz</div>
background-image is not an animatable property. As you can see in this list on the mozilla dev page, this is not possible: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties
What you can do is have two divs with one background image each overlapping each other and then make one of them transparent to create a blending effect.
I made a fiddle to illustrate the idea:
https://jsfiddle.net/Lpduw3mq/
// find elements
var firstDiv = $("#first")
var secondDiv = $("#second")
// Swap backgrounds
var act = true;
setInterval(function(){
if (act) {
firstDiv.addClass("transparent")
secondDiv.removeClass("transparent")
act = false
} else {
firstDiv.removeClass("transparent")
secondDiv.addClass("transparent")
act = true
}
}, 5000)
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
.base {
position: absolute;
top: 0;
left: 0;
}
.back {
width: 100px;
height: 100px;
background-image: url("https://www.skoobe.de/static/v/7b2334ac8a86ab5d764bc6e94df87df4aa5b4e2adc78c783e73ae2cbaf613745.jpg");
display: block;
opacity: 1;
transition: opacity 0.5s;
}
.back2 {
width: 100px;
height: 100px;
background-image: url("https://www.skoobe.de/static/v/a5c0d3825217f88c4c893e7b630c4f1c5eb4c9bec834e1112383614270b5d583.jpg");
display: block;
opacity: 1;
transition: opacity 0.5s;
}
.transparent {
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="first" class="base back"></div>
<div id="second" class="base back2 transparent"></div>
You can use an unordered list of two items absolutely styled with the image backgrounds and use keyframe animation to change between these two items while smoothly changing a background opacity. Check this out http://tympanus.net/codrops/2012/01/02/fullscreen-background-image-slideshow-with-css3/

Displaying modal in JavaScript not transitioning smoothly

I pinched a css effect that I like for some popup modals in my application, but I'm having some trouble when the modal(s) are created in the DOM in JS.
When the user clicks on the button to 'open' the modal, it should transition smoothly, appearing to grow in size (scaling up). When it's just html and css this works as desired, however when it's on a click event in JS that I've written, the modal just abruptly appears and disappears (if I use 'display: block'), or it's super-jerky or I can't make it work at all (if I use 'visibility: visible').
My feeling is that it isn't viewing it as a 'transition' and the effect doesn't apply, or that I'm somehow trying to transition the blurred background rather than the modal element.
This is my css.....
.modal {
display: none; <-- added to flip between states, might be cause of problem
height: 100vh;
width: 100%;
position: fixed;
top: 0;
left: 0;
background-color: rgba($color-black, .8);
z-index: 999999;
opacity: .98;
transition: all .3s;
#supports(-webkit-backdrop-filter: blur(10px)) or (backdrop-filter:blur(10px)){
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
background-color: rgba($color-black, .3);
}
&__content {
#include absCenter;
width: 75%;
background-color: $color-white;
box-shadow: 0 2rem 4rem rgba($color-black, .2);
border-radius: 3px;
display: table;
overflow: hidden;
opacity: 1;
transform: translate(-50%, -50%) scale(1);
transition: all .5s .2s;
}
Please forgive the (very) pseudo code for the JS, but the actual code is spaghetti like mama used to make.....
dbRecord.forEach(el => {
const button = document.createElement('button')
button.innerHTML = <populate some html with db info>
button.addEventListener('click', (e) => {
modal.style.display = 'block'
modal.innerHTML = <set attributes from parent element>
document.querySelector('.modalCloseButton').addEventListener('click') => {
modal.style.display = 'none'
}
...
}
}
How can I make this transition smooth rather than abrupt?
I got the transition working only one way. Maybe this code sample helps you to get it also working the other way.
display can't have transitions. Set background and color to transparent. When your transition time is 0.3s make a setTimeout to set it to display: none after 0.3 seconds.
var modal = document.querySelector('.modal');
var dbRecord = ['foo', 'bar']
dbRecord.forEach(el => {
var button = document.createElement('button');
button.innerHTML = 'populate some html with db info<br>' + el;
button.addEventListener('click', (e) => {
modal.querySelector('p').innerHTML = 'set attributes from parent element<br>' + el;
document.querySelector('.modalCloseButton').style.display = 'block';
modal.style.display = 'block';
modal.style.backgroundColor = 'rgba(0,0,0,.8)';
modal.style.color = 'white';
});
document.body.appendChild(button);
});
document.querySelector('.modalCloseButton').addEventListener('click', () => {
modal.style.backgroundColor = 'rgba(0,0,0,0)';
modal.style.color = 'transparent';
document.querySelector('.modalCloseButton').style.display = 'none';
setTimeout(() => {
modal.style.display = 'none';
}, 300)
});
.modal {
display: none;
height: 100vh;
width: 100%;
position: fixed;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0);
z-index: 999999;
color: transparent;
transition: all .3s linear 0s;
}
.modalCloseButton {
display: none;
}
<div class="modal">
<p></p>
<button class="modalCloseButton">×</button>
</div>

Hard transition of other properties when display property is involved

I want to fade between two differently sized elements within a container overlaying each other. The first element should be faded out, then the container resized and finally the other element faded in.
Here's the related snippet:
var layer1 = document.getElementById("layer1");
var layer2 = document.getElementById("layer2");
function switchLayers() {
layer1.addEventListener("transitionend", function() {
layer2.classList.add("fadein");
});
layer1.classList.add("fadeout");
}
#container {
position: relative;
background-color: yellow;
padding: 10px;
overflow: hidden;
}
.layer {
position: relative;
width: 400px;
}
#layer1 {
height: 100px;
float: left;
background-color: blue;
}
#layer2 {
height: 150px;
background-color: red;
display: none;
opacity: 0;
}
#layer1.fadeout {
opacity: 0;
transition: opacity 1s ease-out;
}
#layer2.fadein {
display: block;
opacity: 1;
transition: opacity 1s ease-out;
}
<button onclick="switchLayers()">Switch layers</button>
<div id="container">
<div id="layer1" class="layer"></div>
<div id="layer2" class="layer"></div>
</div>
When the second layer's display property is set to block it works as expected, i.e. the opacity is changed from 0 to 1 within a second. Though if it's set to none, the transition suddenly is discrete.
I've tried to set all within the transition value to transition all properties and also tried to include the display property in the transition like this:
transition: display 0s, opacity 1s ease-out;
Though without success. Note that because the container should resize to the size of the currently displayed layer, the visibility property can't be used (as it hides the element but still lets it occupy the space).
How to made this work?
Try using the visibility property instead of display.
For more information regarding the state changes in visibility and display, refer article.
For transitioning the parent height, you have to manually change the height property of the #container. Using display: block & display: none will never transition the parent.
Refer code:
var layer1 = document.getElementById("layer1");
var layer2 = document.getElementById("layer2");
function switchLayers() {
layer1.addEventListener("transitionend", function() {
layer2.classList.add("fadein");
document.getElementById("container").style.height = "170px";
});
layer1.classList.add("fadeout");
}
#container {
position: relative;
background-color: yellow;
padding: 10px;
height: 100px;
overflow: hidden;
transition: all 0.5s;
}
.layer {
position: relative;
width: 400px;
}
#layer1 {
height: 100px;
float: left;
background-color: blue;
}
#layer2 {
height: 150px;
background-color: red;
visibility: none;
opacity: 0;
}
#layer1.fadeout {
visibility: none;
opacity: 0;
transition: all 1s ease-out;
}
#layer2.fadein {
visibility: visible;
opacity: 1;
transition: all 1s ease-out;
}
<button onclick="switchLayers()">Switch layers</button>
<div id="container">
<div id="layer1" class="layer"></div>
<div id="layer2" class="layer"></div>
</div>
There is no straightforward way. Transitions do not work on display, nor do they work on auto height. So, visibility is a good bet.
Note that because the container should resize to the size of the
currently displayed layer, the visibility property can't be used (as
it hides the element but still lets it occupy the space).
Then, you will need to hack it out. You can make use of min-height. Give a faux min-height to your container, and then apply the height of your layer2 to it once the transition ends. Also, because display on layer2 will block the transition, you need to separate out the classes for display and opacity and space out their application using a zero timeout in between.
Here is a crude idea:
var layer1 = document.getElementById("layer1"),
layer2 = document.getElementById("layer2"),
container = document.getElementById("container"),
h = window.getComputedStyle(layer2).getPropertyValue("height");
container.addEventListener("transitionend", function(e) {
if (e.target.id === 'layer1') {
// apply layer2 height to container min-height
container.style.minHeight = h;
}
if (e.target.id === 'container') {
// First show the layer2
layer2.classList.add("show");
// Then a dummy pause to fadein
setTimeout(function(){
layer2.classList.add("fadein");
}, 0);
}
}, false);
function switchLayers() {
layer1.classList.add("fadeout");
}
#container {
position: relative;
background-color: yellow;
padding: 10px; overflow: hidden;
min-height: 1px; /* faux min-height */
transition: min-height 1s linear;
}
.layer { position: relative; width: 400px; }
#layer1 {
height: 100px; float: left;
background-color: blue;
transition: all 1s linear;
}
#layer2 {
height: 150px; background-color: red;
display: none; opacity: 0;
transition: opacity 1s linear;
}
#layer1.fadeout { opacity: 0; }
#layer2.show { display: block; } /* Separate out display */
#layer2.fadein { opacity: 1; } /* Separate out opacity */
<button onclick="switchLayers()">Switch layers</button>
<div id="container">
<div id="layer1" class="layer"></div>
<div id="layer2" class="layer"></div>
</div>

Categories