Publicado el 14 de agosto de 2025
A medida que la temporada de eventos de Google I/O llega a su fin, en esta publicación se resumen los aspectos más destacados de CSS y la IU web que se compartieron en nuestros eventos de este año.
Las funciones increíblemente potentes con las que los desarrolladores solo soñaban llegaron a los navegadores y están alcanzando la compatibilidad entre navegadores más rápido que nunca. Sin embargo, a pesar de este progreso, algunos de los patrones de IU más comunes siguen siendo sorprendentemente difíciles de implementar correctamente. A menudo, debes recurrir a frameworks de JavaScript, trucos complejos de CSS y grandes cantidades de código personalizado para crear componentes que deberían ser más simples.
El equipo de Chrome, en colaboración con otros proveedores de navegadores, organismos de estándares como CSSWG y WHATWG, y grupos comunitarios como Open UI, se enfoca en hacer que estos patrones de IU fundamentales sean realmente sencillos de implementar.
Menús de selección personalizables
El elemento <select>
es esencial para los formularios, pero su estructura interna siempre estuvo protegida por el navegador, lo que hacía que el diseño con CSS coherente y completo fuera casi imposible. Para crear un <select>
mejor, es necesario comprender sus componentes básicos: la API de Popover y la API de CSS Anchor Positioning.
La API de Popover ahora está en Baseline
Un menú desplegable personalizado necesita un cuadro flotante de opciones que aparezca sobre todos los demás elementos de la IU, que sea fácil de descartar y que administre el enfoque correctamente. La API de Popover controla todo esto y, desde este año, alcanzó el estado de Baseline Newly available, lo que significa que es estable en todos los navegadores principales.
Para crear un elemento emergente, se necesitan dos partes: un elemento activador (como un <button>
) y el elemento emergente en sí. Conéctalos asignándole al elemento emergente un atributo id
y el atributo [popover]
, y, luego, haz referencia a ese id
en el atributo [popovertarget]
del botón.
La API de Popover administra todo el ciclo de vida del elemento y proporciona lo siguiente:
- Renderización de la capa superior: Ya no tendrás que preocuparte por el índice Z.
- Capacidades de descarte ligero opcionales: Se cierra cuando un usuario hace clic fuera del área de la ventana emergente.
- Administración automática del enfoque: El navegador controla la navegación con tabulación dentro y fuera de la ventana emergente.
- Vinculaciones accesibles: El modelo de interacción subyacente se controla de forma nativa.
Se actualizó el elemento <dialog>
Si bien la ventana emergente es potente, no siempre es la opción correcta. Por ejemplo, en las interacciones que bloquean la página y requieren comentarios del usuario, es más apropiado un modal <dialog>
.
Históricamente, <dialog>
carecía de algunas de las comodidades de [popover]
, pero eso está cambiando. Con el nuevo atributo closedby="any"
, los diálogos modales ahora admiten la funcionalidad de descarte ligero, que se cierra cuando el usuario hace clic fuera del diálogo o presiona la tecla Escape.
Además, los invocadores de comandos ([command]
y [commandfor]
) proporcionan una forma declarativa y sin JavaScript de conectar un botón a una acción, como abrir un diálogo con command="show-modal"
.
Elemento <dialog> + closedby=any + invocadores de comandos |
Atributo [popover] |
|
---|---|---|
Uso principal | Interacción modal (acuerdos del usuario, explicaciones, etc.) | IU transitoria (menús, sugerencias, tarjetas, alertas emergentes) |
Descartable con un toque | Sí | Sí |
Traps Focus | Sí | No |
Página de inerts | Sí | No |
Activación Declarativa | Sí | Sí |
Implementación | Elemento | Atributo |
Renderiza en la capa superior | Sí | Sí |
Se puede personalizar por completo | Sí | Sí |
Posicionamiento de anclaje de CSS
Una vez que aparece un elemento emergente, debe posicionarse en relación con el elemento que lo abrió. Calcular esto manualmente con JavaScript es frágil y puede perjudicar el rendimiento.
A partir de Chrome 125, puedes usar la API de CSS Anchor Positioning. Esta nueva capacidad vincula de forma declarativa un elemento a otro y controla automáticamente el reposicionamiento cuando se acerca al borde de la pantalla. Esta función forma parte de Interop 2025, una iniciativa para todos los navegadores que tiene como objetivo implementar funciones muy solicitadas, por lo que podemos esperar que esté disponible en todos los navegadores principales a fines de 2025.

