How to add transitions to a drop down menu? - javascript

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;
}

Related

Text color in CSS Animation doesn't update with rest of content when 'theme toggle' is clicked on iOS

I have text that scrolls horizontally in a marquee style effect. This works great.
In addition to this I have a 'toggle' that when clicked adds the class .dark-mode to the html tag which basically inverts all the colours. So by default it's white page, black text. When toggled, black page, white text.
This works perfectly on my desktop browser. However I've noticed on iOS Safari and Chrome the text within the CSS Animation does not update with the rest of the copy. I haven't been able to test if that's the case on Android as well.
I've included the code for this but also put it on a CodePen here incase it's easier to view for people: https://codepen.io/moy/pen/eYjryXN
What's additional strange, if I scroll down the page then back up the text DOES change colour? Which indicates to me maybe once the animation is running, it leaving the viewport and re-entering somehow renders it again and corrects the colour?
I thought adding:
document.querySelector(‘.marquee’).offsetWidth;
Might force a 'reflow' of the page but it didn't do anything. Really appreciate some help on this. Strange one!
const html = document.querySelector('html');
const button = document.querySelector('.contrast__link');
button.addEventListener('click', e => {
e.preventDefault();
html.classList.toggle('dark-mode');
});
:root {
--color-primary: black;
--color-secondary: white;
--spacing: 24px;
}
.dark-mode {
--color-primary: white;
--color-secondary: black;
}
body {
background: var(--color-secondary);
color: var(--color-primary);
margin: 0 auto;
padding: 48px 24px;
max-width: 800px;
}
.marquee {
margin: 0 calc(var(--spacing) * -1);
margin-bottom: 120px;
}
.marquee h1 {
display: flex;
flex: 1 1 auto;
flex-wrap: nowrap;
overflow: hidden;
}
.marquee span {
-webkit-animation: 8s linear infinite 0s forwards running marquee;
animation: 8s linear infinite 0s forwards running marquee;
box-sizing: border-box;
flex: 1 0 50%;
padding: 0 var(--spacing);
white-space: nowrap;
text-align: center;
}
/**
* The looping animation for the marquee.
*/
#-webkit-keyframes marquee {
from {
transform: translateX(0);
}
to {
transform: translateX(-100%);
}
}
#keyframes marquee {
from {
transform: translateX(0);
}
to {
transform: translateX(-100%);
}
}
<div class="grid__item">
<div class="hgroup">
<div class="marquee">
<h1 class="page-title">
<span>Hello... is it me you're looking 404?</span>
<span>Hello... is it me you're looking 404?</span>
<span>Hello... is it me you're looking 404?</span>
<span>Hello... is it me you're looking 404?</span>
</h1>
</div>
</div>
<p class="contrast">Toggle Here</p>
</div>

animation works once when opening a cart drawer and then doesn't work afterwards

