Obtén información sobre las pantallas conectadas y coloca ventanas en relación con ellas.
API de Window Management
La API de Window Management te permite enumerar las pantallas conectadas a tu máquina y colocar ventanas en pantallas específicas.
Casos de uso sugeridos
Estos son algunos ejemplos de sitios que pueden usar esta API:
- Los editores de gráficos multiventana, como Gimp, pueden colocar varias herramientas de edición en ventanas posicionadas con precisión.
- Las mesas de negociación virtuales pueden mostrar las tendencias del mercado en varias ventanas, cualquiera de las cuales se puede ver en modo de pantalla completa.
- Las apps de presentación de diapositivas pueden mostrar las notas del orador en la pantalla principal interna y la presentación en un proyector externo.
Cómo usar la API de Window Management
El problema
Lamentablemente, el enfoque probado para controlar ventanas, Window.open()
, no tiene en cuenta las pantallas adicionales. Si bien algunos aspectos de esta API parecen un poco arcaicos, como su parámetro windowFeatures
DOMString
, nos ha sido de gran utilidad a lo largo de los años. Para especificar la posición de una ventana, puedes pasar las coordenadas como left
y top
(o screenX
y screenY
, respectivamente) y pasar el tamaño deseado como width
y height
(o innerWidth
y innerHeight
, respectivamente). Por ejemplo, para abrir una ventana de 400 × 300 a 50 píxeles de la izquierda y 50 píxeles de la parte superior, puedes usar el siguiente código:
const popup = window.open(
'https://example.com/',
'My Popup',
'left=50,top=50,width=400,height=300',
);
Puedes obtener información sobre la pantalla actual consultando la propiedad window.screen
, que devuelve un objeto Screen
. Este es el resultado en mi MacBook Pro de 13":
window.screen;
/* Output from my MacBook Pro 13″:
availHeight: 969
availLeft: 0
availTop: 25
availWidth: 1680
colorDepth: 30
height: 1050
isExtended: true
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 30
width: 1680
*/
Al igual que la mayoría de las personas que trabajan en tecnología, tuve que adaptarme a la nueva realidad laboral y configurar mi oficina personal en casa. El mío se ve como el de la foto a continuación (si te interesa, puedes leer los detalles completos sobre mi configuración). El iPad que está junto a mi MacBook está conectado a la laptop a través de Sidecar, por lo que, cuando lo necesito, puedo convertir rápidamente el iPad en una segunda pantalla.

