I have a menu system where there are two hamburger menus. I'm trying to work out how to have JS trigger both instances of these menu icons. They both have all have the same classes.
I've tried adding a for loop, to loop through anything with the instance of the classes, but this didn't seem to work, and I'm going around in endless circles now.
With the code below I've kept the index number of the three menu bars in the first hamburger men at zero[0] so that you can see the desired effect of what happens when you click on the top hamburger menu.
I'd like it so that when I click on either hamburger menu the animation of the bars happens on both icons and the state of the blue box changes.
Any help would be amazing.
Codepen link is here: https://codepen.io/emilychews/pen/jwwVam
Code is below.
JAVASCRIPT
var container = document.getElementsByClassName('container')[0],
bar1 = document.getElementsByClassName('bar1')[0],
bar2 = document.getElementsByClassName('bar2')[0],
bar3 = document.getElementsByClassName('bar3')[0],
box = document.getElementsByClassName('box')[0],
openMenu = false; // used for toggle
container.onclick = function(){
if(openMenu === false) {
bar1.classList.add("bar1_open");
bar2.classList.add("bar2_open");
bar3.classList.add("bar3_open");
box.classList.add("changeBackground");
openMenu = true;
} else {
bar1.classList.remove("bar1_open");
bar2.classList.remove("bar2_open");
bar3.classList.remove("bar3_open");
box.classList.remove("changeBackground");
openMenu = false;
}
};
CSS
* {padding: 0; margin: 0;}
body {height: 200vh; font-family: arial;}
/* red square */
.container {
margin: 10px;
width: 100px;
height: 100px;
background: red;
padding: 0px;
position: relative;
}
/* properties for all menu bar lines */
.bar {
position: absolute;
height: 4px;
width: 60px;
background: blue;
left: 20px;
}
/* 1st menu line */
.bar1 {
position: absolute;
top: 28px;
margin: 0 auto;
transform-origin: top right;
transition: transform .5s;
}
/* 2nd menu line */
.bar2 {
position: absolute;
top: 48px;
margin: 0 auto;
transition: opacity 1s;
}
/* 3rd menu line */
.bar3 {
position: absolute;
top: 68px;
margin: 0 auto;
transform-origin: right bottom;
transition: transform .5s;
}
.bar1_open{
transform-origin: top right;
transform: rotate(-45deg) translate(-7px, -7px);
transition: transform .5s .1s ease-out ;
}
.bar2_open {
opacity: 0;
transition: opacity .2s ease-in;
}
.bar3_open {
top: 69px;
transform-origin: right bottom;
transform: rotate(45deg) translate(-7px, 7px);
transition: transform .5s .1s ease-out;
}
.box {
padding: 10px;
width: 200px;
height: 100px;
background: blue;
position: absolute;
left: 300px;
top: 30px;
z-index: 99;
color: white;
display: flex;
justify-content: center;
align-items: center
}
.changeBackground {
background: red;
}
HTML
<div class="container">
<div class="bar bar1"></div>
<div class="bar bar2"></div>
<div class="bar bar3"></div>
</div>
<!-- second hamburger menu button that currently has no JS -->
<div class="container">
<div class="bar bar1"></div>
<div class="bar bar2"></div>
<div class="bar bar3"></div>
</div>
<div class="box"> This toggles after 1st hamburger menu is clicked</div>
I have refined your code to work how you want it, i set the variables to the array of DOM Elements instead of the single one and for loop through them.
EDIT: heres the updated codepen if you'd like to take a look https://codepen.io/anon/pen/LLBEeQ
var container = document.getElementsByClassName('container'),
bar1 = document.getElementsByClassName('bar1'),
bar2 = document.getElementsByClassName('bar2'),
bar3 = document.getElementsByClassName('bar3'),
box = document.getElementsByClassName('box')[0],
openMenu = false; // used for toggle
for(var i=0; i < container.length; i++){
container[i].onclick = function(){
if(openMenu === false) {
for(var j = 0;j<bar1.length;j++){
bar1[j].classList.add("bar1_open");
bar2[j].classList.add("bar2_open");
bar3[j].classList.add("bar3_open");
}
box.classList.add("changeBackground");
openMenu = true;
} else {
for(var j = 0;j<bar1.length;j++){
bar1[j].classList.remove("bar1_open");
bar2[j].classList.remove("bar2_open");
bar3[j].classList.remove("bar3_open");
}
box.classList.remove("changeBackground");
openMenu = false;
}
}
};
If you are ok with using JQuery this works perfect:
HTML(link to jquery):
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
Javascript:
var container = document.getElementsByClassName('container')[0];
console.log(container);
var bar1 = document.getElementsByClassName('bar1')[0],
bar2 = document.getElementsByClassName('bar2')[0],
bar3 = document.getElementsByClassName('bar3')[0],
box = document.getElementsByClassName('box')[0],
openMenu = false; // used for toggle
$(".container").click(function(){
if(openMenu === false) {
$(".bar1").addClass("bar1_open");
$(".bar2").addClass("bar2_open");
$(".bar3").addClass("bar3_open");
box.classList.add("changeBackground");
openMenu = true;
} else {
$(".bar1").removeClass("bar1_open");
$(".bar2").removeClass("bar2_open");
$(".bar3").removeClass("bar3_open");
box.classList.remove("changeBackground");
openMenu = false;
}
});
Related
CodePen
I am trying to replicate the letter flipping animation in Wordle. But I cannot manage the smooth chaining/sequencing. How can I fix it? (I guess I need to use the JS Promise feature, but yet to understand that concept.)
function myFunction() {
var tiles = document.getElementsByClassName("inner");
var myArray = Array.from(tiles);
myArray.map(function (tile) {
tile.classList.add("flip-in");
// tile.style.setProperty("--flipColor", "green");
tile.addEventListener(
"animationend",
() => {
tile.classList.remove("flip-in");
tile.style.backgroundColor = "green";
tile.classList.add("flip-out");
},
{
once: true
}
);
return;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", myFunction);
You've essentially done it but probably overengineered it a bit. The wordle animation is pretty simple to accomplish using only one animation.
First, let's take care of the CSS animation. Since we will only use one animation for the entire flip we can rename it "flip".
To simulate the card "flipping" we can adjust the scale on the height rather than flipping it. At the same time, we can also apply the background color change.
We can also remove the animation-delay styles. We will apply these dynamically in the JS.
#keyframes flip {
0% {
transform: scaleY(1);
}
50% {
background: white;
transform: scaleY(0);
}
100% {
transform: scaleY(1);
background: green;
}
}
We have to mark the animation as fill-mode: forwards
.flip {
animation: flip 500ms ease forwards;
}
Next, we can simplify the JS to only apply the class. Do some renaming to easier understand what everyone is and does. And here we can also dynamically apply the animation delay based on the index of the tile. This way we will support all different number of tiles.
function applyFlip() {
var tiles = document.getElementsByClassName("inner");
var tilesArray = Array.from(tiles);
tilesArray.map(function (tile, i) {
tile.classList.add("flip");
tile.style.animationDelay = `${i * 100}ms`;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", applyFlip);
Here's a working snippet:
function applyFlip() {
var tiles = document.getElementsByClassName("inner");
var tilesArray = Array.from(tiles);
tilesArray.map(function (tile, i) {
tile.classList.add("flip");
tile.style.animationDelay = `${i * 100}ms`;
});
}
var flipper = document.getElementById("flipper");
flipper.addEventListener("click", applyFlip);
.container {
width: 540px;
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 2px;
}
.inner {
display: flex;
justify-content: center;
align-items: center;
font-size: 40px;
color: black;
width: 100px;
height: 100px;
background: white;
border: 2px solid black;
border-radius: 6px;
}
button {
margin: 50px;
font-size: 24px;
padding: 4px;
}
.flip {
animation: flip 500ms ease forwards;
}
#keyframes flip {
0% {
transform: scaleY(1);
}
50% {
background: white;
transform: scaleY(0);
}
100% {
transform: scaleY(1);
background: green;
}
}
<div class="container">
<div class="inner">S</div>
<div class="inner">T</div>
<div class="inner">A</div>
<div class="inner">C</div>
<div class="inner">K</div>
</div>
<button id="flipper"> Flipper </button>
I want to add transitions to sticky header to my store. I want to stciky header to show from the top when the scroll is > 50. The scrollheader and coverheader classes works fine. But transitions not worked. The header just jumps to above as sticky header is enabled. The logo part is resized in sticky header by almost 80px than normal header.
Here is the code of Javascript.
(function enableStickyHeader() {
var stickyHeader = document.querySelector('header').dataset.sticky;
var scrollHeader = $("header.scrollheader");
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 50 && stickyHeader == 'true') {
scrollHeader.removeClass('scrollheader').addClass("coverheader");
} else {
scrollHeader.removeClass("coverheader").addClass('scrollheader');
}
});
})();
And through css I am applying css transition property. I have tried to get the results by applying height and line height to headers. But that also not works.
.coverheader {
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
transition: all 0.3s;
position: fixed;
}
header {
width: 100%;
line-height: 50px;
top: 0;
z-index: 150;
}
.scrollheader {
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
transition: all 0.3s;
position: relative;
}
And Html code for the case is this.
<header class="header-section scrollheader" data-section-id="header" data-section-type="header-section" data-sticky="true">
<p>logo and menu is there</p>
</header>
For the effect you give to work, the values on which css is based must change.
I prepared the following example to give you an idea.
Please note: To make it easy to understand, I have slightly extended the animation time. And I made the background black and the header white.
(function enableStickyHeader() {
var stickyHeader = document.querySelector('header').dataset.sticky;
var scrollHeader = $("header.scrollheader");
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 82 && stickyHeader == 'true') {
scrollHeader.removeClass('scrollheader').addClass("coverheader");
} else {
scrollHeader.removeClass("coverheader").addClass('scrollheader');
}
});
})();
html {
height: 10000px;
background: black;
}
html,
body {
padding: 0;
margin: 0;
}
.coverheader {
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
transition: all 0.5s;
position: fixed;
bottom: 100%;
transform: translateY(100%);
}
header {
display: flex;
width: 100%;
line-height: 50px;
z-index: 150;
background: white;
}
.scrollheader {
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
transition: all 0.5s;
position: relative;
transform: translateY(0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header class="header-section scrollheader" data-section-id="header" data-section-type="header-section" data-sticky="true">
<p>logo and menu is there</p>
</header>
i have an html page where,when hovered over the first image a second image fades in/is shown.The first image has an onclick() event which performs a transition of rotating the image and scaling it by some number.During the transition, the first image disappears and some text appears on the same place(area of the div tag of the first image).I perform the transition through javascript and the hovering animation using css. Now when i click on the text(or the area of the div tag) the transition must reverse back i.e., the div area must be as it was before clicking(even with the hovering working.). I would like to know the answer through pure javascript please.
Thank you in advance.
timesclicked = 0;
document.getElementById("hoverImage").addEventListener("click", function()
{
var x = document.getElementById('container');
timesclicked+=1;
if(timesclicked%2!=0)
{
//obj.style.opacity = '0.5';
x.style.transform = 'rotateZ(-360deg) scale(1.4)';
x.style.transition = 'all 1.5s ease-in-out';
setTimeout(() => {
x.innerHTML = '<div style="font-size:16px; font-family: monospace; font-weight:bold; text-align:center; "> My Hero Academia, abbreviated as HeroAca is a Japanese superhero manga series written and illustrated by Kōhei Horikoshi. It has been serialized in Weekly Shōnen Jump since July 2014, and, as of February 2019, 22 volumes have been collected in tankōbon format.</div>'},'1300');
}
else
{
x.style.transform = 'rotateZ(-45deg) scale(1)';
x.style.transition = 'all 1.5s ease-in-out';
setTimeout(() => {
x.innerHTML = '<img src="https://picsum.photos/300">'},'500');
}
});
img
{
width: 300px;
height: 300px;
}
#mainImage,#hoverImage
{
left: 0px;
position: absolute;
top: 0px;
}
#hoverImage
{
opacity: 0;
transition: opacity 0.4s 0.1s ;
}
#hoverImage:hover
{
opacity: 1;
}
#container
{
background: url(https://picsum.photos/300);
background-size: cover;
width: 300px;
height: 300px;
position: absolute;
top:20%;
left:40%;
transform: rotateZ(-45deg);
}
#container:before
{
content: "";
display: block;
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: -1;
background-color: rgba(255, 255, 255, 0.6);
}
<div id="container" >
<img id="mainImage" src="https://picsum.photos/300">
<img id="hoverImage" src="https://picsum.photos/300">
</div>
As much as i know, I think the second clicking event is not happening because the eventlistener is on the hoverImage. I need a way to run the else part of the code somehow.
It looks like there are a few problems with your code, and you're going to have some debugging to do. That said, try this for a strategy:
Put your on-click event on the #container.
Put all the styling and transitioning details in the css. Your javascript will just add and remove a class from the #container.
Don't track the number of clicks unless you need it for something else. Have your if statement check for the presence or absence of the class you're toggling. (Or use an explicit toggle instead of an if-else block.)
Don't add and remove the text and background in the javascript, put them both in the HTML and control their visibility using the CSS.
edit:
People asked for examples and clarification. I'm stealing some of this from other people's answers.
I'm not completely sure I've understood OP's intentions correctly, and there are some rough-around-the-edgues details (like the cursor when you hover before clicking), but I think this should serve as an example:
let container = document.getElementById("container");
container.addEventListener("click", function(){
container.classList.toggle("selected");
});
#mainImage, #hoverImage, #selectedText {
width: 300px;
height: 300px;
left: 0px;
position: absolute;
top: 0px;
}
#hoverImage {
opacity: 0;
transition: opacity 0.4s 0.1s;
}
#container:hover > #hoverImage {
opacity: 1;
}
#container {
width: 300px;
height: 300px;
position: absolute;
top:20%;
left:40%;
transform: rotateZ(-45deg);
transition: all 1.5s ease-in-out;
}
#container.selected {
transform: rotateZ(-360deg) scale(1.4);
}
#container:before {
content: "";
display: block;
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: -1;
background-color: rgba(255, 255, 255, 0.6);
}
#selectedText {
font-size:16px;
font-family: monospace;
font-weight:bold;
text-align:center;
background: url(https://picsum.photos/300?text);
background-size: cover;
opacity: 0;
transition: opacity 0.1s 0.5s;
}
#container.selected > #selectedText {
opacity: 1;
transition: opacity 0.1s 1.3s;
}
<div id="container">
<img id="mainImage" src="https://picsum.photos/300?main">
<img id="hoverImage" src="https://picsum.photos/300?hover">
<div id="selectedText">
My Hero Academia, abbreviated as HeroAca is a Japanese superhero
manga series written and illustrated by Kōhei Horikoshi. It has been
serialized in Weekly Shōnen Jump since July 2014, and, as of
February 2019, 22 volumes have been collected in tankōbon format.
</div>
</div>
you can add the click event listener on the container div.
timesclicked = 0;
document.getElementById("container").addEventListener("click", function()
{
var x = document.getElementById('container');
timesclicked+=1;
if(timesclicked%2!=0)
{
//obj.style.opacity = '0.5';
x.style.transform = 'rotateZ(-360deg) scale(1.4)';
x.style.transition = 'all 1.5s ease-in-out';
setTimeout(() => {
x.innerHTML = '<div style="font-size:16px; font-family: monospace; font-weight:bold; text-align:center; "> My Hero Academia, abbreviated as HeroAca is a Japanese superhero manga series written and illustrated by Kōhei Horikoshi. It has been serialized in Weekly Shōnen Jump since July 2014, and, as of February 2019, 22 volumes have been collected in tankōbon format.</div>'},'1300');
}
else
{
x.style.transform = 'rotateZ(-45deg) scale(1)';
x.style.transition = 'all 1.5s ease-in-out';
setTimeout(() => {
x.innerHTML = '<img src="https://picsum.photos/300">'},'500');
}
});
img
{
width: 300px;
height: 300px;
}
#mainImage,#hoverImage
{
left: 0px;
position: absolute;
top: 0px;
}
#hoverImage
{
opacity: 0;
transition: opacity 0.4s 0.1s ;
}
#hoverImage:hover
{
opacity: 1;
}
#container
{
background: url(https://picsum.photos/300);
background-size: cover;
width: 300px;
height: 300px;
position: absolute;
top:20%;
left:40%;
transform: rotateZ(-45deg);
}
#container:before
{
content: "";
display: block;
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: -1;
background-color: rgba(255, 255, 255, 0.6);
}
<div id="container" >
<img id="mainImage" src="https://picsum.photos/300">
<img id="hoverImage" src="https://picsum.photos/300">
</div>
</style>
if I understand your problem correctly, I think you just need to move the transition styles into your CSS
x.style.transition = 'all 1.5s ease-in-out';
I have been trying to figure out how to rotate a div based off of my scrolling. I have a codepen that demonstrates the behaviour that I would like to achieve.
However, I do not know hot to make it work with scrolling. Essentially, I would like to scroll down and have the word Data move in a counter-clockwise rotation. And if I decide to scroll up and down it should move with the speed of the scroll. I only want it to move 90deg up or down.
Thanks!
var btn = document.querySelector('.button');
var btnUp = document.querySelector('.button-up')
btnUp.addEventListener('click', function() {
document.querySelector(".parent").style.webkitTransform = "rotate(-90deg)";
document.querySelector(".child").style.webkitTransform = "rotate(90deg)";
});
btn.addEventListener('click', function() {
document.querySelector(".parent").style.webkitTransform = "rotate(0deg)";
document.querySelector(".child").style.webkitTransform = "rotate(0deg)";
});
.parent {
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
transform: rotate(-0deg);
transition: transform 0.7s linear;
margin: 100px auto 30px auto;
}
.child {
position: absolute;
transform: rotate(-0deg);
transition: transform 0.7s linear;
border-radius: 50%;
width: 40px;
height: 40px;
text-align: center;
top: 278px;
/* -child size/2 */
left: 130px;
/* parent size/2 - child size/2 */
}
<div class="parent">
<div class="child">
Data
</div>
</div>
<button class="button">Click Down</button>
<button class="button-up">Click Up</button>
Add
<link href="https://unpkg.com/aos#2.3.1/dist/aos.css" rel="stylesheet">
<script src="https://unpkg.com/aos#2.3.1/dist/aos.js"></script>
and in script
<script>
AOS.init();
</script>
then in div
<div data-aos="fade-down"></div> //you can use whatever you want's
for further information
this website helps you on how to make it work
and
You can find out more at AOS Animation
I'm working on flexslider here onClick next I want to add class it is working but randomly click is coming when I first click class added then on second click not coming third click coming so on. I want to add a class every click. Here might be the problem in if()
$('.flex-next').on('click', function() {
if ($('.timeline span').hasClass('clicked')) {
$('.timeline span.clicked').removeClass('clicked');
$(this).addClass('clicked');
} else {
$('.timeline span').removeClass('clicked');
$('.timeline span').addClass('clicked');
}
});
.timeline {
content: '';
background-color: rgba(255, 255, 255, 0.52);
display: block;
width: 100px;
height: 2px;
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
position: relative;
}
.timeline span:before {
position: absolute;
left: 0;
top: -1px;
content: '';
background-color: red;
display: block;
height: 3px;
animation: yourAnimation 1s 0s linear;
}
.timeline span.clicked {
position: absolute;
left: 0;
top: -1px;
content: '';
background-color: blue;
display: block;
height: 3px;
animation: yourAnimation 1s 0s linear;
}
#keyframes yourAnimation {
0% {
width: 0;
}
50% {
width: 50%;
}
82% {
width: 100%;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex-next">Click here</div>
<span class="timeline">
<span></span>
</span>
You can acheive the required functionality as
$('.flex-next').on('click', function(){
if (! ($('.timeline span').hasClass('clicked')) ) {
$('.timeline span').addClass('clicked');
setTimeOut(function(){
$('.timeline span').removeClass('clicked');
} , 200)
}
});
To add/remove a class on click, it is better to use jquery toggleClass function.
Moreover you may need to execute the click event after the document is loaded correctly
$( document ).ready(function() {
$('.flex-next').on('click', function(){
$('.timeline span').toggleClass( "clicked" );
});
});
For more info, you may refer to: http://api.jquery.com/toggleclass/