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 <permission> de HTML dedicado. Este elemento está en prueba de origen desde 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 mostrarán un mensaje al usuario, a menudo con la opción de almacenar esa decisión. Este es un concepto bien definido en la especificación de permisos.

Preguntar de forma implícita en el primer uso en lugar de solicitar de forma explícita por adelantado

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

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

Desafíos con los métodos imperativos para solicitar permiso

Spam de permisos

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

Aviso de permiso de micrófono que se muestra cuando se carga un sitio web.

Mitigaciones del navegador y requisito de gesto del usuario

El spam de permisos hizo que los proveedores de navegadores requirieran un gesto del usuario, como un clic en un botón o un evento de tecla presionada, antes de mostrar un mensaje de permiso. El problema con este enfoque es que es muy difícil, si no imposible, que el navegador determine si un gesto del usuario determinado debería generar un mensaje de permiso o no. Tal vez el usuario solo hizo clic en cualquier parte de la página por frustración porque tardó mucho en cargarse, o tal vez sí hizo clic en el botón Ubicarme. Algunos sitios web también se volvieron muy buenos para engañar a los usuarios y hacer que hagan clic en el contenido para activar el mensaje.

Otra medida de mitigación es agregar mitigaciones del abuso de instrucciones, como bloquear por completo las funciones desde el principio o mostrar la solicitud de permiso de una manera no modal y menos intrusiva.

El navegador Chrome muestra un

Contextualización de permisos

Otro desafío, especialmente en pantallas grandes, es la forma en que se muestra comúnmente el mensaje de permiso: por encima de la línea de la muerte, es decir, fuera del área de la ventana del navegador en la que la app puede dibujar. No es raro que los usuarios no vean el mensaje en la parte superior de la ventana del navegador cuando acaban de hacer clic en un botón en la parte inferior de la ventana. Este problema suele agravarse cuando se aplican mitigaciones de spam en el navegador.

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 se puede deshacer fácilmente

Por último, es demasiado fácil para los usuarios navegar hasta un callejón sin salida. Por ejemplo, una vez que el usuario bloqueó el acceso a una función, debe conocer el menú desplegable de información del sitio en el que puede restablecer los 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 el parámetro de configuración actualizado. Los sitios no pueden proporcionar un acceso directo fácil 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 videoconferencias), 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 del sitio de Chrome.

Un elemento <permission> declarativo

Para abordar los desafíos que se describen en esta entrada del blog, el equipo de permisos de Chrome lanzó una prueba de origen para un nuevo elemento HTML, <permission>. Por el momento, este elemento permite que los desarrolladores soliciten de forma declarativa permiso para usar un subconjunto de las potentes funciones disponibles para los sitios web. En su forma más simple, se usa como en el siguiente ejemplo:

<permission type="camera" />

Aún se debate activamente si <permission> debería 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, lo que, en HTML, significa que no puede 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 escribir este documento, los valores permitidos son 'camera', 'microphone' y camera microphone (separados por espacios). De forma predeterminada, este elemento se renderiza de forma similar a los botones con un diseño básico de usuario-agente.

Varios botones de elementos de permisos con permisos de cámara, micrófono y cámara más micrófono.

El atributo type-ext

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

El atributo lang

El texto del botón lo proporciona el navegador y debe ser coherente, por lo que no se puede personalizar directamente. El navegador cambia el idioma del texto según el idioma heredado del documento o la cadena de elementos principal, o un atributo lang opcional. Esto significa que los desarrolladores no necesitan localizar el elemento <permission> por su cuenta. Si el elemento <permission> supera la etapa de prueba de origen, es posible que se admitan varias cadenas o íconos para cada tipo de permiso, lo que aumentará la flexibilidad. Si te interesa usar el elemento <permission> y necesitas un ícono o una cadena específicos, comunícate con nosotros.

Comportamiento

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

  • Si no permitieron una función antes, pueden permitirla en cada visita o permitirla para la visita actual.

    Mensaje de permiso para permitir una función esta vez o en cada visita.

  • Si ya había permitido la función, puede seguir permitiéndola o dejar de hacerlo.

    Mensaje de permiso para seguir permitiendo o dejar de permitir.

  • Si antes no permitieron una función, pueden seguir sin permitirla o permitirla esta vez.

    Mensaje de permiso para continuar sin permitir o permitir esta vez.

El texto del elemento <permission> se actualiza automáticamente según el estado. Por ejemplo, si se otorgó permiso para usar una función, el texto cambia para indicar que se permite la función. Si primero se debe otorgar el permiso, el texto cambia 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 permiso con los textos

