Page Visibility API

Con la navegación con pesañas, hay una probabilidad razonable de que cualquier página web
quede en segundo plano y, por lo tanto, no sea visible para el usuario.

La API de Visibilidad de Página ofrece eventos que puedes escuchar para saber cuando un documento se convierte en visible o en oculto, así como características para observar el estado de visibilidad actual de la página.

Notas: La API de Visibilidad de Página es especialmente útil para ahorrar recursos y mejorar el rendimiento permitiendo que la página evite ejecutar tareas innecesarias cuando el documento no es visible.

Cuando el usuario minimiza la ventana o cambia a otra persaña, la API manda un evento de visibilitychange para que los listeners sepan que el estado de la página ha cambiado. Este evento se puede detectar y ejecutar algunas acciones o cambiar el comportamiento de la página. Por ejemplo, si tu aplicación web está reproduciendo un vídeo, puede pausarlo cuando el usuario ponga la pestaña en segundo plano, y volver a reproducirlo cando el usuario vuelva a la pestaña. El usuario no pierde la posición de contenido en el vídeo, el sonido del vídeo no interfiere con el audio en la nueva pestaña en primer plano, y el usuario no se pierde ninguna parte del vídeo.

Los estados de visibilidad de los <iframe> son los mismos que los del documento padre. Esconder un <iframe> usando propiedades CSS (como display: none;) no dispara los eventos de visibilidad ni cambia el estado del documento contenido en el frame.

Casos de uso

Consideremos algunos casos de uso para la API de Visibilidad de Página.

  • Un sitio tiene un carrusel de imágenes que no debería avanzar a la siguiente diapositiva a no ser que el usuario esté viendo la página.
  • Una aplicación que muestra un panel de información y no se quiere que se actualice la información del servidor cuando la página no está visible.
  • Una página quiere detectar cuando se está precargando para poder mantener un recuento preciso de las vistat de página.
  • Un sitio desea desactivar los sonidos cuando el dispositivo está en modo de espera (el usuario presiona el botón de encendido para apagar la pantalla). 

Históricamente, los desarrolladores han usado proxies imperfectos para detectar esto. Por ejemplo, observar los eventos blurfocus  on the window helps you know when your page is not the active page, but it does not tell you that your page is actually hidden to the user. The Page Visibility API addresses this.

Note: While onblur and onfocus will tell you if the user switches windows, it doesn't necessarily mean it's hidden. Pages only become hidden when the user switches tabs or minimizes the browser window containing the tab.

Policies in place to aid background page performance

Separately from the Page Visibility API, user agents typically have a number of policies in place to mitigate the performance impact of background or hidden tabs. These may include:

  • Most browsers stop sending requestAnimationFrame() callbacks to background tabs or hidden <iframe>s in order to improve performance and battery life.
  • Timers such as setTimeout() are throttled in background/inactive tabs to help improve performance. See Reasons for delays longer than specified for more details.
  • Budget-based background timeout throttling is now available in modern browsers (Firefox 58+, Chrome 57+), placing an additional limit on background timer CPU usage. This operates in a similar way across modern browsers, with the details being as follows:
    • In Firefox, windows in background tabs each have their own time budget in milliseconds — a max and a min value of +50 ms and -150 ms, respectively. Chrome is very similar except that the budget is specified in seconds.
    • Windows are subjected to throttling after 30 seconds, with the same throttling delay rules as specified for window timers (again, see Reasons for delays longer than specified). In Chrome, this value is 10 seconds.
    • Timer tasks are only permitted when the budget is non-negative.
    • Once a timer's code has finished running, the duration of time it took to execute is subtracted from its window's timeout budget.
    • The budget regenerates at a rate of 10 ms per second, in both Firefox and Chrome.

Some processes are exempt from this throttling behavior. In these cases, you can use the Page Visibility API to reduce the tabs' performance impact while they're hidden.

  • Tabs which are playing audio are considered foreground and aren’t throttled.
  • Tabs running code that's using real-time network connections (WebSockets and WebRTC) go unthrottled in order to avoid closing these connections timing out and getting unexpectedly closed.
  • IndexedDB processes are also left unthrottled in order to avoid timeouts.

Example

View live example (video with sound).

The example, which pauses the video when you switch to another tab and plays again when you return to its tab, was created with the following code:

// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange; 
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
  hidden = "hidden";
  visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
  hidden = "msHidden";
  visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
  hidden = "webkitHidden";
  visibilityChange = "webkitvisibilitychange";
}
 
var videoElement = document.getElementById("videoElement");

// If the page is hidden, pause the video;
// if the page is shown, play the video
function handleVisibilityChange() {
  if (document[hidden]) {
    videoElement.pause();
  } else {
    videoElement.play();
  }
}

// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || hidden === undefined) {
  console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
  // Handle page visibility change   
  document.addEventListener(visibilityChange, handleVisibilityChange, false);
    
  // When the video pauses, set the title.
  // This shows the paused
  videoElement.addEventListener("pause", function(){
    document.title = 'Paused';
  }, false);
    
  // When the video plays, set the title.
  videoElement.addEventListener("play", function(){
    document.title = 'Playing'; 
  }, false);

}

Properties added to the Document interface

The Page Visibility API adds the following properties to the Document interface:

Document.hidden Read only
Returns true if the page is in a state considered to be hidden to the user, and false otherwise.
Document.visibilityState Read only
A DOMString indicating the document's current visibility state. Possible values are:
visible
The page content may be at least partially visible. In practice this means that the page is the foreground tab of a non-minimized window.
hidden
The page's content is not visible to the user, either due to the document's tab being in the background or part of a window that is minimized, or because the device's screen is off.
prerender
The page's content is being prerendered and is not visible to the user. A document may start in the prerender state, but will never switch to this state from any other state, since a document can only prerender once.
Note: Not all browsers support prerendering.
unloaded
The page is in the process of being unloaded from memory.
Note: Not all browsers support the unloaded value.
Document.onvisibilitychange
An EventListener providing the code to be called when the visibilitychange event is fired.
//startSimulation and pauseSimulation defined elsewhere
function handleVisibilityChange() {
  if (document.hidden) {
    pauseSimulation();
  } else  {
    startSimulation();
  }
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);

Specifications

Specification Status Comment
Page Visibility (Second Edition) Recommendation Initial definition.

Browser compatibility

Document.visibilityState

Update compatibility data on GitHub
DesktopMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome para AndroidFirefox para AndroidOpera para AndroidSafari en iOSSamsung Internet
visibilityStateChrome Soporte completo 33
Soporte completo 33
Soporte completo 13
Prefijado
Prefijado Requiere de un prefijo de vendedor : webkit
Edge Soporte completo 12Firefox Soporte completo 18
Soporte completo 18
Sin soporte 10 — 52
Prefijado
Prefijado Requiere de un prefijo de vendedor : moz
IE Soporte completo 10Opera Soporte completo 12.1
Notas
Soporte completo 12.1
Notas
Notas Doesn't fire the visibilitychange event when the browser window is minimized, nor when hidden is set to true.
Safari Soporte completo 7WebView Android Soporte completo 4.4.3Chrome Android Soporte completo 33
Soporte completo 33
Soporte completo Si
Prefijado
Prefijado Requiere de un prefijo de vendedor : webkit
Firefox Android Soporte completo 18
Soporte completo 18
Sin soporte 10 — 52
Prefijado
Prefijado Requiere de un prefijo de vendedor : moz
Opera Android Soporte completo 12.1
Notas
Soporte completo 12.1
Notas
Notas Doesn't fire the visibilitychange event when the browser window is minimized, nor when hidden is set to true.
Safari iOS Soporte completo 7Samsung Internet Android ?
prerender value
DeprecadoNo estándar
Chrome Soporte completo SiEdge ? Firefox Soporte completo 49IE ? Opera ? Safari ? WebView Android Soporte completo SiChrome Android Soporte completo SiFirefox Android Soporte completo 49Opera Android ? Safari iOS ? Samsung Internet Android ?

Leyenda

Soporte completo  
Soporte completo
Compatibilidad desconocida  
Compatibilidad desconocida
No estandar . Esperar poco soporte entre navegadores.
No estandar . Esperar poco soporte entre navegadores.
Deprecado. No debe ser usado en nuevos sitios web.
Deprecado. No debe ser usado en nuevos sitios web.
Ver notas de implementación.
Ver notas de implementación.
Requiere de un prefijo de proveedor o un de nombre diferente para su uso.
Requiere de un prefijo de proveedor o un de nombre diferente para su uso.

See also