CSS transition in combination with JS clickEvent - javascript

Encountering the following issue when trying to combine CSS transitions with JS event handlers. I know how to use CSS transition property for example:
div {
width: 50px;
height: 50px;
background: blue;
transition: width 2s;
}
div:hover {
width: 300px;
}
<div></div>
I also know how to put a click handler on an DOM element like this:
let eventDiv = document.querySelector('#clickMe');
let hiddenDiv = document.querySelector('#hiddenDiv');
eventDiv.onclick = () => {
if(hiddenDiv.style.display === 'block') {
hiddenDiv.style.display = 'none'
} else{
hiddenDiv.style.display = 'block';
}
}
#clickMe{
width: 100px;
height: 50px;
background-color: blue;
}
#hiddenDiv {
width: 100px;
height: 50px;
background-color: green;
display: none;
}
<div id="clickMe"></div>
<div id="hiddenDiv"></div>
Question
How do I combine the two and get a CSS transition (<div> should not appear immediately but should slide in) when I toggle the visibility of the <div> with a JS onclick event?

As per my comment, to combine the js and transition, you need to add and remove a class that changes the property that you want to transition.
In the below snippet, I add and remove a class of hide, which changes the height (that has a trnasition on it)
let eventDiv = document.getElementById('clickMe');
let hiddenDiv = document.getElementById('hiddenDiv');
eventDiv.onclick = () => {
if(hiddenDiv.classList.contains("hide")) {
hiddenDiv.classList.remove("hide");
} else{
hiddenDiv.classList.add("hide");
}
}
#clickMe{
width: 100px;
height: 50px;
background-color: blue;
}
#hiddenDiv {
width: 100px;
height: 50px;
background-color: green;
overflow:hidden;
transition: height 1s;
}
#hiddenDiv.hide {
height: 0;
}
<div id="clickMe"></div>
<div id="hiddenDiv" class="hide"></div>

The problem here is that you cannot give transition to display property:
div {
width: 50px;
height: 50px;
background: blue;
transition: 2s;
}
div:hover {
display:none;
}
<div></div>
What you can do is to use opacity instead.
let eventDiv = document.querySelector('#clickMe');
let hiddenDiv = document.querySelector('#hiddenDiv');
eventDiv.onclick = () => {
if(hiddenDiv.style.opacity === '1') {
hiddenDiv.style.opacity = '0'
} else{
hiddenDiv.style.opacity = '1';
}
}
#clickMe{
width: 100px;
height: 50px;
background-color: blue;
}
#hiddenDiv {
width: 100px;
height: 50px;
background-color: green;
opacity: 0;
transition: 2s;
}
<div id="clickMe"></div>
<div id="hiddenDiv"></div>
IMPORTANT
If you choose to use this property remember to change display to none after the transition is over if you don't want it to be block.

Related

Multiple divs addClass and removeClass at the same time [duplicate]