Diseño de CSS

Para garantizar que los usuarios puedan reconocer fácilmente el botón como una superficie para acceder a funciones potentes, se restringe el diseño del elemento <permission>. Si las restricciones de diseño no funcionan para 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 más 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, el elemento <permission> se inhabilitará 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 el color de fondo, respectivamente. El contraste entre los dos colores debe ser suficiente para que el texto sea legible con claridad (proporción de contraste de al menos 3). El canal alfa debe ser 1.

font-size, zoom

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

outline-offset

Los valores negativos se corregirán a 0.
margin (todo) 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 inferiores a 0 se corregirán a 0.

display

Los valores que no sean 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 inferiores a -0.05em se corregirán a -0.05em.

min-height

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

max-height

Tendrá un valor predeterminado de 3em. Si se proporciona, se tendrá en cuenta el valor mínimo calculado entre los valores predeterminado y proporcionado.

min-width

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

max-width

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

padding-top

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

padding-left

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

transform

No se permitirán los efectos visuales que distorsionen la imagen. Por el momento, solo aceptamos la traducción en 2D y el aumento proporcional de la escala.

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 mencionada 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 lógicamente equivalentes (por ejemplo, inline-size es equivalente a width), siguiendo las mismas reglas que sus equivalentes.

Pseudoclases

Existen dos seudoclases especiales que permiten aplicar un diseño al elemento <permission> según el estado:

  • :granted: La seudoclase :granted permite aplicar un diseño especial cuando se otorga un permiso.
  • :invalid: La seudoclase :invalid permite aplicar un diseño especial cuando el elemento se encuentra en un estado no válido, por ejemplo, cuando se publica 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 el mensaje de permiso que activó el elemento (por ejemplo, haciendo clic en el botón de cierre o fuera del mensaje).

  • onpromptaction: Este evento se activa cuando el usuario resuelve el mensaje de permiso que activó el elemento realizando alguna acción en el mensaje. Esto no significa necesariamente que el estado del permiso haya cambiado. Es posible que el usuario haya realizado una acción que mantenga el statu quo (por ejemplo, seguir permitiendo 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 hiciera clic en él y "invalid" en otros casos, por ejemplo, cuando el elemento está parcialmente obstruido por otro contenido HTML.

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 características

Si un navegador no admite un elemento HTML, no lo mostrará. Esto significa que, si tienes el elemento <permission> en tu código HTML, no sucederá nada si el navegador no lo conoce. Es posible que aún desees detectar la compatibilidad con JavaScript, por ejemplo, para crear un mensaje de permiso que se active con un clic en 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 para obtener instrucciones sobre cómo preparar tu sitio para usar las pruebas de origen. La prueba de origen se ejecutará desde Chrome 126 hasta 131 (19 de febrero de 2025).

Demostración

Explora la demostración y consulta el código fuente en GitHub. Esta es una captura de pantalla de la experiencia en un navegador compatible.

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

Comentarios

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

Preguntas frecuentes

  • ¿Por qué es mejor que un <button> normal vinculado a la API de Permissions? Un clic en <button> es un gesto del usuario, pero los navegadores no tienen forma de verificar que esté conectado a la solicitud de permiso. Si el usuario hizo clic en un <permission>, el navegador puede tener la certeza de que el clic está relacionado con una solicitud de permiso. Esto permite que el navegador facilite flujos que, de otro modo, serían mucho más riesgosos. Por ejemplo, permitir 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 una mejora progresiva. En los navegadores no compatibles, se puede usar un flujo de permisos clásico. Por ejemplo, en función del clic de un <button> normal. El equipo de permisos también está trabajando en un polyfill. Marca como destacada la repo de GitHub para recibir una notificación cuando esté lista.
  • ¿Se analizó este tema con otros proveedores de navegadores? El elemento <permission> se debatió activamente en la TPAC de W3C en 2023 en una sesión separada. Puedes leer las notas públicas de la sesión. El equipo de Chrome también solicitó posiciones formales sobre los estándares a ambos proveedores. Consulta la sección Vínculos relacionados. El elemento <permission> es un tema de debate constante con otros navegadores, y esperamos estandarizarlo.
  • ¿Debería ser un elemento vacío? Aún se debate activamente si <permission> debería ser un elemento vacío o no. Si tienes comentarios, participa en el problema.

Agradecimientos

Balázs Engedy, Thomas Nguyen, Penelope McLachlan, Marian Harbach, David Warren y Rachel Andrew revisaron este documento.