1

I am trying to create "Toast" messages in webpages like in Android. I am done with the creation and styling, but the only problem is the transition. I want the toast to fade in and fade out. This is the code I wrote so far :

function show(msg = "Hello") {
  var t = document.getElementById("toast");
  t.innerHTML = msg;
  t.style.display = "flex";
  t.style.opacity = 1;
  setInterval(function() {
    t.style.opacity = 0;
  }, 2000);
}
* {
  box-sizing: border-box;
}

html,
body {
  width: 100%;
  height: 100%;
  padding: 10px;
  margin: 0;
}

#toast {
  background-color: black;
  color: white;
  opacity: 0;
  border-radius: 0.7em;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translateX(-50%) translateY(-50%);
  padding: 10px;
  display: none;
  text-align: center;
  align-items: center;
  justify-content: center;
  transition: opacity 1s;
}
<html>

<head>
  <title>Toast demo</title>
</head>

<body>
  <div id="toast"></div>
  <button onclick="show('Message')">Show toast</button>
  <button onclick="show('Message<br>with<br>multiple<br>lines')">Show toast</button>
</body>

</html>

With this code, at the first instance, the fade-in is not there, and the subsequent ones are shown for a small time interval. Why does this happen and how to fix this behaviour? CSS solution is appreciated and I do not want to use jQuery.

4
  • 2
    Did you mean to use setTimeout instead of setInterval? Commented Mar 5, 2020 at 19:18
  • in addition, you need to remove ` display: none;` line from your CSS code. while display type is none, your opacity effect will not work properly. Commented Mar 5, 2020 at 19:42
  • Thanks, it worked! But now there's another problem: If I click the button multiple times in less than 2 seconds, the consecutive toasts are not displayed properly. Commented Mar 5, 2020 at 19:54
  • According to me, removing the display: none; attribute will keep the object above all other elements and will make the underlying elements untouchable. Am I right? Commented Mar 5, 2020 at 19:57

2 Answers 2

1

instead of:

function show(msg = "Hello") {
  var t = document.getElementById("toast");
  t.innerHTML = msg;
  t.style.display = "flex";
  t.style.opacity = 1;
  setInterval(function() {
    t.style.opacity = 0;
  }, 2000);
}

You can use Vanilla Javascript new .animate() Api, which is more performant than both setInterval & RequestAnimationFrame():

  var t = document.getElementById("toast");
      t.animate({
        filter: ["opacity(1)","opacity(0)"];    // Start & End States of the Animation.
        },{
            duration: 488,       // Duration in Ms
            fill: 'forwards',    // retains the end State of the animation.
            iterations: 1,       // Number of iterations or Infinity
            delay: 88,           // Delay for the Animation Start (2000)
            easing: 'ease-in',   // Easing Function
        //  direction:,
        //  endDelay:,
        //  iterationStart:,
       });

This Also Gives you alot more control than Just pure Css Animations & better matches the browsers refresh/repaint Cycles. More information can be found here MDN WebAnimation Api

If you want this to work via touch or mouseclick events then you need to add in the appropriate event handlers to deal with this.

https://developer.mozilla.org/en-US/docs/Web/API/Touch_events

You mentioned that the code above is not working, probably because it doesn't have any event listeners attached to is so I've made an update.
HTML::

<html>
  <head>
    <title>Toast demo</title>
  </head>
<body>
  <div id="toast"></div>
    <button id="ShowMsg">Show toast</button>
    <button id="ShowMsg2">Show toast</button>

    <script src="LinkToYourJsFile.js">Or Include The Js In Here..</script>
</body>
</html>

JS::

let ShowMsg = document.getElementById("ShowMsg");
let ShowMsg2 = document.getElementById("ShowMsg2");

function showToast(){
  var t = document.getElementById("toast");
      t.innerHTML='<p>Message you want to display</p>'; // For multiline, just repeat with <br> or Js equivelent \n
      t.animate({
        filter: ["opacity(0)","opacity(1)"]    // Start & End States of the Animation.
        },{
            duration: 488,       // Duration in Ms
            fill: 'forwards',    // retains the end State of the animation.
            iterations: 1,       // Number of iterations or Infinity
            delay: 88,           // Delay for the Animation Start (2000)
            easing: 'ease-in',   // Easing Function
        //  direction:,
        //  endDelay:,
        //  iterationStart:,
       });
}

ShowMsg.addEventListener("mousedown", showToast);  // 1) What is the event, 2) name of the function to run when the event occurs
ShowMsg2.addEventListener("mousedown", showToast2StarvinMarvin);  // Repeat the same process for toast 2. 

** Note that in your Css your t => toast Msg should intially start with filter:opacity(0); and not have display:none; as in your original code. Javascript will over-ride this when the events are fired. also the Js MUST either be at the bottom of the Html document OR be in an external file linked at the bottom of the Html. or alternatively wrapped inside of

document.addEventListener("DOMContentLoaded", (function(){
     // Your Anime code & variables etc goes here;
}));

To fade the element out repeat but change the event listener to "mouseleave" and switch the opacity value in .animate() function around. So 0 = 1, 1 = 0;

I'm still learning this stuff myself so see if you can read some of the documentaion on Mozilla Developer Network & here on Stack Overflow to get it working how you would like.. Hope this helps.

Sign up to request clarification or add additional context in comments.

8 Comments

How to use Vanilla JS? Do I need to include some library?
@Puspam No you do not need any external librarys to run javascript, it is already built into the browser add a <script></script> tag at the very end of your html just before the closing body tag.
You can either write Javascript directly inside these tags, or you can create an external file by saving a new file as my.js with the .js file extension and then to include it use <script src="FilePathToMy.js"></script>
Vanilla Just means Plain Javascript as opposed to JQuery, it is not the name of a library, w3schools.com/js/js_whereto.asp
OK, understood. But your code is not working at all. Can you please provide a working example?
|
0

I came up with a complete idea which can show as well as disappear the toast after a specified time and also, it works very smoothly even if the toast is invoked when it is already displaying. Here is my code:

var t = document.getElementById("toast");
var showing = false;
var timeout1, timeout2;

function showToast(msg = "") {
  clearTimeout(timeout1);
  clearTimeout(timeout2);

  t.innerHTML = msg;
  if (!showing) {
    showing = true;
    t.style.display = "flex";
    t.animate({
      opacity: ["0", "1"]
    }, {
      duration: 1000,
      iterations: 1,
      fill: "forwards"
    });
  }
  timeout1 = setTimeout(() => {
    showing = false;
    t.animate({
      opacity: ["1", "0"]
    }, {
      duration: 1000,
      iterations: 1,
      fill: "forwards"
    });
  }, 3000);
  timeout2 = setTimeout(() => {
    t.style.display = "none";
  }, 4000);
}
* {
  box-sizing: border-box;
}

#toast {
  background-color: black;
  color: white;
  border-radius: 0.7em;
  position: fixed;
  left: 50%;
  top: 50%;
  opacity: 0;
  display: none;
  transform: translateX(-50%) translateY(-50%);
  padding: 10px;
  text-align: center;
  align-items: center;
  justify-content: center;
}

button {
  width: 100%;
  height: 50%;
}
<div id="toast"></div>
<button onclick="showToast('Hello')">Show toast</button>
<button onclick="showToast('Hi')">Show toast</button>

Any more suggestion is appreciated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.