Si bien puedes vincular elementos de forma explícita con las propiedades anchor-name
y position-anchor
, una actualización en la especificación y en Chrome 133 crea una relación de anclaje implícita entre un <popover>
y su <button>
de invocación. Esto simplifica en gran medida el código y significa que ahora puedes posicionar la ventana emergente con una sola línea de CSS, como position-area: bottom span-left
.
La herramienta de anclaje de chrome.dev te muestra cómo usar position-area
para obtener la ubicación que desees:
Ve un paso más allá y haz que el navegador vuelva a posicionar tus anclajes, lo que evitará que salgan de la pantalla, definiendo alternativas con position-try-fallbacks
. En la siguiente demostración, se muestra una ventana emergente que usa esta propiedad para la lógica de reposicionamiento integrada:
Un <select>
verdaderamente personalizable
Con esos componentes básicos implementados en versiones anteriores, el diseño web nativo para los elementos <select>
finalmente llegó a Chrome 134. Esto incluye una nueva propiedad appearance
, nuevos seudoelementos y el elemento <selectedcontent>
.
Para habilitar la personalización, aplica appearance: base-select;
al elemento <select>
y a su nuevo seudoelemento ::picker(select)
, que segmenta la lista desplegable de opciones. Esto expone nuevas partes internas para el diseño de estilo, incluidas las siguientes:
<selectedcontent>
: Representa el contenido de la opción seleccionada que se muestra en el botón.::picker-icon
: Ícono de flecha desplegable<option>:checked
y::checkmark
: Para aplicar estilo a la opción seleccionada y a su indicador de marca de verificación

Esto permite incluir contenido enriquecido en las opciones y tener un control detallado sobre la visualización. Por ejemplo, puedes mostrar un ícono y un subtítulo en la lista de opciones, pero ocultarlos en el estado cerrado con display: none
dentro de selectedcontent
.
Lo mejor es que esta API se puede mejorar de forma progresiva. En los navegadores que no admiten estas funciones, los usuarios seguirán viendo un elemento de selección nativo de la Web funcional. Obtienes un aspecto personalizado y, al mismo tiempo, conservas la accesibilidad integrada, la navegación con el teclado y la integración de formularios del elemento select nativo de la Web.
Carrusel
Los carruseles se encuentran en todas partes de la Web, no solo en las secciones de héroe. Esto incluye el contenido que se puede desplazar horizontalmente en diseños ajustados, como la IU de una tienda de aplicaciones. Sin embargo, crear carruseles en la Web sigue siendo un desafío, con muchas consideraciones, como la administración de estados, los tirones de desplazamiento, la interactividad y la accesibilidad. Pero, si lo piensas bien, los carruseles son básicamente áreas de desplazamiento sofisticadas con más posibilidades de interacción de la IU.
Primeros pasos con los desplazadores
Para compilar un carrusel, comienza con una lista de elementos que desbordan su contenedor. Para ocultar la barra de desplazamiento horizontal y mantener el contenido desplazable, usa scrollbar-width: none
. Además, para que el desplazamiento se sienta "rápido", aplica scroll-snap-type
y scroll-snap-align
, lo que garantiza que los elementos se ajusten a su lugar a medida que el usuario se desplaza.
Anterior y siguiente con un ::scroll-button
El nuevo seudoelemento ::scroll-button()
, que se lanzó en Chrome 135, le indica al navegador que genere botones "siguiente" y "anterior" accesibles y con estado. El navegador controla automáticamente los roles de ARIA, el orden de tabulación y hasta inhabilita los botones cuando llegas al principio o al final, todo sin JavaScript adicional.
Para iniciar los botones de desplazamiento, asígnale contenido y una etiqueta accesible, de la siguiente manera:
.carousel {
&::scroll-button(left) {
content: "⬅" / "Scroll Previous";
}
&::scroll-button(right) {
content: "⮕" / "Scroll Next";
}
}

