Trying to trigger a CSS transition using JavaScript - Stack Overflow

Playing with JavaScript and CSS transition, I tried to remove a CSS classright after having dynamicall

Playing with JavaScript and CSS transition, I tried to remove a CSS class right after having dynamically inserted a div, using JavaScript and innerHTML.

I'm really surprised to see that the CSS transition associated with the opacity of the blue div is not triggered the way I want (works under Safari, works randomly under Chrome, doesn't work under Firefox Dev Edition). Can someone explain this phenomenon ?

I'm not sure about why it is not working the same way as it does for the red div. Maybe something I don't know about how browsers handle innerHTML ?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Having fun with JS</title>
    <style>
        .std {
            width:100px;
            height:100px;
            opacity: 1;
            transition: opacity 5s;
        }

        .std--hidden {
            opacity: 0;
        }

        .std--red {
            background-color: red;
        }

        .std--blue {
            background-color: blue;
        }
    </style>
</head>
<body>
<button>click here</button>
<div class='std std--red std--hidden'></div>
<div class='insert-here'>
</div>
<script>
    // let a chance to the browser to trigger a rendering event before the class is toggled
    // see 
    setTimeout(function() {
        // everything works fine for the red div
        document.querySelector('.std--red').classList.toggle('std--hidden');
    }, 0);


    document.querySelector('button').addEventListener('click', function(e) {

        var template = `<div class='std std--blue std--hidden'></div>`;
        document.querySelector('.insert-here').innerHTML = template;

        setTimeout(function() {
            // Why does the CSS transition seems to be triggered randomly ?
            // well more exactly
            // - it works under my Safari
            // - it does not work under my FirefoxDeveloperEdition
            // - it works randomly under my Google Chrome
            document.querySelector('.std--blue').classList.toggle('std--hidden');
        }, 0);

    });
</script>
</body>
</html>

EDIT

So I've just read the CSS transitions specs and found this

This processing of a set of simultaneous style changes is called a style change event. (Implementations typically have a style change event to correspond with their desired screen refresh rate, and when up-to-date puted style or layout information is needed for a script API that depends on it.)

Can this be the explanation somehow ? Does the setTimeout 0 is too fast on some browsers that they don't have time to pute the style differences and thus don't trigger a style change event ? Indeed if use a longer setTimeout (say, ~16.6666, guessing a 1/60 refresh rate...) it seems to work everywhere. Can someone confirm that ?

Playing with JavaScript and CSS transition, I tried to remove a CSS class right after having dynamically inserted a div, using JavaScript and innerHTML.

I'm really surprised to see that the CSS transition associated with the opacity of the blue div is not triggered the way I want (works under Safari, works randomly under Chrome, doesn't work under Firefox Dev Edition). Can someone explain this phenomenon ?

I'm not sure about why it is not working the same way as it does for the red div. Maybe something I don't know about how browsers handle innerHTML ?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Having fun with JS</title>
    <style>
        .std {
            width:100px;
            height:100px;
            opacity: 1;
            transition: opacity 5s;
        }

        .std--hidden {
            opacity: 0;
        }

        .std--red {
            background-color: red;
        }

        .std--blue {
            background-color: blue;
        }
    </style>
</head>
<body>
<button>click here</button>
<div class='std std--red std--hidden'></div>
<div class='insert-here'>
</div>
<script>
    // let a chance to the browser to trigger a rendering event before the class is toggled
    // see http://stackoverflow./a/4575011
    setTimeout(function() {
        // everything works fine for the red div
        document.querySelector('.std--red').classList.toggle('std--hidden');
    }, 0);


    document.querySelector('button').addEventListener('click', function(e) {

        var template = `<div class='std std--blue std--hidden'></div>`;
        document.querySelector('.insert-here').innerHTML = template;

        setTimeout(function() {
            // Why does the CSS transition seems to be triggered randomly ?
            // well more exactly
            // - it works under my Safari
            // - it does not work under my FirefoxDeveloperEdition
            // - it works randomly under my Google Chrome
            document.querySelector('.std--blue').classList.toggle('std--hidden');
        }, 0);

    });
</script>
</body>
</html>

EDIT

So I've just read the CSS transitions specs and found this

This processing of a set of simultaneous style changes is called a style change event. (Implementations typically have a style change event to correspond with their desired screen refresh rate, and when up-to-date puted style or layout information is needed for a script API that depends on it.)

Can this be the explanation somehow ? Does the setTimeout 0 is too fast on some browsers that they don't have time to pute the style differences and thus don't trigger a style change event ? Indeed if use a longer setTimeout (say, ~16.6666, guessing a 1/60 refresh rate...) it seems to work everywhere. Can someone confirm that ?

