Una prueba de origen para un nuevo elemento HTML <permission>

Existen varios métodos imperativos para solicitar permiso para usar funciones potentes, como el acceso a la ubicación en apps web. Estos métodos presentan varios desafíos, por lo que el equipo de permisos de Chrome está experimentando con un nuevo método declarativo: un elemento HTML <permission> dedicado. Este elemento está en prueba de origen de Chrome 126 y, en última instancia, esperamos estandarizarlo.

Métodos imperativos para solicitar permiso

Cuando las apps web necesitan acceder a funciones potentes, deben solicitar permiso. Por ejemplo, cuando Google Maps requiere la ubicación del usuario a través de la API de Geolocation, los navegadores le preguntan al usuario y, por lo general, ofrecen la opción de almacenar esa decisión. Este es un concepto bien definido en la especificación de permisos.

Pregunta de forma implícita en el primer uso en lugar de una solicitud explícita por adelantado

La API de Geolocation es una API potente y se basa en el enfoque de solicitud implícita del primer uso. Por ejemplo, cuando una app llama al método navigator.geolocation.getCurrentPosition(), la solicitud de permisos aparece automáticamente en la primera llamada. Otro ejemplo es navigator.mediaDevices.getUserMedia().

Otras APIs, como la API de notificaciones o la API de Device Orientation y Motion, suelen tener una forma explícita de solicitar permisos a través de un método estático, como Notification.requestPermission() o DeviceMotionEvent.requestPermission().

Desafíos relacionados con los métodos imperativos para solicitar permisos

Spam de permisos

Antes, los sitios web podían llamar a métodos como navigator.mediaDevices.getUserMedia() o Notification.requestPermission(), pero también navigator.geolocation.getCurrentPosition() inmediatamente cuando se cargaba un sitio web. Aparecerá un mensaje de permiso antes de que el usuario interactuara con el sitio web. En ocasiones, esto se describe como spam de permisos y afecta ambos enfoques, ya que solicita de forma implícita el primer uso y la solicitud explícita por adelantado.

El mensaje de permiso de acceso al micrófono se muestra cuando se carga un sitio web.

Mitigaciones del navegador y requisito de gestos del usuario

El spam de permisos llevó a que los proveedores de navegadores requirieran un gesto del usuario, como un clic en un botón o un evento de keydown antes de mostrar una solicitud de permiso. El problema de este enfoque es que es muy difícil, sino imposible, que el navegador determine si un gesto determinado del usuario debe generar una solicitud de permiso para que se muestre o no. Tal vez el usuario solo estaba haciendo clic en la página frustrado en algún lugar porque la página tardó demasiado en cargarse, o tal vez realmente estaba haciendo clic en el botón Ubicarme. Algunos sitios web también se volvieron muy buenos para engañar a los usuarios para que hagan clic en el contenido para activar el mensaje.

Otra mitigación es agregar mitigaciones de abuso de instrucciones, como bloquear por completo funciones para comenzar, o mostrar la solicitud de permiso de una manera no modal y menos intrusiva.

El navegador Chrome muestra un

Contexto de permisos

Otro desafío, especialmente en pantallas grandes, es la forma en que se muestra comúnmente la solicitud de permiso: por encima de la línea de muerte, es decir, fuera del área de la ventana del navegador en la que la app puede dibujar. No es extraño que los usuarios se pierdan el mensaje que aparece en la parte superior de la ventana del navegador cuando solo hacen clic en un botón en la parte inferior de la ventana. Este problema suele agravarse cuando se implementan las mitigaciones de spam en los navegadores.

Google Maps con el mensaje de permiso de ubicación abierto. El botón de acceso a la ubicación que activó el mensaje está lejos.

No es fácil deshacer

Por último, es demasiado fácil para los usuarios dirigirse a un callejón sin salida. Por ejemplo, una vez que el usuario bloquea el acceso a una función, debe conocer el menú desplegable de información del sitio en el que puede Restablecer permisos o volver a activar los permisos bloqueados. En el peor de los casos, ambas opciones requieren una recarga completa de la página hasta que se aplique la configuración actualizada. Los sitios no tienen la capacidad de proporcionar un acceso directo sencillo para que los usuarios cambien un estado de permiso existente y deben explicarles minuciosamente cómo cambiar su configuración, como se muestra en la parte inferior de la siguiente captura de pantalla de Google Maps.

Controles de sitios de Chrome en Google Maps para revocar permisos

Si el permiso es clave para la experiencia, por ejemplo, el acceso al micrófono para una aplicación de videoconferencia, las apps como Google Meet muestran diálogos intrusivos que le indican al usuario cómo desbloquear el permiso.

Instrucciones de Google Meet para abrir los controles de sitios de Chrome.

Un elemento <permission> declarativo

Para abordar los desafíos descritos en esta publicación, el equipo de permisos de Chrome lanzó una prueba de origen para un nuevo elemento HTML, <permission>. Este elemento les permite a los desarrolladores solicitar permiso de forma declarativa para usar, por ahora, un subconjunto de las potentes funciones disponibles para los sitios web. En su forma más sencilla, se usa como en el siguiente ejemplo:

<permission type="camera" />

Aún se está debatiendo activamente si <permission> debe ser un elemento nulo o no. Un elemento vacío es un elemento de cierre automático en HTML que no puede tener ningún nodo secundario. Esto, en HTML, significa que puede no tener una etiqueta de cierre.

El atributo type

El atributo type contiene una lista de permisos separados por espacios que solicitas. En el momento de la redacción de este documento, los valores permitidos son 'camera', 'microphone' y camera microphone (separados por espacio). De forma predeterminada, este elemento se renderiza de forma similar a los botones con diseños de usuario-agente básicos.

Diversos botones de elementos de permisos con permisos de cámara, micrófono y cámara, además de micrófono

El atributo type-ext

Para algunos permisos que permiten parámetros adicionales, el atributo type-ext acepta pares clave-valor separados por espacios, como, por ejemplo, precise:true para el permiso de ubicación geográfica.

El atributo lang

El navegador proporciona el texto del botón para que sea coherente, por lo que no se puede personalizar directamente. El navegador cambia el idioma del texto en función del idioma heredado del documento, de la cadena de elementos superiores o de un atributo opcional lang. Esto significa que los desarrolladores no necesitan localizar el elemento <permission> por su cuenta. Si el elemento <permission> procede más allá de la etapa de prueba de origen, se pueden admitir varias cadenas o íconos para cada tipo de permiso a fin de aumentar la flexibilidad. Si te interesa usar el elemento <permission> y necesitas una cadena o un ícono específicos, comunícate con nosotros.

Comportamiento

Cuando el usuario interactúa con el elemento <permission>, puede pasar por varias etapas:

  • Si no habían permitido una función antes, pueden habilitarla en cada visita o en la visita actual.

    Se solicita permiso para habilitar una función esta vez o en cada visita.

  • Si ya habían permitido la función antes, pueden seguir haciéndolo o dejar de hacerlo.

    El mensaje de permiso debe continuar permitiendo o dejar de permitirse.

  • Si anteriormente inhabilitaron una función, pueden seguir no permitiéndola o permitirla esta vez.

    El mensaje de permiso continúa sin permitir ni permitir esta hora.

El texto del elemento <permission> se actualiza automáticamente según el estado. Por ejemplo, si se otorgó permiso para usar un componente, el texto cambia para indicar que el componente está permitido. Si primero se debe otorgar el permiso, el texto cambiará para invitar al usuario a usar la función. Compara la captura de pantalla anterior con la siguiente para ver los dos estados.

Botones de permisos con los textos

Diseño de CSS

Para garantizar que los usuarios puedan reconocer fácilmente el botón como una plataforma para acceder a funciones potentes, se restringe el diseño del elemento <permission>. Si las restricciones de estilo no funcionan en tu caso de uso, nos encantaría saber cómo y por qué. Si bien no se pueden satisfacer todas las necesidades de diseño, esperamos descubrir formas seguras de permitir un mejor diseño del elemento <permission> después de la prueba de origen. En la siguiente tabla, se detallan algunas propiedades que tienen restricciones o reglas especiales aplicadas. En caso de que se incumpla alguna de las reglas, se inhabilitará el elemento <permission> y no se podrá interactuar con él. Cualquier intento de interactuar con él generará excepciones que se pueden detectar con JavaScript. El mensaje de error contendrá más detalles sobre el incumplimiento detectado.

Propiedad Reglas

color, background-color

Se puede usar para establecer el color del texto y del fondo, respectivamente. El contraste entre los dos colores debe ser suficiente para que el texto sea claramente legible (relación de contraste de al menos 3). El canal alfa tiene que ser 1.