I've been dealing with this bug for some time and I cannot figure out what to do.
I have two simple CSS animations for opening and closing the cart.
.animate-close-cart {
animation: closeCart 0.2s 0s 1 linear forwards;
}
#keyframes closeCart {
from {
transform: translateX(-35%);
}
to {
transform: translateX(0);
}
}
.animate-open-cart {
animation: openCart 0.2s 0s 1 linear forwards;
}
#keyframes openCart {
from {
transform: translateX(0);
}
to {
transform: translateX(-35%);
}
}
upon clicking my cart button I add or remove the appropriate class:
Opening the cart:
value: function _openMiniCart() {
var mainWrapper = document.getElementById("main_wrapper");
mainWrapper.classList.remove("animate-close-cart");
mainWrapper.classList.add("animate-open-cart");
}
Closing the cart:
value: function _closeMiniCart() {
var mainWrapper = document.getElementById("main_wrapper");
mainWrapper.classList.remove("animate-open-cart");
mainWrapper.classList.add("animate-close-cart");
}
The main_wrapper block is wrapped around my entire webpage:
<body>
<div id="main_wrapper">
// header, template, page contents etc.
<div/>
</body>
Opening the cart the animation plays, the web page moves to the left showing the cart. Perfect.
Closing the cart the animation plays, the web page moves back to the right, hiding the cart.
Then...
Opening it once again, the webpage just jumps without animation to the left, showing the cart,
But closing it, it plays the animation and moves back to the right.
Every open after the first initial open always makes the webpage just immediately jump to -35%.
I don't know how to debug this or what could be causing this issue.
edit:
With CSS transform the same bug where it only offers a smooth transition on the first open cart, all other open carts jump immediately:
#main_wrapper {
transition: transform 0.2s;
}
.animate-close-cart {
transform: translateX(0);
}
.animate-open-cart {
transform: translateX(0);
}
So when you say the entire page moves, do you mean you slide the main content screen a bit out of view? Or you allow the blocks to keep everything visible on both sides if they're both available? I'm not sure I'm understanding the intent correctly but here's an example of an effect I've used in the past if it helps accomplish your goal. Otherwise a reproducible example of your pain points instead of just snippets would likely make it more clear to find you a solution. Cheers.
toggleMe = () => {
const side = document.getElementById('side-wrapper');
side.classList.toggle('slide-me');
}
#main-wrapper {
height: 80vh;
width: 80vw;
margin: 2rem;
border: red 5px dashed;
display: flex;
flex-direction: row;
overflow: hidden; /* make this visible if you want to see in action */
}
#section-wrapper, #side-wrapper {
outline: #fff 3px dashed;
outline-offset: -10px;
}
#section-wrapper {
height: 100%;
width: 100%;
background-color: #00f;
}
#side-wrapper {
height: 100%;
width: 350px;
background-color: #0f0;
margin-right: -350px;
transition: margin-right 1s ease-in-out;
}
.slide-me {
margin-right: 0 !important;
}
#example input:checked:after {
content: 'SIDE IS OPEN';
display: inline-block;
margin-left: 1rem;
color: green;
}
<label id="example">
Click to toggle side slide
<input type="checkbox" onclick="toggleMe()">
</label>
<div id="main-wrapper">
<div id="section-wrapper"></div>
<div id="side-wrapper"></div>
</div>

CSS transition does not work on mobile

Please have a look at the animation below. While you may see that it works on PC, there must be something wrong since it does not work on mobile. For example on Android, the image is zoomed and with opacity 1 from the very beginning. I assume that the transition has been made but the duration was 0s. Thank you for your help.
$(document).ready(function(){
$(".photo").css(" -moz-transform", "scale(1.2)");
$(".photo").css("-webkit-transform", "scale(1.2)");
$(".photo").css("-o-transform", "scale(1.2)");
$(".photo").css("opacity", "1");
$(".photo").css("transform", "scale(1.2)");
});
.photo {
display: inline-block;
vertical-align:top;
max-width:100%;
opacity: 0.1;
-moz-transition: transform 40s, opacity 6s;
-webkit-transition: transform 40s, opacity 6s;
transition: transform 40s, opacity 6s;
}
.photoDiv {
display: inline-block;
background-color: #f1f1f1;
width: 100%;
position: relative;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="photoDiv">
<img class="photo" src="https://img-aws.ehowcdn.com/877x500p/s3-us-west-1.amazonaws.com/contentlab.studiod/getty/f24b4a7bf9f24d1ba5f899339e6949f3">
</div>
I think it's cleaner to remove the CSS from JS. Also jQuery is redundant and way too big for what you are trying to do here. Also make sure to add the JS at the end of the body. This way you are sure the content is loaded before JS will even be loaded.
window.addEventListener('load', function() {
var photos = document.getElementsByClassName('photo');
if( photos )
{
for( var i = 0; i < photos.length; i++ )
{
var photo = photos[i];
photo.classList.add('active');
}
}
});
.photo {
display: inline-block;
vertical-align:top;
max-width:100%;
opacity: 0.1;
/*ease-in-out is the animation, 2s is the delay/ pause*/
transition: transform 40s ease-in-out 2s, opacity 6s ease-in-out 2s;
transform: scale(1);
}
.active {
opacity: 1;
transform: scale(1.2);
}
.photoDiv {
display: inline-block;
background-color: #f1f1f1;
width: 100%;
position: relative;
overflow: hidden;
}
<div class="photoDiv">
<img class="photo" src="https://img-aws.ehowcdn.com/877x500p/s3-us-west-1.amazonaws.com/contentlab.studiod/getty/f24b4a7bf9f24d1ba5f899339e6949f3">
</div>

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

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;
}

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