Si quiero aprovechar la pantalla más grande, puedo colocar la ventana emergente del ejemplo de código anterior en la segunda pantalla. Yo lo hago de la siguiente manera:
popup.moveTo(2500, 50);
Esta es una estimación aproximada, ya que no hay forma de conocer las dimensiones de la segunda pantalla. La información de window.screen
solo abarca la pantalla integrada, pero no la del iPad. El width
informado de la pantalla integrada era de 1680
píxeles, por lo que cambiar a 2500
píxeles podría funcionar para desplazar la ventana al iPad, ya que sé que se encuentra a la derecha de mi MacBook. ¿Cómo puedo hacer esto en el caso general? Resulta que hay una mejor manera que adivinar. Esa forma es la API de Window Management.
Detección de características
Para verificar si se admite la API de Window Management, usa lo siguiente:
if ('getScreenDetails' in window) {
// The Window Management API is supported.
}
El permiso window-management
Antes de poder usar la API de Window Management, debo pedirle permiso al usuario para hacerlo. El permiso window-management
se puede consultar con la API de Permissions de la siguiente manera:
let granted = false;
try {
const { state } = await navigator.permissions.query({ name: 'window-management' });
granted = state === 'granted';
} catch {
// Nothing.
}
Mientras se usan navegadores con el nombre de permiso anterior y el nuevo, asegúrate de usar código defensivo cuando solicites permiso, como en el siguiente ejemplo.
async function getWindowManagementPermissionState() {
let state;
// The new permission name.
try {
({ state } = await navigator.permissions.query({
name: "window-management",
}));
} catch (err) {
return `${err.name}: ${err.message}`;
}
return state;
}
document.querySelector("button").addEventListener("click", async () => {
const state = await getWindowManagementPermissionState();
document.querySelector("pre").textContent = state;
});
El navegador puede optar por mostrar el mensaje de permiso de forma dinámica en el primer intento de usar cualquiera de los métodos de la nueva API. Sigue leyendo para obtener más información.
La propiedad window.screen.isExtended
Para saber si hay más de una pantalla conectada a mi dispositivo, accedo a la propiedad window.screen.isExtended
. Devuelve true
o false
. En mi configuración, devuelve true
.
window.screen.isExtended;
// Returns `true` or `false`.
El método getScreenDetails()
Ahora que sé que la configuración actual es de varias pantallas, puedo obtener más información sobre la segunda pantalla con Window.getScreenDetails()
. Si llamo a esta función, se mostrará un mensaje de permiso que me preguntará si el sitio puede abrir y colocar ventanas en mi pantalla. La función devuelve una promesa que se resuelve con un objeto ScreenDetailed
. En mi MacBook Pro 13 con un iPad conectado, esto incluye un campo screens
con dos objetos ScreenDetailed
:
await window.getScreenDetails();
/* Output from my MacBook Pro 13″ with the iPad attached:
{
currentScreen: ScreenDetailed {left: 0, top: 0, isPrimary: true, isInternal: true, devicePixelRatio: 2, …}
oncurrentscreenchange: null
onscreenschange: null
screens: [{
// The MacBook Pro
availHeight: 969
availLeft: 0
availTop: 25
availWidth: 1680
colorDepth: 30
devicePixelRatio: 2
height: 1050
isExtended: true
isInternal: true
isPrimary: true
label: "Built-in Retina Display"
left: 0
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 30
top: 0
width: 1680
},
{
// The iPad
availHeight: 999
availLeft: 1680
availTop: 25
availWidth: 1366
colorDepth: 24
devicePixelRatio: 2
height: 1024
isExtended: true
isInternal: false
isPrimary: false
label: "Sidecar Display (AirPlay)"
left: 1680
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 24
top: 0
width: 1366
}]
}
*/
La información sobre las pantallas conectadas está disponible en el array screens
. Observa cómo el valor de left
para el iPad comienza en 1680
, que es exactamente el width
de la pantalla integrada. Esto me permite determinar exactamente cómo se organizan las pantallas de forma lógica (una al lado de la otra, una encima de la otra, etcétera). Ahora también hay datos para cada pantalla que muestran si es una isInternal
y si es una isPrimary
. Ten en cuenta que la pantalla integrada no es necesariamente la pantalla principal.
El campo currentScreen
es un objeto activo que corresponde al window.screen
actual. El objeto se actualiza en las posiciones de ventanas en varias pantallas o en los cambios de dispositivo.
El evento screenschange
Lo único que falta ahora es una forma de detectar cuándo cambia la configuración de mi pantalla. Un nuevo evento, screenschange
, hace exactamente eso: se activa cada vez que se modifica la constelación de la pantalla. (Ten en cuenta que "screens" está en plural en el nombre del evento). Esto significa que el evento se activa cada vez que se conecta o desconecta una pantalla nueva o una pantalla existente (física o virtualmente en el caso de Sidecar).
Ten en cuenta que debes buscar los detalles de la nueva pantalla de forma asíncrona, ya que el evento screenschange
en sí no proporciona estos datos. Para buscar los detalles de la pantalla, usa el objeto activo de una interfaz Screens
almacenada en caché.
const screenDetails = await window.getScreenDetails();
let cachedScreensLength = screenDetails.screens.length;
screenDetails.addEventListener('screenschange', (event) => {
if (screenDetails.screens.length !== cachedScreensLength) {
console.log(
`The screen count changed from ${cachedScreensLength} to ${screenDetails.screens.length}`,
);
cachedScreensLength = screenDetails.screens.length;
}
});
El evento currentscreenchange
Si solo me interesan los cambios en la pantalla actual (es decir, el valor del objeto activo currentScreen
), puedo escuchar el evento currentscreenchange
.
const screenDetails = await window.getScreenDetails();
screenDetails.addEventListener('currentscreenchange', async (event) => {
const details = screenDetails.currentScreen;
console.log('The current screen has changed.', event, details);
});
El evento change
Por último, si solo me interesan los cambios en una pantalla concreta, puedo escuchar el evento change
de esa pantalla.
const firstScreen = (await window.getScreenDetails())[0];
firstScreen.addEventListener('change', async (event) => {
console.log('The first screen has changed.', event, firstScreen);
});
Nuevas opciones de pantalla completa
Hasta ahora, podías solicitar que los elementos se mostraran en modo de pantalla completa a través del método requestFullScreen()
, cuyo nombre es muy apropiado. El método toma un parámetro options
en el que puedes pasar FullscreenOptions
. Hasta el momento, su única propiedad fue navigationUI
.
La API de Window Management agrega una nueva propiedad screen
que te permite determinar en qué pantalla iniciar la vista de pantalla completa. Por ejemplo, si quieres que la pantalla principal se muestre en pantalla completa, haz lo siguiente:
try {
const primaryScreen = (await getScreenDetails()).screens.filter((screen) => screen.isPrimary)[0];
await document.body.requestFullscreen({ screen: primaryScreen });
} catch (err) {
console.error(err.name, err.message);
}
Polyfill
No es posible agregar un polyfill a la API de Window Management, pero puedes agregar un shim a su forma para que puedas programar exclusivamente en función de la nueva API:
if (!('getScreenDetails' in window)) {
// Returning a one-element array with the current screen,
// noting that there might be more.
window.getScreenDetails = async () => [window.screen];
// Set to `false`, noting that this might be a lie.
window.screen.isExtended = false;
}
Los otros aspectos de la API, es decir, los diversos eventos de cambio de pantalla y la propiedad screen
de FullscreenOptions
, simplemente nunca se activarían o serían ignorados de forma silenciosa por los navegadores no compatibles.
Demostración
Si eres como yo, sigues de cerca el desarrollo de las distintas criptomonedas. (En realidad, no lo hago porque amo este planeta, pero, para los fines de este artículo, supón que sí). Para hacer un seguimiento de las criptomonedas que poseo, desarrollé una app web que me permite observar los mercados en todas las situaciones de la vida, como desde la comodidad de mi cama, donde tengo una configuración decente de una sola pantalla.

