'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.



Solution 1:[1]

@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?

Solution 2:[2]

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.

Solution 3:[3]

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

Solution 4:[4]

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.

Solution 5:[5]

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>

Solution 6:[6]

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;

  }

});

Solution 7:[7]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 AM Douglas
Solution 2 RizkiDPrast
Solution 3 Aqueel Aboobacker VP
Solution 4 vothaison
Solution 5 skav3n
Solution 6
Solution 7