1

fellow nerds, I recently stumbled across something rather strange, that essentially breaks the web app I'm working on... Which is that css attributes I add to an HTML element through (vanilla) javascript, seems to be async, to demonstrate that I have a small piece of code...

   ...

    _( leftView ).addClass('notrans');
    _( rightView ).addClass('notrans');

    if ( fromLeft ) {
        if ( !rightFocused ) {
            _( leftView ).css({ 'left' : '-100%' })
            _( rightView ).css({ 'left' : '-50%' });
        } else _( leftView ).css({ 'left' : '-50%' });
    }

    if ( fromRight ) {
        if ( !leftFocused ) {
            _( leftView ).css({ 'left' : '100%' });
            _( rightView ).css({ 'left' : '150%' });
        } else _( rightView ).css({ 'left' : '100%' });
    }

    _( leftView ).removeClass('notrans');
    _( rightView ).removeClass('notrans');

    ...

NOTE: The small underscore you see everywhere, is a small library I made and tested... And I'm 99% sure that the CSS, add class and remove class functions work.

Now, the problem is that when I get to the remove class part of the code ( last two lines ), the CSS doesn't seem to have been applied yet. So when it finally does, I will already have removed the notrans class, and the elements will move with a transition instead of none. This can be fixed with a 1ms timeout to the removal of the classes but will break some other stuff down the line... So is there anybody that knows if adding CSS attributes through JS is async, and how to fix it?:)

Aske K.

5
  • Can you show us the library code that actually adds and removes the styles? Also it's not vanilla, it's a library: it's just a library you wrote. Commented Apr 26, 2017 at 18:17
  • How many elements are being affected here? If there are a very large amount, lets say more than 5,000, then it is possible that the rendering engine hasn't finished rendering and calculating the changes made in the css. If it is more like 100 elements, then this is probably not the case. Commented Apr 26, 2017 at 18:19
  • @TravisJ That wouldn't make it async. Commented Apr 26, 2017 at 18:19
  • @zfrisch - It wouldn't, but it would make it appear to not be synchronous. Commented Apr 26, 2017 at 18:22
  • @TravisJ It was actually only affecting 2 HTML element at the time of the testing, so it wasn't the problem, but anyway thanks. Commented Apr 26, 2017 at 18:27

1 Answer 1

2

Yes and no.

When you have JavaScript making changes to the CSS, the changes are queued and then all applied together when the JavaScript is done.

Exception: certain properties cause a recalculation to be done. For example, getting measurements like offsetHeight causes the browser to apply any pending CSS changes, make the measurement, then continue.

However, I don't know for sure if transitions are properly applied even if a measurement is done. The easy way would be to make the removeClass async, by sticking it in setTimeout(... , 1) or (better) requestAnimationFrame (which is called the very next frame, well after the CSS has updated)

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

4 Comments

Oh, thanks a lot, worked by just calling offsetHeight on the elements, even on transitions, you're a true hero:)
To be honest, I actually wasn't aware that changes made to css during JS execution contexts were queued. Do you have any links for that so I can read a little more about it?
@TravisJ I don't, unfortunately. It's just one of the things I've picked up in my experience, and I know I read it somewhere but it was a very long time ago.
I found a list of them, although without much citation, on github here: gist.github.com/paulirish/5d52fb081b3570c81e3a . I was surprised to see .innerText on there.

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.