This question already has answers here:
Swap css class
(4 answers)
Closed 10 months ago.
I want to make these two divs always have opposite skew angles.
But it doesn’t work and when I click on body, then they have the same skewY value.
Does anyone know how to correct this? Thank you!
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="div1 content skew1">
</div>
<div class="div2 content skew2">
</div>
.div1 {
width: 100px;
height: 100px;
background-color: white;
border: 1px solid black;
}
.div2 {
width: 100px;
height: 100px;
background-color: white;
border: 1px solid black;
}
.skew1 {
transform: skewY(20deg);
transition: transform 1s;
}
.skew2 {
transform: skewY(-20deg);
transition: transform 1s;
}
$(function () {
$("body").on("click", function () {
if ($(".content").hasClass("skew1")) {
$(".content").removeClass("skew1").addClass("skew2");
} else {
$(".content").removeClass("skew2").addClass("skew1");
}
});
});
The problem is that .removeClass and .addClass both operate on ALL the elements in .content. Which means after one click they will have exactly the same classes. Use .toggleClass instead.
Exmaple:
When your App runs $('.content') will return [ <div1 class="skew1">, <div2 class="skew2"> ]
On the first click .removeClass('skew1') will return [ <div1>, <div2 class="skew2"> ]
Then, .addClass('skew2') will return [ <div1 class="skew2">, <div2 class="skew2"> ]
$(function () {
$("body").on("click", function () {
$(".content").toggleClass("skew1 skew2");
});
});
.div1 {
width: 100px;
height: 100px;
background-color: white;
border: 1px solid black;
}
.div2 {
width: 100px;
height: 100px;
background-color: white;
border: 1px solid black;
}
.skew1 {
transform: skewY(20deg);
transition: transform 1s;
}
.skew2 {
transform: skewY(-20deg);
transition: transform 1s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="div1 content skew1">
</div>
<div class="div2 content skew2">
</div>
This should help:
$(function() {
$("body").on("click", function() {
const div1 = $(".div1");
const div2 = $(".div2");
if (div1.hasClass("skew1")) {
div1.removeClass("skew1");
div1.addClass("skew2");
div2.removeClass("skew2");
div2.addClass("skew1");
} else {
div1.removeClass("skew2");
div1.addClass("skew1");
div2.removeClass("skew1");
div2.addClass("skew2");
}
});
});
you can do this using toggleClass
$(function () {
$("body").on("click", function () {
$('.content').toggleClass('skew1').toggleClass('skew2')
});
});
.div1 {
width: 100px;
height: 100px;
background-color: white;
border: 1px solid black;
}
.div2 {
width: 100px;
height: 100px;
background-color: white;
border: 1px solid black;
}
.skew1 {
transform: skewY(20deg);
transition: transform 1s;
}
.skew2 {
transform: skewY(-20deg);
transition: transform 1s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="div1 content skew1">
</div>
<div class="div2 content skew2">
</div>

Keep div visible when the mouse is over it

I have a div2 that fades away after 3 seconds and appears again on div1 or itself hover.
The problem is that it fades away again after 3 seconds and I want it to remain active while the mouse is over it.
Here's my code:
$(document).ready(function(){
// div2 fades away after 3s
setInterval(function(){
$(".div2").addClass("fade-away");
}, 3000);
// div2 pops up on hover
$(".div1, .div2").hover(function(){
$(".div2").removeClass("fade-away")
});
});
.div1 {
width: 300px;
height: 200px;
background: pink;
}
.div2 {
position: absolute;
width: 300px;
height: 50px;
margin-top: -70px;
background: lightblue;
opacity: 1;
}
.fade-away {
opacity: 0;
}
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<div class="div1"></div>
<div class="div2"></div>
Is there a way to make the div2 remain active while the mouse is over it with javascrit and css only? Sorry for my english.
You can use a boolean flag to do it.
Set the boolean to true when mouseenter and set it to false on mouseleave event.
https://jsfiddle.net/ramseyfeng/0nc2bw8f/
$(document).ready(function() {
let mouseIn = false;
// div2 fades away after 3s
setInterval(function() {
if (!mouseIn) {
$(".div2").addClass("fade-away");
}
}, 3000);
$('.div1').on('mouseenter', () => {
mouseIn = true;
});
$('.div1').on('mouseleave', () => {
mouseIn = false;
});
// div2 pops up on hover
$(".div1, .div2").hover(function() {
$(".div2").removeClass("fade-away")
});
});
.div1 {
width: 300px;
height: 200px;
background: pink;
}
.div2 {
position: absolute;
width: 300px;
height: 50px;
margin-top: -70px;
background: lightblue;
opacity: 1;
}
.fade-away {
opacity: 0;
}
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<div class="div1"></div>
<div class="div2"></div>
Here is a quick and easy way to do it.
You can do it by hovering over any class, I just did it in text for the example.
.hide {
display: none;
}
.myDIV:hover + .hide {
display: block;
color: red;
}
<body>
<h2>Display an Element on Hover</h2>
<div class="myDIV">Hover over me.</div>
<div class="hide">I am shown when someone hovers over the div above.</div>
</body>

Looping through each element and logging the height

I want to be able to log the height of each of the .slide-text-overlay elements, but no value seems to be showing. The simple for of loop should loop through each class and just log the html of that class and then the height - but the height isn't logging; instead, just an empty line in the console.
Any ideas what I'm doing wrong here? Thanks for any help
var overlays = document.querySelectorAll('.overlay');
for (let overlay of overlays) {
console.log(overlay);
console.log(overlay.style.height);
}
.overlay:first-of-type {
color: red;
width: 100px;
height: 50px;
background: orange;
}
.overlay:nth-of-type(2) {
color: blue;
width: 100px;
height: 75px;
background: pink;
}
<div class='overlay'>
overlay 1
</div>
<div class='overlay'>
overlay 2
</div>
Use the offset Height in JS
var overlays = document.querySelectorAll('.overlay');
for (var i=0; i < overlays.length; i++) {
console.log(overlays[i].offsetHeight)
}
.overlay:first-of-type {
color: red;
width: 100px;
height: 50px;
background: orange;
}
.overlay:nth-of-type(2) {
color: blue;
width: 100px;
height: 75px;
background: pink;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='overlay'>
overlay 1
</div>
<div class='overlay'>
overlay 2
</div>
Documentation:
https://www.w3schools.com/jsref/prop_element_offsetheight.asp
The class in the querySelector should be overlay
var overlays = document.querySelectorAll('.overlay');
for (let overlay of overlays) {
console.log(overlay);
console.log(overlay.style.height);
}
.overlay:first-of-type {
color: red;
width: 100px;
height: 50px;
background: orange;
}
.overlay:nth-of-type(2) {
color: blue;
width: 100px;
height: 75px;
background: pink;
}
<div class='overlay'>
overlay 1
</div>
<div class='overlay'>
overlay 2
</div>
Try this:
var overlays = document.getElementsByClass('.overlay');
for (let overlay of overlays) {
console.log(overlay);
console.log(overlay.style.height);
}

Setting conditions for classList.toggle

I have a function that's triggered by onClick. Here's the example. I want to only be able to trigger the function 'slide1' when 'slide2' is not triggered. I tried setting up a conditional statement like this:
function slide1() {
btn1.classList.toggle('slide', btn2.className != 'slide');
}
I also tried an if statement like this:
function slide1() {
if(btn2.className != 'slide') {
btn1.classList.toggle('slide');
}
}
That didn't work either.
I just need a simple way to toggle classes if certain conditions are met; without jQuery or a library. Thanks.
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
function slide1() {
btn1.classList.toggle('slide');
}
function slide2() {
btn2.classList.toggle('slide');
}
* {
margin: 0;
transition: 1s ease;
-webkit-transition: 1s ease;
}
div {
width: 50%;
height: 100vh;
display: block;
position: absolute;
text-align: center;
cursor: pointer;
}
#btn1 {
background: blue;
}
#btn2 {
background: red;
left: 50%;
}
#btn1.slide {
width: 80%;
z-index: 999;
}
#btn2.slide {
width: 80%;
z-index: 999;
left: 20%;
}
<div id="btn1" onClick="slide1();">
left
</div>
<div id="btn2" onClick="slide2();">
right
</div>
UPDATE: Here is an expanded example of the problem I'm dealing with. There are several elements with classes that need to be toggled only under certain circumstances. If 'panel1' is triggered when 'panel2' has already been triggered, then 'panel1' will cover 'panel2'. and the same with 'panel3'.
To answer your question, the proper way to check if an element has a class in JavaScript is element.classList.contains.
So, in your example, you should replace the condition with
if(btn2.className.contains('slide')) {
...
}
As a sidenote, having different functions doing the exact same thing on different elements should be avoided, where possible. Instead of having two functions, you should have only one and use the click event's target:
let halves = document.querySelectorAll("div");
function slide(event) {
// remove `slide` class from both divs:
[].map.call(halves, function(half){
half.classList.remove('slide');
});
// add `slide` class to currently clicked div:
event.target.classList.add('slide')
}
* {
margin: 0;
transition: 1s ease;
-webkit-transition: 1s ease;
}
div {
width: 50%;
height: 100vh;
display: block;
position: absolute;
text-align: center;
cursor: pointer;
}
#btn1 {
background: blue;
}
#btn2 {
background: red;
left: 50%;
}
#btn1.slide {
width: 80%;
z-index: 999;
}
#btn2.slide {
width: 80%;
z-index: 999;
left: 20%;
}
<div id="btn1" onClick="slide(event);">
left
</div>
<div id="btn2" onClick="slide(event);">
right
</div>
On a different note, I assume you're aware the selectors used in both your question and my answer are outrageously generic and should never be used in production ready code.
And as a last note, your CSS is quite faulty but I'm not considering fixing it here, as it wouldn't help anyone except yourself, which goes against the first principle of SO: one answer should help multiple users having the same problem. Here's how I'd have coded your example:
let br = document.querySelector('#blueRed');
br.addEventListener('click', function(event) {
event.target.classList.toggle('slide');
[].map.call(br.querySelectorAll('div'), function(div) {
if (div !== event.target) {
div.classList.remove('slide');
}
});
})
body {
margin: 0;
}
#blueRed {
height: 100vh;
display: flex;
}
#blueRed div {
text-align: center;
display: flex;
align-items: center;
justify-content: center;
transition: flex-grow 1s cubic-bezier(0.4, 0, 0.2, 1);
flex-grow: 1;
background-color: blue;
color: white;
cursor: pointer;
}
#blueRed div:last-child {
background-color: red;
}
#blueRed div.slide {
flex-grow: 3;
}
<div id="blueRed">
<div>left</div>
<div>right</div>
</div>
Fiddle here. Should be prefixed.
I think I understand your objective...
I condensed the functions into one and start off one button with the className = 'slide'. If one button is clicked then the class slide always alternates between the two buttons.
Demo
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
function slide() {
btn1.classList.toggle('slide');
btn2.classList.toggle('slide');
}
* {
margin: 0;
transition: 1s ease;
-webkit-transition: 1s ease;
}
div {
width: 50%;
height: 100vh;
display: block;
position: absolute;
text-align: center;
cursor: pointer;
}
#btn1 {
background: blue;
}
#btn2 {
background: red;
left: 50%;
}
#btn1.slide {
width: 80%;
z-index: 999;
}
#btn2.slide {
width: 80%;
z-index: 999;
left: 20%;
}
<div id="btn1" onClick="slide();" class='slide'>
left
</div>
<div id="btn2" onClick="slide();">
right
</div>