Diseña estos botones y posiciónalos en relación con su carrusel principal con la posición de anclaje de CSS, que es el enfoque recomendado para hacerlo.
Navegación directa con ::scroll-marker
En el caso de los indicadores de puntos o las miniaturas, los seudoelementos ::scroll-marker
y ::scroll-marker-group
asocian los marcadores de navegación directamente con los elementos de tu contenedor de desplazamiento. El navegador trata al grupo como un tablist
y controla la navegación con el teclado.
Al igual que con los botones de desplazamiento, inicia los marcadores de desplazamiento habilitando la propiedad content
y proporcionando una etiqueta accesible. En el siguiente ejemplo, se usa un atributo de datos para establecer la etiqueta del marcador de desplazamiento. Además, coloca los marcadores de desplazamiento en ::scroll-marker-group
con la propiedad scroll-marker-group
. Por último, aplica un diseño al marcador activo con la nueva seudoclase :target-current
. Este es un ejemplo de cómo podría verse un carrusel básico:
.carousel {
scroll-marker-group: after;
> li::scroll-marker {
content: ''/ attr(data-name);
}
> li::scroll-marker:target-current {
background: blue;
}
}

Consultas de estado de desplazamiento
Las nuevas funciones de CSS relacionadas con el desplazamiento te permiten crear carruseles más dinámicos e interactivos. La consulta de estado de desplazamiento es una nueva consulta de medios que se aplica según el estado de un elemento desplazable. Existen tres tipos diferentes de consultas de estado de desplazamiento, a las que se puede acceder con scroll-state()
en una instrucción @container
. Son los siguientes:
scroll-state(snapped)
: Coincide cuando un elemento está en la posición "ajustada". En los carruseles, es cuando se centra en el carrusel.scroll-state(stuck)
: Aplica un estilo a un elemento, como un encabezado, cuando su elemento principal se vuelve fijo.scroll-state(scrollable)
: Agrega indicadores visuales, como un efecto de atenuación, para mostrar que hay más contenido para desplazarse.
reunir todo en un solo lugar
Una combinación de nuevas primitivas de carrusel de CSS, consultas de estado de desplazamiento y posicionamiento de anclaje te facilitan la creación de carruseles interactivos y personalizados. Ve un paso más allá e incorpora animaciones controladas por desplazamiento para vincular animaciones directamente a la posición de desplazamiento, lo que crea efectos de alto rendimiento, como elementos que se escalan y se desvanecen a medida que se desplazan a la vista. Estas animaciones se ejecutan fuera del subproceso principal, lo que permite una experiencia fluida.
Este carrusel interactivo combina consultas de scroll-state()
, ::scroll-button
, ::scroll-marker
, posicionamiento de anclaje de CSS y :target-current
.
Además, puedes usar una nueva propiedad llamada interactivity
para ayudar a los usuarios a enfocarse en el contenido activo. interactivity: inert
permite que el usuario aplique inercia con CSS, lo que hace que los elementos del carrusel fuera de la pantalla no se puedan enfocar y los quita del árbol de accesibilidad.
Obtén más información sobre los carruseles de CSS.
Tarjetas de desplazamiento interactivas
Las tarjetas de desplazamiento (las ventanas emergentes enriquecidas que aparecen cuando colocas el cursor sobre un nombre de usuario o un vínculo) son increíblemente útiles, pero notoriamente difíciles de crear correctamente. Lograr que los retrasos, el control de eventos y la compatibilidad con varios dispositivos funcionen correctamente puede llevarle meses a un equipo dedicado. Sin embargo, estamos trabajando en una nueva solución declarativa que debería resolver este problema de una vez por todas.
Ventanas emergentes activadas por intereses con [interestfor]
El atributo[interestfor]
es la magia principal detrás de las tarjetas de desplazamiento declarativas. Esta próxima función ofrece el poder de las ventanas emergentes, pero las activa en función del "interés" del usuario. Por ejemplo, el interés del usuario en un dispositivo apuntador sería un desplazamiento del puntero, la navegación con tabulaciones con un teclado o una presión prolongada o un toque en pantallas táctiles. Aún no se resolvió la interacción en dispositivos móviles.
Para convertir una ventana emergente basada en clics en una basada en intereses, crea un elemento de invocación, que puede ser un <button>
o un <a>
, y asígnale un atributo [interestfor]
que sea igual al id
del elemento [popover]
. En HTML, se ve de la siguiente manera:
<button interestfor="profile-callout">
...
</button>
<div id="profile-callout" popover>
...
</div>
El navegador controla toda la lógica compleja de los eventos, lo que incluye lo siguiente:
- Eventos de entrada y salida: Entrada con desplazamiento sobre dispositivos de puntero preciso, navegación con tabulación con el teclado, presión prolongada o toque en dispositivos de puntero grueso
- Retrasos de eventos: Controla los retrasos de entrada y salida con una sola propiedad de CSS.
Esta función admite otras funciones de ventanas emergentes, como la compatibilidad con la capa superior, en la que la ventana emergente se renderiza en una nueva capa sobre el resto del árbol del DOM. Además, las vinculaciones de componentes semánticos y el modelo de árbol de accesibilidad subyacente se controlan de forma nativa.
Cómo aplicar estilo a los invocadores de intereses
Los activadores de intereses incluyen algunas capacidades nuevas. Una de ellas es la capacidad de controlar las demoras de entrada y salida con una propiedad de CSS: interest-target-delay
. La otra es la capacidad de aplicar un diseño al elemento de invocación según si tiene interés o no, con la seudoclase :has-interest
.
[interesttarget] {
interest-target-delay: 0s 1s;
&:has-interest {
background: yellow;
}
}
popover="hint"
y la IU multifuncional
Una pieza clave del rompecabezas para los invocadores de intereses es un nuevo tipo de ventana emergente: popover="hint"
. La principal diferencia con respecto a otros elementos emergentes es que un elemento emergente de sugerencia no cierra otros elementos emergentes cuando se abre. Esto es ideal para las tarjetas de vista previa o las sugerencias que deben aparecer sin descartar un menú o una ventana de chat ya abiertos.
Browser Support
popover=auto | popover=manual | popover=hint | |
---|---|---|---|
Descarte ligero (a través de un clic fuera del elemento o la tecla esc ) | Sí | No | Sí |
Cierra otros elementos de popover=auto cuando se abre | Sí | No | No |
Cierra otros elementos de popover=hint cuando se abre | Sí | No | Sí |
Cierra otros elementos de popover=manual cuando se abre | No | No | No |
Se puede abrir y cerrar la ventana emergente con JS (showPopover() o hidePopover() ). | Sí | Sí | Sí |
Administración del enfoque predeterminada para la siguiente parada de tabulación | Sí | Sí | Sí |
Se puede ocultar o alternar con popovertargetaction | Sí | Sí | Sí |
Se puede abrir dentro del elemento principal popover para mantenerlo abierto | Sí | Sí | Sí |
Esto te permite compilar de forma declarativa una IU potente y multifuncional. Ahora, un solo botón puede tener una ventana emergente automática con popovertarget
para su acción de clic principal (como abrir un panel de notificaciones) y una ventana emergente de sugerencia invocada por interés para mostrar una sugerencia útil cuando se coloca el puntero sobre el botón.
El futuro es declarativo
Las funciones que se describen aquí representan un cambio fundamental hacia una plataforma web más potente y declarativa. Si dejamos que el navegador se encargue del trabajo complejo y repetitivo de la administración de estados y la accesibilidad, podemos eliminar grandes cantidades de JavaScript, mejorar el rendimiento y enfocarnos en lo que mejor hacemos: crear experiencias de usuario innovadoras y atractivas. Esta es una verdadera época dorada para la IU web, y solo está comenzando. Sigue nuestro trabajo para crear una Web más potente y accesible.
Más recursos: