Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Jonathan

Cross browser to detect tab or window is active so animations stay in sync using HTML5 Visibility API

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hello ..

 

To anyone that needs to pause() and resume() your GSAP animations when switching browser tabs or windows and have them stay in sync. I did more tests and found that Firefox and Chrome where sometimes not firing the event focus and blur, when you left the active tab.

 

So i found a better way that is consistent,  to check if the current active tab has focus or not, using the HTML5 Visibility API.

// main visibility API function 
// use visibility API to check if current tab is active or not
var vis = (function(){
    var stateKey, 
        eventKey, 
        keys = {
                hidden: "visibilitychange",
                webkitHidden: "webkitvisibilitychange",
                mozHidden: "mozvisibilitychange",
                msHidden: "msvisibilitychange"
    };
    for (stateKey in keys) {
        if (stateKey in document) {
            eventKey = keys[stateKey];
            break;
        }
    }
    return function(c) {
        if (c) document.addEventListener(eventKey, c);
        return !document[stateKey];
    }
})();

Use the HTML5 Visibility API like this:

// check if current tab is active or not
vis(function(){
					
    if(vis()){
	
        // tween resume() code goes here	
	setTimeout(function(){            
            console.log("tab is visible - has focus");
        },300);		
												
    } else {
	
        // tween pause() code goes here
        console.log("tab is invisible - has blur");		 
    }
});

You will still need the following to check if other windows have focus or not (blur). Chromium type browser like Google Chrome or Latest Opera do not fire all the time when binding the event with jQuery window, so you need to check for window.addEventListener.

// check if browser window has focus		
var notIE = (document.documentMode === undefined),
    isChromium = window.chrome;
      
if (notIE && !isChromium) {

    // checks for Firefox and other  NON IE Chrome versions
    $(window).on("focusin", function () { 

        // tween resume() code goes here
        setTimeout(function(){            
            console.log("focus");
        },300);

    }).on("focusout", function () {

        // tween pause() code goes here
        console.log("blur");

    });

} else {
    
    // checks for IE and Chromium versions
    if (window.addEventListener) {

        // bind focus event
        window.addEventListener("focus", function (event) {

            // tween resume() code goes here
            setTimeout(function(){                 
                 console.log("focus");
            },300);

        }, false);

        // bind blur event
        window.addEventListener("blur", function (event) {

            // tween pause() code goes here
             console.log("blur");

        }, false);

    } else {

        // bind focus event
        window.attachEvent("focus", function (event) {

            // tween resume() code goes here
            setTimeout(function(){                 
                 console.log("focus");
            },300);

        });

        // bind focus event
        window.attachEvent("blur", function (event) {

            // tween pause() code goes here
            console.log("blur");

        });
    }
}

You will also notice that i have a setTimeout() in the focus event handler so the tab/window has enough time to gain focus, and so the focus event handler fire consistently. I noticed Firefox and Google Chrome were not resuming correctly unless i added the setTimeout().

 

The reason i use the HTML5 Visibility API is because some browsers like Chrome wont trigger the tab blur unless you actually click inside the other  new tab, simply scrolling with the mouse wont trigger the event,

 

I hope this helps anyone who needs to pause() and resume() their animation so they don't get out of sync. :)

 

**UPDATE**

 

FULL PAGE mode:

 

EDIT mode:

See the Pen sxgJl by jonathan (@jonathan) on CodePen

 

To Test, try:

  • First clicking inside the Preview panel so the page gains focus (important)
  • Switching between tabs
  • Giving another program focus and come back to the browser

See below post for more info

 

Also.. I made it into a jQuery plugin called TabWindowVisibilityManager so you only have to define your pause() and resume() code once inside the FOCUS and BLUR callbacks. See the bottom post.

TabWindowVisibilityManager.zip

See the Pen sxgJl by jonathan (@jonathan) on CodePen

  • Like 6
Link to comment
Share on other sites

Hi Jonathan,

 

This is fantastic. Kind of crazy how many different conditions need to be handled. Glad you figured it out and posted here.

 

Any chance you could do a CodePen demo so we can see it in action?

 

-c

Link to comment
Share on other sites

Yep.. I will create a codepen to demonstrate this.. good idea Carl!

 

I will post with the codepen shortly.. standby...

Link to comment
Share on other sites

Ok..

 

Here is my codepen example of the HTML5 Visibility API and window focus / blur events...

 

Test this using the FULL mode link.

 

FULL PAGE mode:

See the Pen sxgJl by jonathan (@jonathan) on CodePen

 

EDIT mode:

See the Pen sxgJl by jonathan (@jonathan) on CodePen

 

To Test, try:

  • First clicking inside the Preview panel so the page gains focus ( very important )
  • Switching between tabs
  • Giving another program focus and come back to the browser

Testing in Edit Mode is a little tricky because the different HTML, CSS, and JS panels trigger the window focus and window blur events. So to test you have to make sure you focus inside the output Preview panel. But I found Full Page mode to work better.

 

Basically the HTML5 Visibility API is used to check the tab visibility state. And the focus and blur event handlers listen for the browser window. So each one should have you covered when switching between tabs, and the browser window.

 

**Update**

Latest Firefox, Google Chrome, Opera, IE8, IE9, IE10, and IE11

 

Also Tested this on Galaxy S3 Mobile Android (4.3) using Mobile Chrome, Firefox Mobile, Opera Mini, and the Stock Android Browser

 

:)

  • Like 2
Link to comment
Share on other sites

Wow, Jonathan. 

 

That's incredible. Looks great and works as advertised. I hope lots of folks put this to good use.

 

Carl

Link to comment
Share on other sites

Thanks Carl, Yeah, I hope it helps others too!

 

I was thinking of making it into a jQuery plugin or simple function. So you could just write the tween resume() code for the FOCUS function once. And then also write the tween pause() code for BLUR function once.

 

Hopefully it will make it easy to reuse with having to write duplicate code for all those checks. When I make it I will post the jQuery plugin or function here.

 

Thank You :)

  • Like 2
Link to comment
Share on other sites

Excellent job!!!

 

Thanks a lot Jonathan, I'm pretty sure a lot of people will benefit from this.

 

Rodrigo.

Link to comment
Share on other sites

Hey Jonathan. 

Just noticed that your pen is featured as an "editor's pick" on the front-page of http://codepen.io/

 

Nice!

  • Like 1
Link to comment
Share on other sites

Cool... Alright Everyone, I converted the HTML5 Visibility API and window focus /  blur events into a jQuery Plugin.

 

It is called Tab Window Visibility Manager jQuery Plugin and is FREE to use.

 

You only have to specify the code for the Focus and Blur of the browser tab & window once using the plugins callbacks.

 

Just include the TabWindowVisibilityManager jQuery Plugin (or download below):
 

Usage:

// Tab Window Visibility Manager
$(window).TabWindowVisibilityManager({
    onFocusCallback: function(){
            
           // tween resume() code goes here	                

    },
    onBlurCallback: function(){
           
           // tween pause() code goes here	

    }
});

Always use window in the jQuery() factory symbol when using this plugin.

 

I hope it makes keeping your animations in sync when entering / leaving browser tabs and windows!

 

I uploaded a zip file below called TabWindowVisibilityManager.zip  with the minified and non-minified JS of the TabWindowVisibilityManager files inside it. :)

 

Please let me know if there is any bugs or anything wrong with the plugin, Thank You!

  • Like 3
Link to comment
Share on other sites

Hey Jonathan,

 

Great work on the jQuery plugin. Very slick implementation. Love how concise it is to use.

 

If you are planning on more widespread exposure for this plugin (which I absolutely think you should go for) I would suggest changing the name as currently

 

  • it implies that perhaps theres something inherently wrong with GSAP's timing mechanism and third-party tools are necessary to fix it ( I fully understand that wasn't your intention)
  • Although it does allow folks to easily pause() and resume() GSAP animations on tab blur/focus it can have a much wider usage outside of any GSAP integration.

My 2 cents is that something like FocusManager, VisibilityManager, TabFocusExtreme2000 might be more fitting and get your more attention.

 

You put a ton of work into this thing and I'd love to see as many folks use it and appreciate your skills as possible.

  • Like 2
Link to comment
Share on other sites

Sorry about that Carl.. I didn't mean to imply anything was wrong with GSAP timing... but how the browsers are very different in handling focus and blur events when entering and exiting a browser tab and window. Im bad at naming things, My Bad :!

 

Good idea Carl.. I changed the name to TabWindowVisibilityManager, and re-uploaded the TabWindowVisibilityManager.zip above.

 

Thank again for the constructive criticism Carl  :)

  • Like 1
Link to comment
Share on other sites

  • 8 months later...

man... This is the only plugin that actually does what you expect it to do. Various Visibility.js plugins don't account for browser blur/focus, I don't know why.

 

Thank you so much!

 

I hope you can make this into a plugin on GitHub with a little bit of documentation (demo, installation, API, example).

 