Using .css("background-color") for comparison jQuery/Js

I am working on a project to make angled divs where the break between each basic panel on a page is an angle if the div has a background-image on the previous div, and a background-color of green on the next div.
I know I can't select pseudo classes directly so I decided to use the .addClass() to show and hide the angle.
The problem is my comparisons either turn all divs green, or adds angles to all the divs. I think most of my problem is in my approach, but I'm not sure where I am going wrong.
Here is the JS and the jQuery so far, I'm just trying to make the comparison work so it is still rough:
$(function() {
green = $('div').css("background-color", "rgb(0,255,0)");
if ($('.box').prev() === green)
{
$(this).addClass('withTop withoutTop');
//if ($(this).css("background-color") == green)
}
});
I have used regex to strip all but digits from the rgb but it seems to have the same effect. Thanks in advance and here is the link to the codepen.
http://codepen.io/AnomalousDevs/pen/GJmrrw
CSS and markup
$(function() {
green = $('div').css("background-color", "rgb(0,255,0)");
if ($('.box').prev() === green) {
$(this).addClass('withTop withoutTop');
//if ($(this).css("background-color") == green)
}
});
.box {
height: 100px;
width: 100%;
/*background-color: rgb(0,255,0);*/
position: relative;
}
.box:nth-of-type(5) {
background-color: green;
/* background-image:url("http://www.google.com/imgres?imgurl=http://dreamatico.com/data_images/guitar/guitar-6.jpg&imgrefurl=http://dreamatico.com/guitar.html&h=851&w=1280&tbnid=DVUGPDoyiOu4sM:&zoom=1&docid=OlLKDKDUUigDoM&hl=en&ei=iqJzVcaEOcvAtQXW-oO4Cw&tbm=isch&ved=0CDwQMygKMAo");*/
}
.box:nth-of-type(4) {
background: red;
position: relative;
}
.box:nth-of-type(3) {
background: blue;
}
.box:nth-of-type(2) {
background: rgb(0, 255, 0);
}
.box:nth-of-type(1) {
background: lightblue;
}
.withTop::before {
content: '';
position: absolute;
background: black;
width: 100%;
/*top:-16px;*/
height: 30px;
left: 0;
transform: skewY(-1.3Deg);
z-index: 1;
}
.withoutTop::after {
content: '';
position: absolute;
background: black;
width: 100%;
height: 30px;
left: 0;
transform: skewY(2Deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="parent">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box withTop"></div>
</section>
Your question is not clear but I think that what you are trying to achieve is adding a class to the .box after the green one.
Suggestion of base logic you should do:
$(function() {
var boxes = $('.box'),
greenBox = '';
//for each box
boxes.each(function(index) {
//if this box is the green one
if ($(this).css("background-color") === "rgb(0, 255, 0)") {
greenBox = $(this);
//addClass to the next one
$(this).next().addClass('withTop');
}
});
});
.box {
height: 100px;
width: 100%;
/*background-color: rgb(0,255,0);*/
position: relative;
}
.box:nth-of-type(5) {
background-color: green;
/* background-image:url("http://www.google.com/imgres?imgurl=http://dreamatico.com/data_images/guitar/guitar-6.jpg&imgrefurl=http://dreamatico.com/guitar.html&h=851&w=1280&tbnid=DVUGPDoyiOu4sM:&zoom=1&docid=OlLKDKDUUigDoM&hl=en&ei=iqJzVcaEOcvAtQXW-oO4Cw&tbm=isch&ved=0CDwQMygKMAo");*/
}
.box:nth-of-type(4) {
background: red;
position: relative;
}
.box:nth-of-type(3) {
background: blue;
}
.box:nth-of-type(2) {
background: rgb(0, 255, 0);
}
.box:nth-of-type(1) {
background: lightblue;
}
.withTop::before {
content: '';
position: absolute;
background: black;
width: 100%;
/*top:-16px;*/
height: 30px;
left: 0;
transform: skewY(-1.3Deg);
z-index: 1;
}
.withoutTop::after {
content: '';
position: absolute;
background: black;
width: 100%;
height: 30px;
left: 0;
transform: skewY(2Deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="parent">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box withTop"></div>
</section>

Categories