34

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.

Abk
  • 2,137
  • 1
  • 23
  • 33

8 Answers8

28

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

AM Douglas
  • 1,873
  • 1
  • 13
  • 17
  • Thanks for the answer. You've given me enough option to select from but in the jQuery example in the question, did you notice how the button moves up and down gradually while the `#hint` is being toggle?. Can you help me implement that. I don't want the button to **jump** from one position to another like in the answer you provided. – Abk Nov 06 '16 at 11:02
  • 1
    @Abk you would need to modify the element's `height` rather than use `transform: scale(x)` as I did in the examples. – AM Douglas Nov 06 '16 at 14:52
  • Okay. Let me try it. – Abk Nov 06 '16 at 15:48
20

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>
arhak
  • 2,488
  • 1
  • 24
  • 38
  • 1
    All of 100,000 element "$el.style.display: none" is very slow. Because of reflowing a HTML DOM. "$el.style.visibility: hidden" is faster. But this remain spaces. But "height: 0" solve it. good answer!! – 신동평 Nov 01 '20 at 11:24
8

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.

RizkiDPrast
  • 1,695
  • 1
  • 14
  • 21
4

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

3

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.

vothaison
  • 1,646
  • 15
  • 15
  • 2
    can you give more help by adding some snippet to the snippet in the question? – Abk Nov 06 '16 at 08:41
1

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;

  }

});
Rajesh Patel
  • 1,946
  • 16
  • 20
  • Maybe it was downvoted because you didn't say anything about the `display` property. – Abk Nov 06 '16 at 08:47
1

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>
skav3n
  • 170
  • 2
  • 10
1

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.

ABI
  • 191
  • 4