I'm so loving this ****. Btw, it's not only good for animations. It's also good for HTML5 notifications.

 

I registered just to tell you this. And that's saying something.

  • Like 1
Link to comment
Share on other sites

  • 6 months later...

Hi Jonathan,


 


Thanks a lot for your plugin, it was very useful to me.


 


In my scenario, when I click on the tool-bar (URL), the focus is lost, even though I'm the in same page.


How to retain focus even if we click on the URL? Please could you suggest me on this?


 


Thanks & regards,


Link to comment
Share on other sites

  • 10 months later...

Thanks for this, Jonathan!

 

Now, strange enough, when I download and use the zip-file, the browser gives an error "stayInSync" is not a function. I indeed can't find it anywhere.

Do you know what is causing this?

 

Geert

Link to comment
Share on other sites

Sorry GeertVW, and welcome to the GreenSock forum!

 

I had a typo in the TabWindowVisibilityManager.html file on Line 99 ..

 

Please replace stayInSync with TabWindowVisibilityManager

 

So try this:

// instead of this: 
$(window).stayInSync({

//use this instead:
$(window).TabWindowVisibilityManager({

I re-uploaded the TabWindowVisibilityManager.zip from the above post with that typo fix. Sorry about that :(

 

Have a great day! :)

  • Like 2
Link to comment
Share on other sites

  • 5 months later...

Hi there! sorry to unearth such an old thread, but after a quick Google search, I thought it would be the best place to post.

 

My website uses GSAP to move 'panels' around depending on what part of the site you want to see. Notably, when you open a link to a blog post, it automatically moves the blog section into view; you can see it in action here: https://robin-v.net/no-mans-sky/

 

Now, using the example above, you can see that if you switch to another tab before the transition has ended and then come back to it, you will still be on the 'front' section (with my name), and the website is now in a kinda buggy state. The two labels on the left and right side of the screen have turned black, and if you click on one of them, the site kinda glitches out, and you you have to click repeatedly on those labels to eventually make it go back to a normal state.

 

This is because, when you tabbed out, the code kept running (so basically all the variables and CSS classes updated to reflect having moved to the blog section), but the animation itself stopped.

 

Anyway: I'm wondering if the jQuery plugin you've made, @Jonathan, is still up-to-date and usable? Or is there a new and better way to detect visibility changes that you would recommend?

(My plan is to use the plugin to detect regaining visibility, and when that happens, just skip to the end of the animation.)

Link to comment
Share on other sites

That plugin is up to date. You might have to add console.log() to see it fire. Not everyone will want to play() on tab and window focus back in.. so you might want to use restart() instead .. or invalidate().restart() so the animation restarts with all values invalidated so it can restart back like a new play.

 

Also keep in mind that some browsers require that you not only click the tab your giving focus to but to also click somewhere on the page (document) in that active tab to fully trigger focus. But that is not the plugin since it just uses the HTML5 visibility API. Some browsers implement differently how a tab or window focus should happen. Basically the HTML5 Visibility API just manages tab focus and blur.. the window focus and blur works outside of the HTML5 Visibility API. And just uses blur and focus on the browser window object.

 

Page Visibility API

 

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

 

Keep in mind that Chrome, since version 38 still has a browser bug that might fire twice for the visibilityChange event.

 

:)

  • Like 2
Link to comment
Share on other sites

Yup, thank you very much! I've implemented it and it's working like a charm.

 

I also got it to work by turning off RequestAnimationFrame and lagSmoothing to make GSAP run even when the window isn't visible, but I guess it's more efficient to leave those on and use your plugin to 'catch up' when going back to the tab. Thanks again ^_^

  • Like 1
Link to comment
Share on other sites

Thanks for sharing this Jonathan!! Great You just saved me hours of time!

  • Like 2
Link to comment
Share on other sites

  • 1 month later...

hi Jonathan, 

 

great plugin! 

 

looks like it won't work for this scenario. when a user drag a tab out of the browser window and place side by side with the original browser window, the tab/window blur event won't fire on the original browser window. 

 

is that a valid case?

Link to comment
Share on other sites

Hello koo9,

 

If you drag a tab outside of a browser window, then it will stop being a tab and the HTML visibility API doesn't apply. Since the HTML visibility API is only for browser tabs, see HTML Visibility API spec. Once one tab becomes a solo window then it is subject to window focus and window blur.

 

So basically:

That  why in my example and code i have 2 parts that work for browser tabs and another part that checks for the browser window

 

:)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×