Share Improve this question edited Mar 5, 2016 at 9:57 thomas.g asked Mar 4, 2016 at 20:00 thomas.gthomas.g 3,9323 gold badges31 silver badges36 bronze badges 10
  • What's the point of using setTimeout? It isn't doing anything. Maybe try removing them and see what happens? – Adjit Commented Mar 4, 2016 at 20:07
  • Yes it is useful, it queues the code removing the css class after that the browser has first rendered the DOM – thomas.g Commented Mar 4, 2016 at 20:09
  • Try removing the backtick where you inserted the inner HTML elements in your var template. and see instead add double quotes "" – Maqk Commented Mar 4, 2016 at 20:11
  • oooh... tha backtick doesn't do anything... you should probably be using double quotes (") for the outside and single quotes (') for the class= – Adjit Commented Mar 4, 2016 at 20:12
  • 1 The backtick corresponds to an ES6 template string. – thomas.g Commented Mar 4, 2016 at 20:13
 |  Show 5 more ments

4 Answers 4

Reset to default 3

I think I've found the answer, see the CSS 3 transition spec:

Since this specification does not define when a style change event occurs, and thus what changes to puted values are considered simultaneous, authors should be aware that changing any of the transition properties a small amount of time after making a change that might transition can result in behavior that varies between implementations, since the changes might be considered simultaneous in some implementations but not others.

I tried to add a little delay to let the browsers notice the style differences and it works consistently. It seems that some browsers are executing a setTimeout 0 really faster than others :-)

    setTimeout(function() {
        document.querySelector('.std--blue').classList.toggle('std--hidden');
    }, 17);

To trigger a transition you don't really need a class to toggle. This is important since you may not be able to set up classes dynamically to toggle beforehand. In other words you may just need to alter some CSS attributes to trigger the transitions. However yes... you need to satisfy the followings;

  1. In order your <div id="blue"></div> element to animate, it must carry the std class where the transition is defined. So first we should do like blue.classList.add("std");
  2. You need to perform the task asynchronously. Refreshing the DOM asynchronously is best done by the requestAnimationFrame() function.

var blue = document.getElementById("blue");
blue.classList.add("std");
blue.style.backgroundColor = "blue";
blue.style.opacity         = 0;

document.querySelector('button')
        .addEventListener( 'click'
                         , _ => requestAnimationFrame(_ => blue.style.opacity = 1)
                         );
.std { width:100px;
       height:100px;
       opacity: 1;
       transition: opacity 5s;
}
.std--red { background-color: red;}
<button>click here</button>
<div class='std std--red'></div>
<div id="blue"></div>

It seems you have to trigger the transition by making a reference to the style. I simply added this line (even into console.log is ok)

document.querySelector('.std.std--blue').style.width = '20';

and here it works: jsfiddle

NB: I am using FirefoxDeveloperEdition.

I have followed this solution:

CSS Transitions do not animate when you add or remove class, It will only animate when you change the CSS properties.

Complete script

<script>

setTimeout(function() {
    // everything works fine for the red div
    document.querySelector('.std--red').classList.toggle('std--hidden');
}, 0);


document.querySelector('button').addEventListener('click', function(e) {

    var template = `<div class='std std--blue std--hidden'></div>`;
    document.querySelector('.insert-here').innerHTML = template;
    document.querySelector('.std.std--blue').style.width = '20';
    setTimeout(function() {

        document.querySelector('.std.std--blue').style.width = '100';
        document.querySelector('.std--blue').classList.toggle('std--hidden');
    }, 0);

    });
</script>

You must set a value to the timeout so you give time for the element to be inserted in the DOM (must exist before calling document.querySelector)

setTimeout(function() { document.querySelector('.std--blue').classList.toggle('std--hidden')},100);

you don't need the first timeout

onload = function() {
document.querySelector('.std--red').classList.toggle('std--hidden');

 document.querySelector('button').addEventListener('click', function(e) {
   var template = "<div class='std std--blue std--hidden'></div>";
   document.querySelector('.insert-here').innerHTML = template;
   setTimeout(function() { document.querySelector('.std--blue').classList.toggle('std--hidden')},100);
    });
}
 .std {
            width:100px;
            height:100px;
            opacity: 1;
            transition: opacity 5s;
        }

        .std--hidden {
            opacity: 0;
        }

        .std--red {
            background-color: red;
        }

        .std--blue {
            background-color: blue;
        }
<button>click here</button>
<div class='std std--red std--hidden'></div>
<div class='insert-here'>
</div>

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745646025a4637976.html

相关推荐

  • Trying to trigger a CSS transition using JavaScript - Stack Overflow

    Playing with JavaScript and CSS transition, I tried to remove a CSS classright after having dynamicall

    3小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信