font-size, zoom

Se debe configurar con el equivalente de small y xxxlarge. De lo contrario, se inhabilitará el elemento. Se tendrá en cuenta Zoom cuando se calcule font-size.

outline-offset

Los valores negativos se corregirán a 0.
margin (todos) Los valores negativos se corregirán a 0.

font-weight

Los valores inferiores a 200 se corregirán a 200.

font-style

Los valores distintos de normal y italic se corregirán a normal.

word-spacing

Los valores superiores a 0.5em se corregirán a 0.5em. Los valores en 0 se corregirán a 0.

display

Los valores distintos de inline-block y none se corregirán a inline-block.

letter-spacing

Los valores superiores a 0.2em se corregirán a 0.2em. Los valores en -0.05em se corregirán a -0.05em.

min-height

Tendrá un valor predeterminado de 1em. Si se proporciona, se considerará el valor máximo calculado entre los valores predeterminados y proporcionados.

max-height

Tendrá un valor predeterminado de 3em. Si se proporciona, se considerará el valor mínimo calculado entre los valores predeterminados y proporcionados.

min-width

Tendrá un valor predeterminado de fit-content. Si se proporciona, se considerará el valor máximo calculado entre los valores predeterminados y proporcionados.

max-width

Tendrá un valor predeterminado de tres veces fit-content Si se proporciona, se considerará el valor mínimo calculado entre los valores predeterminados y proporcionados.

padding-top

Solo tendrá efecto si height se establece como auto. En este caso, los valores superiores a 1em se corregirán a 1em, y padding-bottom se establecerán al valor de padding-top.

padding-left

Solo tendrá efecto si width se establece como auto. En este caso, los valores superiores a 5em se corregirán a 5em, y padding-right se establecerán al valor de padding-left..

transform

No se permitirá distorsionar los efectos visuales. Por ahora, solo aceptamos la traslación en 2D y el aumento proporcional.

Las siguientes propiedades de CSS se pueden usar con normalidad:

  • font-kerning
  • font-optical-sizing
  • font-stretch
  • font-synthesis-weight
  • font-synthesis-style
  • font-synthesis-small-caps
  • font-feature-settings
  • forced-color-adjust
  • text-rendering
  • align-self
  • anchor-name aspect-ratio
  • border (y todas las propiedades de border-*)
  • clear
  • color-scheme
  • contain
  • contain-intrinsic-width
  • contain-intrinsic-height
  • container-name
  • container-type
  • counter-*
  • flex-*
  • float
  • height
  • isolation
  • justify-self
  • left
  • order
  • orphans
  • outline-* (con la excepción indicada anteriormente para outline-offset)
  • overflow-anchor
  • overscroll-behavior-*
  • page
  • position
  • position-anchor
  • content-visibility
  • right
  • scroll-margin-*
  • scroll-padding-*
  • text-spacing-trim
  • top
  • visibility
  • x
  • y
  • ruby-position
  • user-select
  • width
  • will-change
  • z-index

Además, se pueden usar todas las propiedades equivalentes a la lógica (por ejemplo, inline-size es equivalente a width) de acuerdo con las mismas reglas que su equivalente.

Pseudoclases

Hay dos seudoclases especiales que permiten diseñar el elemento <permission> según el estado:

  • :granted: La seudoclase :granted permite un diseño especial cuando se otorga un permiso.
  • :invalid: La seudoclase :invalid permite un diseño especial cuando el elemento se encuentra en un estado no válido, por ejemplo, cuando se entrega en un iframe de origen cruzado.
permission {
  background-color: green;
}

permission:granted {
  background-color: light-green;
}

/* Not supported during the origin trial. */
permission:invalid {
  background-color: gray;
}

Eventos de JavaScript

El elemento <permission> está diseñado para usarse junto con la API de Permissions. Se pueden escuchar varios eventos:

  • onpromptdismiss: Este evento se activa cuando el usuario descarta la solicitud de permiso que activa el elemento (por ejemplo, si hace clic en el botón de cierre o fuera del mensaje).

  • onpromptaction: Este evento se activa cuando el usuario que realiza alguna acción en el mensaje resuelve la solicitud de permiso que activa el elemento. Esto no necesariamente significa que el estado del permiso haya cambiado; es posible que el usuario haya realizado una acción que mantiene el statu quo (por ejemplo, continuar otorgando un permiso).

  • onvalidationstatuschange: Este evento se activa cuando el elemento cambia de "valid" a "invalid". El elemento se considera "valid" cuando el navegador confía en la integridad del indicador si el usuario hace clic en él, y "invalid" de lo contrario, por ejemplo, cuando otro contenido HTML lo ocluye parcialmente.

