Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the transitionend event firing before the transition completes?

I'm trying to design a website in which different pieces of information are held in different divs. The user clicks a link and the current div fades until transparent and translates to the right, while the new one fades in from the left. The idea is to call a function that adds a "fadeOut" class to the old div, add a "fadeIn" class to the new one, and then remove the extra classes from the old div so that it can start over. It can only remove the extra classes from the old div after all the transitions are finished, of the old div will disappear rather than fading out. I tried to accomplish this using a transitionend listener, but it seems that the transitionend function is running immediately when I create it, rather than after the transition actually ends.

I made a JSFiddle with the core of the problematic code at http://jsfiddle.net/mmmm_cake/Q78pz/4/, and I'm copying it here:

<head>
    <style>
        .page {
            position:fixed;
            margin-left:15%;
            margin-right:15%;
            top:40px;
            left:-20px;
            opacity:0
        }
        .page.fadeIn {
            transition:0.5s;
            opacity:1;
            left:0px
        }
        .page.fadeOut {
            transition:0.5s;
            opacity:0;
            left:20px;
        }
    </style>
    <script>
        var active = 'about';

        function reset(page) {
            page.classList.remove('fadeOut');
            page.classList.remove('fadeIn');
        }

        function show(id) {
            page = document.getElementById(id);
            page.classList.add('fadeIn');
        }

        function hide(id) {
            page = document.getElementById(id);
            page.addEventListener('transitionend', reset(page), false);
            page.classList.add('fadeOut');
            page.removeEventListener('transitionend', reset(page), false);
        }

        function switchTo(id) {
            hide(active);
            show(id);
            active = id;
        }
    </script>
</head>
<body onload="show(active)">
    <div id="navbar">
        <a href="javascript:switchTo('about')">About</a>
        <a href="javascript:switchTo('contact')">Contact Us</a>
    </div>
    <div id="about" class="page">
        <h3>
            About Us
        </h3>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
    </div>
    <div id="contact" class="page">
        <h3>
            Contact Form
        </h3>
        <p>
            Nulla quis commodo arcu. Etiam facilisis risus nulla, vel tempus arcu ultricies eu.
        </p>
    </div>
</body>

I've tried tweaking it many different ways, and as far as I can tell, it all comes down to the transitionend event not firing properly. I've seen lots of people saying that it doesn't fire at all for them, but anyone know how to fix it when it fires too soon?

like image 298
mmmm_cake Avatar asked Jul 16 '14 19:07

mmmm_cake


1 Answers

Edit:

After having a look at your fiddle, I found several issues with your code.

  1. The reason your reset is firing immediately (The topic my original answer dealt with) is that you are calling it instead of adding it as an event listener.

  2. You call show before the transition ends, and so when calling reset, the fadein class is removed and the new page is hidden.

I have forked your fiddle with some changes to make it work.


For completeness, my original answer:

You have a mistake in your hide(id) function

You are calling reset immediately. Change reset(page) to reset.bind(null, page):

function hide(id) {
    page = document.getElementById(id);
    page.addEventListener('transitionend', *reset(page)*, false);
    page.classList.add('fadeOut');
    page.removeEventListener('transitionend', *reset(page)*, false);
}

To

function hide(id) {
    page = document.getElementById(id);
    page.addEventListener('transitionend', reset.bind(null, page), false);
    page.classList.add('fadeOut');
    page.removeEventListener('transitionend', reset.bind(null, page), false);
}
like image 141
major-mann Avatar answered Oct 18 '22 09:10

major-mann