How to close a drop-down while opening another? - javascript

I am new to javascript, I need help with my code.
I have two dropdowns that hold a a button and a container with links. How do I make one dropdown close while I open the other?
I have tried comparing the giving them different ids and comparing them but I am not sure I got that right.
// achieve effect
// event delegation on body
let activeDropDown;
document.body.addEventListener('click', dropDown);
// event function for toggling class
function dropDown(ex) {
// if (activeDropDown.id && activeDropDown.id !== ex.target.id) {
// activeDropDown.nextElementSibling.classList.toggle('shower');
// }
if(ex.target.parentElement.classList.contains('am')) {
let val;
activeDropDown = ex.target.parentElement.id;
activeDropDown.element = ex.target.parentElement;
val = activeDropDown;
ex.target.nextElementSibling.classList.toggle('shower');
console.log(val);
}
}
// close the dropdown if the user click outside the button
window.addEventListener('click', closeDropDown);
// declaring the function
function closeDropDown(ex2) {
if (!ex2.target.matches('.arch-button')) {
// getting the dropdowncontent
let postDrop = document.querySelectorAll('.monthly-post');
// var i;
for (let i = 0; i < postDrop.length; i++) {
let checkDropDown = postDrop[i];
if (checkDropDown.classList.contains('shower')) {
checkDropDown.classList.remove('shower');
}
}
}
};
.am:not(:last-child) {
border-bottom: 0.5px solid #C8C8C8;
}
.am:not(:first-child) {
margin-top: 12px;
}
.monthly-post {
position: relative;
left: 17px;
overflow: hidden;
height: 0;
}
.shower{
overflow: visible !important;
max-height: 100% !important;
height: 100% !important;
transition: all ease-in-out 500ms;
-webkit-transition: all ease-in-out 500ms;
-moz-transition: all ease-in-out 500ms;
-ms-transition: all ease-in-out 500ms;
-o-transition: all ease-in-out 500ms;
}
.post-linker {
display: block;
color: #0069E6;
}
.post-linker:hover,
.post-linker:active{
color: #21293C;
}
<div class="am" id="am-march">
<button class="arch-button">March 2019</button>
<div class="monthly-post">
TEF Application 2019
Big Brother 2019
Hotelo new Application for guest
Air peace easter promo
</div>
</div>
<div class="am" id="am-april">
<button class="arch-button">April 2019</button>
<div class="monthly-post">
ahahahah
ahahahah
ahahaha
ahahahahha
</div>
</div>
I want the dropdrop to close while I open another dropdown.

You can use event.path or event.composedPath to check the element is different, and close other drop-downs.

Consume closeDropDown(); from dropDown() and remove click handlers.
let activeDropDown;
document.body.addEventListener('click', dropDown);
function dropDown(ex) {
closeDropDown();
if (ex.target.parentElement.classList.contains('am')) {
let val;
activeDropDown = ex.target.parentElement.id;
activeDropDown.element = ex.target.parentElement;
val = activeDropDown;
ex.target.nextElementSibling.classList.toggle('shower');
console.log(val);
}
}
function closeDropDown() {
let postDrop = document.querySelectorAll('.monthly-post');
for (let i = 0; i < postDrop.length; i++) {
let checkDropDown = postDrop[i];
if (checkDropDown.classList.contains('shower')) {
checkDropDown.classList.remove('shower');
}
}
};
.am:not(:last-child) {
border-bottom: 0.5px solid #C8C8C8;
}
.am:not(:first-child) {
margin-top: 12px;
}
.monthly-post {
position: relative;
left: 17px;
overflow: hidden;
height: 0;
}
.shower {
overflow: visible !important;
max-height: 100% !important;
height: 100% !important;
transition: all ease-in-out 500ms;
-webkit-transition: all ease-in-out 500ms;
-moz-transition: all ease-in-out 500ms;
-ms-transition: all ease-in-out 500ms;
-o-transition: all ease-in-out 500ms;
}
.post-linker {
display: block;
color: #0069E6;
}
.post-linker:hover,
.post-linker:active {
color: #21293C;
}
<div class="am" id="am-march">
<button class="arch-button">March 2019</button>
<div class="monthly-post">
TEF Application 2019
Big Brother 2019
Hotelo new Application for guest
Air peace easter promo
</div>
</div>
<div class="am" id="am-april">
<button class="arch-button">April 2019</button>
<div class="monthly-post">
ahahahah
ahahahah
ahahaha
ahahahahha
</div>
</div>

Related

How can I get each of my modals to show correctly?

I know this code won't work in the current state because it will just select the first modal class. I have tried many variations of using querySelectorAll and forEach loops in the functions and event listeners but I can't seem to get it right.
How can I convert the current code to work with the different project card modals?
// Project card modals
const modal = document.querySelector('.modal')
const trigger = document.querySelector('.trigger')
const closeButton = document.querySelector('.close-button')
const body = document.querySelector('body')
function toggleModal() {
modal.classList.toggle('show-modal')
showModal()
}
function windowOnClick(event) {
if (this.event.target === modal) {
toggleModal()
showModal()
}
}
trigger.addEventListener('click', toggleModal)
closeButton.addEventListener('click', toggleModal)
window.addEventListener('click', windowOnClick)
// Disable body scroll with modal open
const showModal = function (e) {
if (modal.classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
<div class="projects-container">
<div class="projects-grid">
<div class="project-cell">
<div class="project-tile trigger">
<img Card Image />
</div>
<div class="modal">
<div class="modal-content">
<div class="close-button">×</div>
Modal Content
</div>
</div>
</div>
</div>
</div>
.modal {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(68, 71, 90, 0.8);
backdrop-filter: blur(20px) saturate(180%);
opacity: 0;
visibility: hidden;
transform: scale(1.1);
transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
z-index: 5;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 1rem 2rem;
width: 70%;
background-color: rgb(40, 42, 54, 0.8);
border-radius: 5px;
backdrop-filter: blur(20px) saturate(180%);
border: 2px solid transparent;
box-shadow: 0 0 5px 1px var(--dracula-background);
}
.close-button {
width: 1.5rem;
line-height: 1.5rem;
text-align: center;
border-radius: 3px;
color: black;
font-weight: 500;
background-color: rgba(255, 85, 85, 0.7);
cursor: url('../assets/images/icons/cursor-hand-white.png'), auto;
position: absolute;
right: 0;
top: 0;
transition: ease all 0.1s;
}
.show-modal {
opacity: 1;
visibility: visible;
transform: scale(1);
transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
You can use unique id attributes on your modal elements to differentiate them, and then use data attributes to target modals.
// Project card modals
const body = document.querySelector('body')
function toggleModal(modal) {
modal.classList.toggle('show-modal')
showModal(modal)
}
document.addEventListener('click', function(event) {
if (event.target.classList.contains('modal')) {
toggleModal(event.target)
showModal(event.target)
} else if (event.target.classList.contains('trigger')) {
toggleModal(document.getElementById(event.target.getAttribute('data-target')))
} else if (event.target.classList.contains('close-button')) {
toggleModal(document.getElementById(event.target.getAttribute('data-target')))
}
})
// Disable body scroll with modal open
const showModal = function(modal) {
if (modal.classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
.modal {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(68, 71, 90, 0.8);
backdrop-filter: blur(20px) saturate(180%);
opacity: 0;
visibility: hidden;
transform: scale(1.1);
transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
z-index: 5;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 1rem 2rem;
width: 70%;
background-color: rgb(40, 42, 54, 0.8);
border-radius: 5px;
backdrop-filter: blur(20px) saturate(180%);
border: 2px solid transparent;
box-shadow: 0 0 5px 1px var(--dracula-background);
}
.close-button {
width: 1.5rem;
line-height: 1.5rem;
text-align: center;
border-radius: 3px;
color: black;
font-weight: 500;
background-color: rgba(255, 85, 85, 0.7);
position: absolute;
right: 0;
top: 0;
transition: ease all 0.1s;
}
.show-modal {
opacity: 1;
visibility: visible;
transform: scale(1);
transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
<div class="projects-container">
<div class="projects-grid">
<div class="project-cell">
<div class="project-tile trigger" data-target="modal1">
<img Card Image /> trigger1
</div>
<div class="modal" id="modal1">
<div class="modal-content">
<div class="close-button" data-target="modal1">×</div>
Modal Content 1
</div>
</div>
</div>
<div class="project-cell">
<div class="project-tile trigger" data-target="modal2">
<img Card Image /> trigger2
</div>
<div class="modal" id="modal2">
<div class="modal-content">
<div class="close-button" data-target="modal2">×</div>
Modal Content 2
</div>
</div>
</div>
<div class="project-cell">
<div class="project-tile trigger" data-target="modal3">
<img Card Image /> trigger3
</div>
<div class="modal" id="modal3">
<div class="modal-content">
<div class="close-button" data-target="modal3">×</div>
Modal Content 3
</div>
</div>
</div>
</div>
</div>
I can definitely refactor this, but I was able to get it working by using the IDs. I also had to switch the querySelectorAll to getElementsByClassName because querySelectorAll will return a static collection, while getElementsByClassName returns a live collection.
// Project card modals
const body = document.querySelector('body')
const modal = document.getElementsByClassName('modal')
const trigger = document.getElementsByClassName('trigger')
const closeButton = document.getElementsByClassName('close-button')
// When the user clicks the project image, open the modal
trigger[0].onclick = function () {
modal[0].classList.toggle('show-modal')
if (modal[0].classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
trigger[1].onclick = function () {
modal[1].classList.toggle('show-modal')
if (modal[1].classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
trigger[2].onclick = function () {
modal[2].classList.toggle('show-modal')
if (modal[2].classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
trigger[3].onclick = function () {
modal[3].classList.toggle('show-modal')
if (modal[3].classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
// When the user clicks on (x), close the modal
closeButton[0].onclick = function () {
modal[0].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
closeButton[1].onclick = function () {
modal[1].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
closeButton[2].onclick = function () {
modal[2].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
closeButton[3].onclick = function () {
modal[3].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function (event) {
if (event.target == modal[0]) {
modal[0].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
if (event.target == modal[1]) {
modal[1].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
if (event.target == modal[2]) {
modal[2].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
if (event.target == modal[3]) {
modal[3].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
}

How to make a created div in Javascript fade in and fade out?

I'm making a website with a 'like' function and if you click the like icon it should make div as a alert at the bottom of the website. The code that I wrote makes the div fade in and after a few seconds the pop up fades out. Then after the fade out the pop up just shows up again on the screen, but stuck this time. I'm learning Javascript so it is new to me so anything would be appreciated.
function myFunction() {
var test = document.querySelector('#color');
var x = document.createElement('div');
if(test.style.color == ""){
test.style.color = "red";
x.innerHTML ='Liked this tournament!';
x.id = "snackbar";
x.className = "show";
} else{
test.style.color = "";
x.innerHTML('Removed like from this tournament!');
x.id = "snackbar";
x.className = "show";
}
document.body.appendChild(x);
}
#snackbar {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 1;
left: 10%;
bottom: 30px;
font-size: 17px;
}
#snackbar.show {
visibility: visible;
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
animation: fadein 0.5s, fadeout 0.5s 2.5s;
}
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
<ul>
<li onclick="myFunction();"><i id="color" class="fas fa-heart"></i></li>
<li><i class="fas fa-plus"></i></li>
<li><i class="fas fa-expand"></i></li>
</ul>
I think it's maybe because of the document.body.appendChild(x); overwriting the css? I'm not sure what's happening..
A short video about the pop up: https://imgur.com/a/KfD7hNW
I'm not sure if you forgot to copy a portion of your CSS but you don't seem to have any actual animations. If you want those effects you can use the CSS that https://animate.style/ provides either by importing it or extracting it from their GitHub files if you just want the two animations. But if you're going to use the animation attribute, you need some kind of keyframe animation built out otherwise nothing is going to happen. The forwards value lets the animations play and then doesn't repeat them so it's not flashing after the user clicks the button.
Also, you had some broken JS but that was a simple mistake.
Worth reading: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations so you can see how all of the attributes can be animated and controlled
function myFunction() {
var test = document.querySelector('#color');
var x = document.createElement('div');
if(test.style.color == ""){
test.style.color = "red";
x.innerHTML ='Liked this tournament!';
x.id = "snackbar";
x.className = "show";
} else{
test.style.color = "";
x.innerHTML='Removed like from this tournament!'
x.id = "snackbar";
x.className = "show";
}
document.body.appendChild(x);
}
#snackbar {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 1;
left: 10%;
bottom: 30px;
font-size: 17px;
}
#snackbar.show {
visibility: visible;
animation: fadeIn 0.5s, fadeOut 0.5s 2.5s forwards;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.fadeOut {
animation-name: fadeOut;
}
.fadeIn {
animation-name: fadeIn;
}
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
<ul>
<li onclick="myFunction();">click me<i id="color" class="fas fa-heart"></i></li>
<li>not me<i class="fas fa-plus"></i></li>
<li>or me<i class="fas fa-expand"></i></li>
</ul>
In your approach every time that you click your icon you will create a new div element in the same place, which will create tons of div.. This is not efficient. So you can try something like this.
After adding show class to your div element you can set a timer which will wait for animation happens. Then remove that class with
myDiv.classList.remove('show');
const test = document.querySelector('#color');
const myDiv = document.createElement('div');
myDiv.id = "snackbar";
document.body.appendChild(myDiv);
test.addEventListener('click',() =>{
if(test.style.color == ""){
test.style.color = "red";
myDiv.innerText ='Liked this tournament!';
myDiv.className = "show";
setTimeout(() =>{
myDiv.classList.remove('show');
}, 2000);
}
else{
test.style.color = "";
myDiv.innerText = 'Removed like from this tournament!';
myDiv.className = "show";
setTimeout(() =>{
myDiv.classList.remove('show');
}, 2000);
}
})
*,
*::before,
*::after {
box-sizing: border-box;
}
body{
min-height: 100vh;
overflow: hidden;
display: grid;
place-content: center;
margin:0;
background-color: bisque;
font-size: 100px;
}
#snackbar {
visibility: hidden;
min-width: 250px;
margin-left: -125px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 1;
left: 10%;
bottom: 30px;
font-size: 17px;
}
#snackbar.show {
visibility: visible;
animation: fadeIn 0.5s, fadeOut 0.5s 1s forwards;
}
#keyframes fadeIn {
0%{
opacity:0;
}
100%{
opacity: 1;
}
}
#keyframes fadeOut {
0%{
opacity:1;
}
100%{
opacity: 0;
}
}
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
<ul>
<li>click me<i id="color" class="fas fa-heart"></i></li>
<li>not me<i class="fas fa-plus"></i></li>
<li>or me<i class="fas fa-expand"></i></li>
</ul>

CSS: Smooth transition between elements in an array

I have this array:
myArr = [1, 2, 3, 4]
The first element in this array is displayed on the screen.
There are two buttons (left and right). They fire functions that move the elements in the array forward or backward:
shiftLeft() {
var firstElement = myArr.shift()
myArr.push(firstElement)
}
Resulting in: myArr = [2, 3, 4, 1] and now element 2 shows up on the screen.
The unfortunate side affect of this method is that it is difficult to animate the transition for the old element to the new one.
I tried to use keyframes but the animation is not as smooth (and I lack experience).
You can find a generic version of my setup here: https://codepen.io/riza-khan/pen/KKVyaaR
Results I am looking for:
A smooth transition from the first to the second element. Much like any generic carousels from (pick your favorite CSS framework).
Happy to provide additional information should it be required.
Thank you,
You could have an overlay layer that is spawning and removing nodes to trigger the animation, and a setTimer to change the underlay value after the animation completes.
Note: Stack Overflow snippets do not currently support scss, instead see my codepen here.
const arr = [1, 2, 3, 4];
const left = document.querySelector(".left");
const right = document.querySelector(".right");
const container = document.querySelector(".container");
const overlay = document.querySelector("#overlay");
let prevEle = document.querySelector(".number");
let disabled = false;
left.addEventListener("click", function() {
if (disabled) return;
movement("left", arr);
});
right.addEventListener("click", function() {
if (disabled) return;
movement("right", arr);
});
// document.addEventListener("DOMContentLoaded", function () {
// setupUI();
// });
function createNew() {
let ele = document.createElement("div");
ele.classList.add("number");
ele.classList.add("fadeIn");
ele.innerText = arr[0];
return ele;
}
function setupUI() {
disabled = true;
let newEle = createNew();
overlay.removeChild(overlay.firstChild);
overlay.prepend(newEle);
setTimeout(() => disabled = false, 350);
setTimeout(() => prevEle.innerText = arr[0], 350);
}
function movement(direction, array) {
if (direction === "right") {
var element = array.shift();
array.push(element);
} else {
var element = array.pop();
array.unshift(element);
}
setupUI();
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
height: 100vh;
background: rgb(250,175,170);
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 2fr 1fr;
.number {
grid-column: 1 / -1;
cursor: default;
}
.fadeIn {
animation: fadeIn ease .5s;
-webkit-animation: fadeIn ease .5s;
-moz-animation: fadeIn ease .5s;
-o-animation: fadeIn ease .5s;
-ms-animation: fadeIn ease .5s;
}
#keyframes fadeIn {
0% {opacity:0;}
100% {opacity:1;}
}
}
.overlay {
position: absolute;
width: 100vw;
height: 100vh;
pointer-events: none;
.number {
background: rgb(250,175,170);
}
.container{
background: transparent;
}
}
.number {
margin: auto;
font-size: 25em;
}
.btn {
margin: auto;
border: solid 2px black;
padding: 1em 2em;
border-radius: 5px;
transition: all 0.5s ease;
cursor: pointer;
&:hover {
background: black;
color: white;
}
}
<div class="overlay">
<div class="overlay container" id="overlay">
</div>
</div>
<div class="container">
<div class="number">1</div>
<button class="btn left">Left</button>
<button class="btn right">Right</button>
</div>

How to darken an image completely?

I want to darken an image, but it isn't fully black in the end, because I can see the image some extent. I want to use vanilla JS only (no jQuery).
I have used a color array (colorArr), but I think there are much more elegant ways for darkening.
var element = document.getElementById("img");
var colorArr = ["#fff","#ddd","#bbb","#999","#777","#555","#333","#000",];
var counter = 0;
var j=0;
var i = setInterval(function(){
if(j < colorArr.length){
element.style.backgroundColor = colorArr[j];
j++;
}
counter++;
if(counter === 8) {
clearInterval(i);
}
}, 250);
div.darken img {
background-color: white;
}
<html>
<body>
<div class="darken">
<img id="img"
src="http://davidrhysthomas.co.uk/linked/astrid_avatar2.png" />
</div>
</body>
</html>
I'll do it using CSS and JavaScript.
window.onload = function () {
document.getElementById("mask").classList.add("on");
};
.dark-img {display: inline-block; position: relative;}
.dark-img .mask {position: absolute; left: 0; top: 0; bottom: 0; right: 0; z-index: 1; opacity: 0; background-color: #000; transition: opacity 2.5s linear;}
.dark-img .mask.on {opacity: 1;}
<div class="dark-img">
<div class="mask" id="mask"></div>
<img src="http://davidrhysthomas.co.uk/linked/astrid_avatar2.png" alt="" />
</div>
This technique allows me to use any colour and duration. Let's say orange for 1.5 seconds:
window.onload = function () {
document.getElementById("mask").classList.add("on");
};
.dark-img {display: inline-block; position: relative;}
.dark-img .mask {position: absolute; left: 0; top: 0; bottom: 0; right: 0; z-index: 1; opacity: 0; background-color: #f90; transition: opacity 1.5s linear;}
.dark-img .mask.on {opacity: 1;}
<div class="dark-img">
<div class="mask" id="mask"></div>
<img src="http://davidrhysthomas.co.uk/linked/astrid_avatar2.png" alt="" />
</div>
This is a CSS only solution!
a.darken {
display: inline-block;
background: black;
padding: 0;
}
a.darken img {
display: block;
-webkit-transition: all 0.5s linear;
-moz-transition: all 0.5s linear;
-ms-transition: all 0.5s linear;
-o-transition: all 0.5s linear;
transition: all 0.5s linear;
}
a.darken:hover img {
opacity: 0;
}
<a href="http://google.com" class="darken">
<img src="http://www.placehold.it/200x200" width="200">
</a>
You can use Web Animations API, Promise.all() to animate the background-color of <img> .parentElement from #fff to #000 and animate <img> element opacity to 0 in parallel.
const element = document.getElementById("img");
element.parentElement.style.width = `${element.naturalWidth}px`;
const button = document.querySelector("button");
const colorArr = ["#fff", "#ddd", "#bbb", "#999", "#777", "#555", "#333", "#000"];
const settings = {
easing: "linear",
fill: "forwards",
duration: 2500,
iterations: 1
};
button.onclick = () =>
Promise.all([element.parentElement.animate(colorArr.map(color => ({
backgroundColor: color
})), settings)
, element.animate([{opacity: 0}],
settings)]);
div.darken img {
background-color: white;
position: relative;
opacity: 1;
}
<html>
<body>
<button>click</button>
<div class="darken">
<img id="img" src="http://davidrhysthomas.co.uk/linked/astrid_avatar2.png" />
</div>
</body>
</html>
Use a pseudo element and keep the markup as is, add a CSS transition and then fire it with a hover or script, which ever suit best
window.addEventListener('load', function(){
document.querySelector('button').addEventListener('click', function (){
document.querySelector('.darken').classList.toggle('on');
})
})
div.darken img {
background-color: white;
}
div.darken {
display: inline-block;
position: relative;
}
div.darken::after {
content: '';
position: absolute;
top: 0; left: 0;
bottom: 0; right: 0;
background: black;
opacity: 0;
transition: opacity 1s;
}
div.darken:hover::after {
opacity: 1;
}
div.darken.on::after {
opacity: 1;
background: lightgray;
}
#keyframes darken {
0% { opacity: 0; }
100% { opacity: 1; }
}
<html>
<body>
<button>Click here (or hover image) to toggle darken</button><br>
<div class="darken">
<img id="img"
src="http://davidrhysthomas.co.uk/linked/astrid_avatar2.png" />
</div>
</body>
</html>

JavaScript - add transition between display:none and display:block

I am using JavaScript to toggle notification like below.
How can I add transition between display: block and display: none;
I don't want to add an external library like jQuery because I am only going to be using the toggle effect alone.
var btn = document.querySelector('button');
btn.addEventListener('click', function(){
var hint = document.getElementById('hint');
if(hint.style.display == 'none'){
hint.style.display = 'block';
}
else{
hint.style.display = 'none';
}
});
div#hint{
background: gold;
color: orangered;
padding: .5em;
font-weight: bold;
}
<div id='hint'>
<p>This is some hint on how to be safe in this community </p>
<p>This is another hint on how to be safe in this community </p>
</div>
<button> show hint </button>
I know I can use jQuery to achieve this like below.
$(document).ready(function(){
$('button').click(function(){
$('#hint').toggle('slow');
});
});
div#hint{
background: gold;
color: orangered;
padding: .5em;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='hint'>
<p>This is some hint on how to be safe in this community </p>
<p>This is another hint on how to be safe in this community </p>
</div>
<button> show hint </button>
Can I make the button moves up and down gradually while the #hint is being toggle like in the jQuery example above? I don't want the button to jump from one position to another.
#vothaison's suggestion: CSS transitions
Technically, #vothaison wanted to use setInterval as opposed to setTimeout, but I don't see the need for that. It's just more work.
var hint = document.getElementById('hint');
var btn = document.getElementById('btn_show');
btn.addEventListener('click', function(){
var ctr = 1;
hint.className = hint.className !== 'show' ? 'show' : 'hide';
if (hint.className === 'show') {
hint.style.display = 'block';
window.setTimeout(function(){
hint.style.opacity = 1;
hint.style.transform = 'scale(1)';
},0);
}
if (hint.className === 'hide') {
hint.style.opacity = 0;
hint.style.transform = 'scale(0)';
window.setTimeout(function(){
hint.style.display = 'none';
},700); // timed to match animation-duration
}
});
#hint {
background: yellow;
color: red;
padding: 16px;
margin-bottom: 10px;
opacity: 0;
transform: scale(0);
transition: .6s ease opacity,.6s ease transform;
}
<div id="hint" style="display: none;">
<p>This is some hint on how to be safe in this community </p>
<p>This is another hint on how to be safe in this community </p>
</div>
<button id="btn_show"> Show hint </button>
Using CSS animations
var hint = document.getElementById('hint');
var btn = document.getElementById('btn_show');
btn.addEventListener('click', function(){
hint.className = hint.className !== 'show' ? 'show' : 'hide';
if (hint.className === 'show') {
setTimeout(function(){
hint.style.display = 'block';
},0); // timed to occur immediately
}
if (hint.className === 'hide') {
setTimeout(function(){
hint.style.display = 'none';
},700); // timed to match animation-duration
}
});
#-webkit-keyframes in {
0% { -webkit-transform: scale(0) rotate(12deg); opacity: 0; visibility: hidden; }
100% { -webkit-transform: scale(1) rotate(0); opacity: 1; visibility: visible; }
}
#keyframes in {
0% { transform: scale(0) rotate(12deg); opacity: 0; visibility: hidden; }
100% { transform: scale(1) rotate(0); opacity: 1; visibility: visible; }
}
#-webkit-keyframes out {
0% { -webkit-transform: scale(1) rotate(0); opacity: 1; visibility: visible; }
100% { -webkit-transform: scale(0) rotate(-12deg); opacity: 0; visibility: hidden; }
}
#keyframes out {
0% { transform: scale(1) rotate(0); opacity: 1; visibility: visible; }
100% { transform: scale(0) rotate(-12deg); opacity: 0; visibility: hidden; }
}
#hint {
background: yellow;
color: red;
padding: 16px;
margin-bottom: 10px;
}
#hint.show {
-webkit-animation: in 700ms ease both;
animation: in 700ms ease both;
}
#hint.hide {
-webkit-animation: out 700ms ease both;
animation: out 700ms ease both;
}
<div id="hint" style="display: none;">
<p>This is some hint on how to be safe in this community </p>
<p>This is another hint on how to be safe in this community </p>
</div>
<button id="btn_show"> Show hint </button>
Using vanilla JavaScript
There are many, many ways to do this sort of thing with vanilla JavaScript, so here's a quick sketch of one way:
// you may need to polyfill requestAnimationFrame
var hint = document.getElementById('hint');
var btn = document.getElementById('btn_show');
btn.addEventListener('click', function(){
var ctr = 0;
hint.className = hint.className !== 'show' ? 'show' : 'hide';
if (hint.className === 'show') {
window.setTimeout(function(){
hint.style.display = 'block';
fadein();
},0); // do this asap
}
if (hint.className === 'hide') {
fadeout();
window.setTimeout(function(){
hint.style.display = 'none';
},700); // time this to fit the animation
}
function fadein(){
hint.style.opacity = ctr !== 10 ? '0.'+ctr : 1;
hint.style.transform = ctr !== 10 ? 'scale('+('0.'+ctr)+')' : 'scale(1)';
ctr++;
if (ctr < 11)
requestAnimationFrame(fadein);
else
ctr = 0;
}
function fadeout(){
hint.style.opacity = 1 - ('0.'+ctr);
hint.style.transform = 'scale('+(1 - ('0.'+ctr))+')';
ctr++;
if (ctr < 10)
requestAnimationFrame(fadeout);
else
ctr = 0;
}
});
#hint {
background: yellow;
color: red;
padding: 16px;
margin-bottom: 10px;
opacity: 0;
}
<div id="hint" style="display: none;">
<p>This is some hint on how to be safe in this community </p>
<p>This is another hint on how to be safe in this community </p>
</div>
<button id="btn_show"> Show hint </button>
Say what you want about GreenSock, Velocity.js, jQuery, etc — they all trivialise this process of showing and hiding of things. Why not just borrow the show and hide functions from jQuery's source code?
see my example below:
var btn = document.querySelector('button');
var hint = document.getElementById('hint');
var height = hint.clientHeight;
var width = hint.clientWidth;
console.log(width + 'x' + height);
// initialize them (within hint.style)
hint.style.height = height + 'px';
hint.style.width = width + 'px';
btn.addEventListener('click', function(){
if(hint.style.visibility == 'hidden'){
hint.style.visibility = 'visible';
//hint.style.opacity = '1';
hint.style.height = height + 'px';
hint.style.width = width + 'px';
hint.style.padding = '.5em';
}
else{
hint.style.visibility = 'hidden';
//hint.style.opacity = '0';
hint.style.height = '0';
hint.style.width = '0';
hint.style.padding = '0';
}
});
div#hint{
background: gold;
color: orangered;
padding: .5em;
box-sizing: border-box;
overflow: hidden;
font-weight: bold;
transition: height 1s, width 1s, padding 1s, visibility 1s, opacity 0.5s ease-out;
}
<div id='hint'>
<p>This is some hint on how to be safe in this community </p>
<p>This is another hint on how to be safe in this community </p>
</div>
<button> show hint </button>
Hi I dont use display: block to display:none but changing the opacity, height and padding instead
please review this one:
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
var hint = document.getElementById('hint');
if (hint.classList.contains('h-hide')) {
hint.classList.remove('h-hide');
} else {
hint.classList.add('h-hide');
}
});
div#hint {
display: block;
background: gold;
color: orangered;
padding: .5em;
font-weight: bold;
transition: .5s all linear;
opacity: 1;
overflow: hidden;
height: 100px;
}
#hint.h-hide {
padding: 0;
opacity: .25;
height: 0;
}
<div id='hint'>
<p>This is some hint on how to be safe in this community</p>
<p>This is another hint on how to be safe in this community</p>
</div>
<button>show hint</button>
the drawback for this approach is we have to keep tract of the div#hint height and change it using javascript if needed.
var btn = document.querySelector('button');
btn.addEventListener('click', function(){
var hint = document.getElementById('hint');
if(hint.style.visibility == 'hidden'){
hint.style.visibility = 'visible';
hint.style.opacity = '1';
}
else{
hint.style.visibility = 'hidden';
hint.style.opacity = '0';
}
});
div#hint{
background: gold;
color: orangered;
padding: .5em;
font-weight: bold;
transition: visibility 1s, opacity 0.5s linear;
}
<div id='hint'>
<p>This is some hint on how to be safe in this community </p>
<p>This is another hint on how to be safe in this community </p>
</div>
<button> show hint </button>
I think using visibility over display is better option
Without using css3 transition, you can use js setInterval to change some css property of the div, such as:
Change opacity from 0 to 1
Change height from 0 to full height
Change width from 0 to full width
Initially, you should have display: none; opacity: 0; height: 0; width: 0'
Then you have to change display: none to display: block; before you use setInterval to change other properties.
(I guess you know how to hide the div)
You can also use setTimeout(), with a trick of recursive.
Try something like this:
var btn = document.querySelector('button');
btn.addEventListener('click', function(){
var hint = document.getElementById('hint');
hint.classList.toggle("hide");
});
.hint{
background: gold;
color: orangered;
padding: .5em;
font-weight: bold;
visibility: visible;
opacity: 1;
max-height: 500px;
transition: visibility 0s, opacity 0.3s, max-height 0.6s linear;
}
.hide {
visibility: hidden;
opacity: 0;
max-height: 0px;
transition: max-height 0.3s, opacity 0.3s, visibility 0.3s linear;
}
<div id='hint' class="hint">
<p>This is some hint on how to be safe in this community </p>
<p>This is another hint on how to be safe in this community </p>
</div>
<button> show hint </button>
I have also tried to do this
please have a look if it can help you
var btn = document.querySelector('button');
var hint = document.getElementById('hint');
hint.style.opacity = 1;
hint.style.transition = "opacity 1s";
btn.addEventListener('click', function(){
if(hint.style.opacity == 0 || hint.style.opacity==''){
hint.style.opacity = 1;
}
else{
hint.style.opacity = 0;
}
});
let redBox = document.getElementById('redBox');
let blueBox = document.getElementById('blueBox');
let [redButton, blueButton] = document.querySelectorAll('button'); //Destructuring
redButton.addEventListener('click', () => {
smoothDisplayNone(redBox);
});
blueButton.addEventListener('click', () => {
smoothDisplayNone(blueBox);
});
//By using smoothDisplayNone() function, you can add this effect to whatever element you want.
function smoothDisplayNone(selectedElement){
if(!selectedElement.classList.contains('animationDisplayNone')){
selectedElement.classList.add('animationDisplayNone');
selectedElement.classList.remove('animationDisplayBlock');
}
else{
selectedElement.classList.remove('animationDisplayNone');
selectedElement.classList.add('animationDisplayBlock');
}
}
#redBox{
width: 200px;
height: 200px;
background-color: red;
}
#blueBox{
width: 200px;
height: 200px;
background-color: blue;
}
.animationDisplayNone{
animation: smoothDisplayNone 0.5s linear forwards;
}
.animationDisplayBlock{
animation: smoothDisplayBlock 0.5s linear forwards;
}
/*You should set the width and height according to the size of your element*/
#keyframes smoothDisplayBlock{
0% { opacity: 0; width: 0px; height: 0px; }
25% { opacity: 0.25; }
50% { opacity: 0.50; }
75% { opacity: 0.75; }
100% { opacity: 1; width: 200px; height: 200px; }
}
#keyframes smoothDisplayNone {
0% { opacity: 1; width: 200px; height: 200px; }
25% { opacity: 0.75; }
50% { opacity: 0.50; }
75% { opacity: 0.25; }
100% { opacity: 0; width: 0px; height: 0px; }
}
<div id="redBox"></div>
<div id="blueBox"></div>
<button type="button" style="margin-top:10px;">Red</button>
<button type="button" style="margin-top:10px;">Blue</button>
The code looks long at first glance but it is actually very simple to understand. I used the power of css animation to create a smooth effect.
You can use smoothDisplayNone() function easily.

Categories