Puedes registrar objetos de escucha de eventos para estos eventos directamente intercalados en el código HTML (<permission type="…" onpromptdismiss="alert('The prompt was dismissed');" />) o con addEventListener() en el elemento <permission>, como se muestra en el siguiente ejemplo.

<permission type="camera" />
<script>
  const permission = document.querySelector('permission');
  permission.addEventListener('promptdismiss', showCameraWarning);

  function showCameraWarning() {
    // Show warning that the app isn't fully usable
    // unless the camera permission is granted.
  }

  const permissionStatus = await navigator.permissions.query({name: "camera"});
  
  permissionStatus.addEventListener('change', () => {
    // Run the check when the status changes.
    if (permissionStatus.state === "granted") {
      useCamera();
    }
  });

  // Run the initial check.
  if (permissionStatus.state === "granted") {
    useCamera();
  }
</script>

Detección de funciones

Si un navegador no es compatible con un elemento HTML, no lo mostrará. Eso significa que, si tienes el elemento <permission> en tu código HTML, no sucede nada si el navegador no lo sabe. Es posible que aún quieras detectar la compatibilidad con JavaScript, por ejemplo, para crear una solicitud de permiso que se active a través de un clic de un <button> normal.

if ('HTMLPermissionElement' in window) {
  // The `<permission>` element is supported.
}

Prueba de origen

Para probar el elemento <permission> en tu sitio con usuarios reales, regístrate en la prueba de origen. Lee Comienza a usar las pruebas de origen si quieres obtener instrucciones a fin de preparar tu sitio para usar las pruebas de origen. La prueba de origen se ejecutará de la versión 126 a la 131 de Chrome (19 de febrero de 2025).

Demostración

Explora la demostración y revisa el código fuente en GitHub. A continuación, se muestra una captura de pantalla de la experiencia en un navegador compatible.

Demostración del elemento de permiso que muestra tres botones de permisos.

Comentarios

Nos encantaría saber cómo funciona <permission> en tu caso de uso. Puedes responder uno de los problemas en el repositorio o informar uno nuevo. Los indicadores públicos en el repositorio para el elemento <permission> nos permitirán a nosotros y a otros navegadores saber que te interesa.

Preguntas frecuentes

  • ¿En qué es mejor que un <button> normal combinado con la API de Permissions? Un clic en una <button> es un gesto del usuario, pero los navegadores no tienen forma de verificar que esté conectado con la solicitud para pedir permiso. Si el usuario hizo clic en un <permission>, el navegador puede estar seguro de que el clic está relacionado con una solicitud de permiso. Esto permite que el navegador facilite los flujos que, de otro modo, serían mucho más riesgosos. Por ejemplo, permite que el usuario deshaga fácilmente el bloqueo de un permiso.
  • ¿Qué sucede si otros navegadores no admiten el elemento <permission>? El elemento <permission> se puede usar como mejora progresiva. En navegadores no compatibles, se puede usar un flujo de permisos clásico. Por ejemplo, según el clic de un <button> normal. El equipo de permisos también está trabajando en un polyfill. Destaca el repositorio de GitHub para recibir una notificación cuando esté listo.
  • ¿Se analizó esto con otros proveedores de navegadores? El elemento <permission> se debatió activamente en el W3C TPAC en 2023 en una sesión separada. Puedes leer las notas de la sesión pública. El equipo de Chrome también solicitó posiciones formales de estándares a ambos proveedores. Consulta la sección Vínculos relacionados. El elemento <permission> es un tema recurrente de debate con otros navegadores y esperamos estandarizarlo.
  • ¿Debería ser un elemento vacío? Aún se está debatiendo activamente si <permission> debe ser un elemento vacío o no. Si tienes comentarios, informa sobre el problema.

Agradecimientos

Este documento fue revisado por Balázs Engedy, Thomas Nguyen, Penelope McLachlan, Marian Harbach, David Warren y Rachel Andrew.