Como se trata de criptomonedas, los mercados pueden volverse frenéticos en cualquier momento. Si esto sucede, puedo cambiarme rápidamente a mi escritorio, donde tengo una configuración de varias pantallas. Puedo hacer clic en la ventana de cualquier moneda y ver rápidamente todos los detalles en una vista de pantalla completa en la pantalla opuesta. A continuación, se incluye una foto reciente mía que se tomó durante el último baño de sangre de YCY. Me tomó por sorpresa y me dejó con las manos en la cara.

Puedes probar la demostración que se incluye a continuación o ver su código fuente en GitHub.
Seguridad y permisos
El equipo de Chrome diseñó y, luego, implementó la API de Window Management con los principios fundamentales definidos en Controlling Access to Powerful Web Platform Features, incluidos el control del usuario, la transparencia y la ergonomía. La API de Window Management expone información nueva sobre las pantallas conectadas a un dispositivo, lo que aumenta la superficie de huellas digitales de los usuarios, en especial, de aquellos que tienen varias pantallas conectadas de forma constante a sus dispositivos. Como una medida de mitigación de este problema de privacidad, las propiedades de pantalla expuestas se limitan al mínimo necesario para los casos de uso de colocación comunes. Los sitios necesitan el permiso del usuario para obtener información de multipantalla y colocar ventanas en otras pantallas. Si bien Chromium devuelve etiquetas de pantalla detalladas, los navegadores pueden devolver etiquetas menos descriptivas (o incluso vacías).
Control de usuarios
El usuario tiene control total sobre la exposición de su configuración. Pueden aceptar o rechazar el mensaje de permiso, y revocar un permiso otorgado anteriormente a través de la función de información del sitio en el navegador.
Control empresarial
Los usuarios de Chrome Enterprise pueden controlar varios aspectos de la API de Window Management, como se describe en la sección correspondiente de la configuración de los grupos de políticas atómicas.
Transparencia
El hecho de que se haya otorgado el permiso para usar la API de Window Management se expone en la información del sitio del navegador y también se puede consultar a través de la API de Permissions.
Persistencia de permisos
El navegador conserva los permisos otorgados. El permiso se puede revocar a través de la información del sitio del navegador.
Comentarios
El equipo de Chrome quiere conocer tu experiencia con la API de Window Management.
Cuéntanos sobre el diseño de la API
¿Hay algo sobre la API que no funciona como esperabas? ¿O faltan métodos o propiedades que necesitas para implementar tu idea? ¿Tienes alguna pregunta o comentario sobre el modelo de seguridad?
- Informa un problema de especificación en el repositorio de GitHub correspondiente o agrega tus ideas a un problema existente.
Informa un problema con la implementación
¿Encontraste un error en la implementación de Chrome? ¿O la implementación es diferente de la especificación?
- Presenta un error en new.crbug.com. Asegúrate de incluir tantos detalles como puedas, instrucciones simples para reproducir el error y, luego, ingresa
Blink>Screen>MultiScreen
en el cuadro Components.
Cómo mostrar compatibilidad con la API
¿Planeas usar la API de Window Management? Tu apoyo público ayuda al equipo de Chrome a priorizar funciones y muestra a otros proveedores de navegadores lo importante que es admitirlas.
- Comparte cómo planeas usarlo en el hilo de Discourse del WICG.
- Envía un tweet a @ChromiumDev con el hashtag
#WindowManagement
y cuéntanos dónde y cómo lo usas. - Solicita a otros proveedores de navegadores que implementen la API.
Vínculos útiles
- Borrador de especificaciones
- Explicación pública
- Demostración de la API de Window Management | Fuente de la demostración de la API de Window Management
- Error de seguimiento de Chromium
- Entrada de ChromeStatus.com
- Componente Blink:
Blink>Screen>MultiScreen
- Revisión del TAG
- Intención de experimentar
Agradecimientos
Victor Costan, Joshua Bell y Mike Wasserman editaron las especificaciones de la API de Window Management. La API fue implementada por Mike Wasserman y Adrienne Walker. Joe Medley, François Beaufort y Kayce Basques revisaron este artículo. Gracias a Laura Torrent Puig por las fotos.