Funciones de diseño web del presente y del futuro, como se vieron en Google I/O 2022, además de algunos extras.
El 2022 será uno de los mejores años de CSS, tanto en funciones como en lanzamientos de funciones cooperativas del navegador, con el objetivo colaborativo de implementar 14 funciones.
Descripción general
Esta publicación es la versión en formato de artículo de la charla que se brindó en Google I/O 2022. No pretende ser una guía detallada sobre cada función, sino una introducción y una breve descripción general para despertar tu interés, y proporcionar amplitud en lugar de profundidad. Si te interesa, consulta el final de una sección para ver vínculos a recursos con más información.
Índice
Usa la siguiente lista para ir a los temas que te interesen:
Compatibilidad del navegador
Una de las principales razones por las que se lanzan tantas funciones de CSS de forma cooperativa es gracias a los esfuerzos de Interop 2022. Antes de estudiar los esfuerzos de Interop, es importante analizar los esfuerzos de Compat 2021.
Compat 2021
Los objetivos para 2021, basados en los comentarios de los desarrolladores a través de encuestas, fueron estabilizar las funciones actuales, mejorar el conjunto de pruebas y aumentar las puntuaciones de aprobación de los navegadores para cinco funciones:
- Posicionamiento
sticky
- Tamaño
aspect-ratio
- Diseño
flex
- Diseño
grid
- Posicionamiento y animación de
transform
Las puntuaciones de las pruebas aumentaron en todos los ámbitos, lo que demuestra una mayor estabilidad y confiabilidad. ¡Muchas felicidades a los equipos!
Interop 2022
Este año, los navegadores se reunieron para analizar las funciones y las prioridades en las que planeaban trabajar, y unieron sus esfuerzos. Planearon lanzar las siguientes funciones web para desarrolladores:
@layer
- Espacios y funciones de color
- Contención
<dialog>
- Compatibilidad con formularios
- Desplazamiento
- Subgrid
- Tipografía
- Unidades de viewport
- Compatibilidad web
Esta es una lista emocionante y ambiciosa que no puedo esperar a ver cómo se desarrolla.
Novedades de 2022
Como era de esperarse, el estado de CSS en 2022 se vio afectado de manera significativa por el trabajo de Interop 2022.
Capas en cascada
Antes de @layer
, el orden descubierto de las hojas de estilo cargadas era muy importante, ya que los estilos cargados en último lugar pueden anular los estilos cargados anteriormente. Esto llevó a hojas de estilo de entrada administradas meticulosamente, en las que los desarrolladores debían cargar primero los estilos menos importantes y, luego, los más importantes. Existen metodologías completas para ayudar a los desarrolladores a administrar esta importancia, como ITCSS.
Con @layer
, el archivo de entrada puede definir previamente las capas y su orden. Luego, a medida que se cargan los estilos, se pueden colocar dentro de una capa, lo que permite conservar la importancia de la anulación de estilos, pero sin la orquestación de carga administrada meticulosamente.
En el video, se muestra cómo las capas en cascada definidas permiten un proceso de carga y creación más libre y de estilo libre, a la vez que se mantiene la cascada según sea necesario.
Las Herramientas para desarrolladores de Chrome son útiles para visualizar qué estilos provienen de qué capas:
Recursos
- Especificación de CSS Cascade 5
- Explicación de las capas en cascada
- Capas en cascada en MDN
- Una Kravets: Capas en cascada
- Ahmad Shadeed: Hola, CSS Cascade Layers
Subgrid
Antes de subgrid
, una cuadrícula dentro de otra no podía alinearse con las celdas o las líneas de la cuadrícula principal. Cada diseño de cuadrícula era único. Muchos diseñadores colocan una sola cuadrícula sobre todo su diseño y alinean constantemente los elementos dentro de ella, lo que no se podría hacer en CSS.
Después de subgrid
, un elemento secundario de una cuadrícula puede adoptar las columnas o filas de sus elementos principales como propias y alinearse a sí mismo o a sus elementos secundarios con ellas.
En la siguiente demostración, el elemento body crea una cuadrícula clásica de tres columnas: la columna central se llama main
, y las columnas izquierda y derecha nombran sus líneas
fullbleed
. Luego, cada elemento del cuerpo, <nav>
y <main>
, adopta las líneas con nombre del cuerpo estableciendo grid-template-columns: subgrid
.
body {
display: grid;
grid-template-columns:
[fullbleed-start]
auto [main-start] min(90%, 60ch) [main-end] auto
[fullbleed-end]
;
}
body > * {
display: grid;
grid-template-columns: subgrid;
}
Por último, los elementos secundarios de <nav>
o <main>
pueden alinearse o establecer su tamaño con las columnas y líneas fullbleed
y main
.
.main-content {
grid-column: main;
}
.fullbleed {
grid-column: fullbleed;
}
Las Herramientas para desarrolladores pueden ayudarte a ver las líneas y las subcuadrículas (por el momento, solo en Firefox). En la siguiente imagen, se superpusieron la cuadrícula principal y las secundarias. Ahora se parece más a lo que los diseñadores tenían en mente para el diseño.
En el panel de elementos de las Herramientas para desarrolladores, puedes ver qué elementos son cuadrículas y subcuadrículas, lo que resulta muy útil para depurar o validar el diseño.

Recursos
- Especificación de la subcuadrícula
- Subgrid en MDN
- Bramus: Tutoriales prácticos en video sobre subcuadrículas de CSS
Consultas de contenedores
Antes de @container
, los elementos de una página web solo podían responder al tamaño de todo el viewport. Esto es ideal para diseños macro, pero para diseños micro, en los que su contenedor externo no es toda la ventana gráfica, es imposible que el diseño se ajuste según corresponda.
Después de @container
, los elementos pueden responder al tamaño o al estilo de un contenedor principal.
La única advertencia es que los contenedores deben declararse como posibles objetivos de la búsqueda, lo que es un requisito pequeño para un gran beneficio.
/* establish a container */
.day {
container-type: inline-size;
container-name: calendar-day;
}
Estos son los estilos que permiten que los elementos del evento consulten las columnas Lun., Mar., Mié., Jue. y Vie. en el siguiente video.
A continuación, se muestra el código CSS para consultar el tamaño del contenedor calendar-day
y, luego, ajustar un diseño y los tamaños de fuente:
@container calendar-day (max-width: 200px) {
.date {
display: block;
}
.date-num {
font-size: 2.5rem;
display: block;
}
}
Este es otro ejemplo: Un componente de libro se adapta al espacio disponible en la columna a la que se arrastra:
Una tiene razón al evaluar la situación como la nueva versión adaptable. Hay muchas decisiones de diseño interesantes y significativas que tomar cuando se usa @container
.
Recursos
- Especificación de Container Queries
- Explicación de las consultas de contenedor
- Consultas de contenedores en MDN
- El nuevo diseño responsivo en web.dev
- Demostración del calendario por Una
- Awesome container queries collection (Impresionante colección de consultas de contenedores)
- Cómo creamos Designcember en web.dev
- Ahmad Shadeed: Saluda a las consultas de contenedores de CSS
accent-color
Antes de accent-color
, cuando querías un formulario con colores que coincidieran con la marca, podías terminar con bibliotecas complejas o soluciones de CSS que se volvían difíciles de administrar con el tiempo. Si bien te brindaron todas las opciones y, con suerte, incluyeron la accesibilidad, la elección de usar los componentes integrados o adoptar los tuyos se vuelve tediosa.
Después de accent-color
, una línea de CSS agrega un color de la marca a los componentes integrados. Además de un tinte, el navegador elige de forma inteligente colores de contraste adecuados para las partes auxiliares del componente y se adapta a los esquemas de color del sistema (claro u oscuro).
/* tint everything */
:root {
accent-color: hotpink;
}
/* tint one element */
progress {
accent-color: indigo;
}
Para obtener más información sobre accent-color
, consulta mi entrada en web.dev, en la que exploro muchos más aspectos de esta útil propiedad de CSS.
Recursos
- Especificación de accent-color
- accent-color en MDN
- accent-color en web.dev
- Bramus: Tint User-Interface Controls with CSS accent-color (Colorea los controles de la interfaz de usuario con accent-color de CSS)
Nivel de color 4 y 5
En las últimas décadas, sRGB dominó la Web, pero en un mundo digital en expansión con pantallas de alta definición y dispositivos móviles equipados con pantallas OLED o QLED, sRGB no es suficiente. Además, se esperan páginas dinámicas que se adapten a las preferencias del usuario, y la administración del color ha sido una preocupación creciente para los diseñadores, los sistemas de diseño y los encargados del mantenimiento del código.
Sin embargo, no en 2022, ya que CSS tiene varias funciones y espacios de color nuevos: - Colores que alcanzan las capacidades de color HD de las pantallas - Espacios de color que coinciden con una intención, como la uniformidad perceptual. - Espacios de color para gradientes que cambian drásticamente los resultados de la interpolación - Funciones de color para ayudarte a mezclar y contrastar, y elegir en qué espacio trabajas
Antes de todas estas funciones de color, los sistemas de diseño debían precalcular los colores de contraste adecuados y garantizar paletas vibrantes apropiadas, todo mientras los preprocesadores o JavaScript hacían el trabajo pesado.
Después de todas estas funciones de color, el navegador y CSS pueden hacer todo el trabajo de forma dinámica y justo a tiempo. En lugar de enviar muchos KB de CSS y JavaScript a los usuarios para habilitar los colores de temas y visualización de datos, CSS puede encargarse de la organización y los cálculos. CSS también está mejor equipado para verificar la compatibilidad antes del uso o controlar los resguardos de forma correcta.
@media (dynamic-range: high) {
.neon-pink {
--neon-glow: color(display-p3 1 0 1);
}
}
@supports (color: lab(0% 0 0)) {
.neon-pink {
--neon-glow: lab(150% 160 0);
}
}
hwb()
HWB significa tono, blancura y negrura. Se presenta como una forma fácil de articular el color, ya que solo se trata de un tono y una cantidad de blanco o negro para aclarar u oscurecer. Los artistas que mezclan colores con blanco o negro pueden apreciar esta incorporación de sintaxis de color.
El uso de esta función de color genera colores del espacio de color sRGB, igual que HSL y RGB. En cuanto a las novedades para 2022, esto no te brinda colores nuevos, pero puede facilitar algunas tareas para los fanáticos de la sintaxis y el modelo mental.
Recursos
Espacios de color
La forma en que se representan los colores se realiza con un espacio de color. Cada espacio de color ofrece diversas funciones y compensaciones para trabajar con el color. Algunos pueden juntar todos los colores brillantes, mientras que otros pueden alinearlos primero según su luminosidad.
Se espera que CSS del 2022 ofrezca 10 nuevos espacios de color, cada uno con características únicas para ayudar a los diseñadores y desarrolladores a mostrar, elegir y mezclar colores. Anteriormente, sRGB era la única opción para trabajar con el color, pero ahora CSS desbloquea un nuevo potencial y un nuevo espacio de color predeterminado, LCH.
color-mix()
Antes de color-mix()
, los desarrolladores y diseñadores necesitaban preprocesadores como Sass para mezclar los colores antes de que el navegador los viera.
La mayoría de las funciones de mezcla de colores tampoco proporcionaban la opción de especificar en qué espacio de color se debía realizar la mezcla, lo que a veces generaba resultados confusos.
Después de color-mix()
, los desarrolladores y diseñadores pueden mezclar colores en el navegador, junto con todos sus otros estilos, sin ejecutar procesos de compilación ni incluir JavaScript. Además, pueden especificar en qué espacio de color se realizará la mezcla o usar el espacio de color de mezcla predeterminado de LCH.
A menudo, se usa un color de la marca como base y se crean variantes a partir de él, como colores más claros o más oscuros para los estilos de desplazamiento. Así se ve con color-mix()
:
.color-mix-example {
--brand: #0af;
--darker: color-mix(var(--brand) 25%, black);
--lighter: color-mix(var(--brand) 25%, white);
}
y, si quisieras mezclar esos colores en un espacio de color diferente, como sRGB, cámbialo:
.color-mix-example {
--brand: #0af;
--darker: color-mix(in srgb, var(--brand) 25%, black);
--lighter: color-mix(in srgb, var(--brand) 25%, white);
}
A continuación, se muestra una demostración de temas con color-mix()
. Intenta cambiar el color de la marca y observa cómo se actualiza el tema:
¡Disfruta de la combinación de colores en varios espacios de color en tus hojas de estilo en 2022!
Recursos
- Especificación de color-mix()
- color-mix() en MDN
- Demostración de temas
- Otra demostración de temas
- Fabio Giolito: Crea un tema de color con estas próximas funciones de CSS
color-contrast()
Antes de color-contrast()
, los autores de hojas de estilo debían conocer los colores accesibles con anticipación. A menudo, una paleta mostraría texto en blanco o negro sobre una muestra de color para indicarle al usuario del sistema de color qué color de texto se necesitaría para contrastar correctamente con esa muestra.

Después de color-contrast()
, los autores de hojas de estilo pueden delegar la tarea por completo en el navegador. No solo puedes emplear el navegador para elegir automáticamente un color blanco o negro, sino que también puedes proporcionarle una lista de colores adecuados para el sistema de diseño y hacer que elija el primero que supere la proporción de contraste deseada.
A continuación, se muestra una captura de pantalla de una demostración de un conjunto de paletas de colores HWB en la que el navegador elige automáticamente los colores del texto según el color de la muestra:

Los conceptos básicos de la sintaxis se ven de la siguiente manera, donde se pasa el color gris a la función y el navegador determina si el negro o el blanco tienen el mayor contraste:
color: color-contrast(gray);
La función también se puede personalizar con una lista de colores, de la que elegirá el color con mayor contraste de la selección:
color: color-contrast(gray vs indigo, rebeccapurple, hotpink);
Por último, en caso de que sea preferible no elegir el color con el mayor contraste de la lista, se puede proporcionar una relación de contraste objetivo y se elegirá el primer color que la supere:
color: color-contrast(
var(--bg-blue-1)
vs
var(--text-lightest), var(--text-light), var(--text-subdued)
to AA /* 4.5 could also be passed */
);
Sin embargo, esta función se puede usar para más que solo el color del texto, aunque estimo que ese será su caso de uso principal. Piensa en lo mucho más fácil que será ofrecer interfaces accesibles y legibles una vez que la elección de colores contrastantes adecuados se incorpore al lenguaje CSS.
Recursos
Sintaxis de color relativa
Antes de la sintaxis de color relativa, para calcular el color y realizar ajustes, los canales de color debían colocarse individualmente en propiedades personalizadas. Esta limitación también convirtió a HSL en la función de color principal para manipular colores, ya que el tono, la saturación o la luminosidad se podían ajustar de forma sencilla con calc()
.
Después de la sintaxis de color relativa, cualquier color en cualquier espacio se puede deconstruir, modificar y devolver como un color, todo en una sola línea de CSS. Ya no hay limitaciones para HSL: las manipulaciones se pueden realizar en cualquier espacio de color deseado y se deben crear muchas menos propiedades personalizadas para facilitarlo.
En el siguiente ejemplo de sintaxis, se proporciona un valor hexadecimal base y se crean dos colores nuevos en relación con él. El primer color --absolute-change
crea un color nuevo en LCH a partir del color base y, luego, reemplaza la luminosidad del color base por 75%
, manteniendo la croma (c
) y el tono (h
). El segundo color --relative-change
crea un color nuevo en LCH a partir del color base, pero esta vez reduce la croma (c
) en un 20%.
.relative-color-syntax {
--color: #0af;
--absolute-change: lch(from var(--color) 75% c h);
--relative-change: lch(from var(--color) l calc(c-20%) h);
}
Es similar a mezclar colores, pero se parece más a las alteraciones que a la mezcla. Puedes convertir un color a partir de otro, lo que te permite acceder a los tres valores de canal según el nombre de la función de color utilizada, con la oportunidad de ajustar esos canales. En general, esta es una sintaxis muy útil y potente para el color.
En la siguiente demostración, usé la sintaxis de color relativa para crear variantes más claras y oscuras de un color base, y usé color-contrast()
para garantizar que las etiquetas tengan el contraste adecuado:

Esta función también se puede usar para generar paletas de colores. Aquí tienes una demostración en la que se generan paletas completas a partir de un color base proporcionado. Este conjunto de CSS alimenta todas las paletas, y cada una simplemente proporciona una base diferente. Como beneficio adicional, dado que usé LCH, observa qué tan uniformes son las paletas en términos de percepción: no se ven puntos calientes ni puntos muertos gracias a este espacio de color.
:root {
--_color-base: #339af0;
--color-0: lch(from var(--_color-base) 98% 10 h);
--color-1: lch(from var(--_color-base) 93% 20 h);
--color-2: lch(from var(--_color-base) 85% 40 h);
--color-3: lch(from var(--_color-base) 75% 46 h);
--color-4: lch(from var(--_color-base) 66% 51 h);
--color-5: lch(from var(--_color-base) 61% 52 h);
--color-6: lch(from var(--_color-base) 55% 57 h);
--color-7: lch(from var(--_color-base) 49% 58 h);
--color-8: lch(from var(--_color-base) 43% 55 h);
--color-9: lch(from var(--_color-base) 39% 52 h);
--color-10: lch(from var(--_color-base) 32% 48 h);
--color-11: lch(from var(--_color-base) 25% 45 h);
--color-12: lch(from var(--_color-base) 17% 40 h);
--color-13: lch(from var(--_color-base) 10% 30 h);
--color-14: lch(from var(--_color-base) 5% 20 h);
--color-15: lch(from var(--_color-base) 1% 5 h);
}

Esperamos que ahora puedas ver cómo los espacios de color y las diferentes funciones de color se pueden usar para diferentes propósitos, según sus fortalezas y debilidades.
Recursos
- Especificación de sintaxis de color relativa
- Cómo crear paletas de colores con sintaxis de color relativa
- Cómo crear variantes de color con sintaxis de color relativa
Espacios de color de gradiente
Antes de los espacios de color de gradiente, se usaba sRGB como espacio de color predeterminado. sRGB suele ser confiable, pero tiene algunas debilidades, como la zona gris muerta.
Después de los espacios de color del gradiente, indícale al navegador qué espacio de color debe usar para la interpolación de color. Esto les permite a los desarrolladores y diseñadores elegir el gradiente que prefieran. El espacio de color predeterminado también cambia a LCH en lugar de sRGB.
La adición de sintaxis va después de la dirección del gradiente, usa la nueva sintaxis in
y es opcional:
background-image: linear-gradient(
to right in hsl,
black, white
);
background-image: linear-gradient(
to right in lch,
black, white
);
Aquí tienes un gradiente básico y esencial de negro a blanco. Observa el rango de resultados en cada espacio de color. Algunos alcanzan el negro oscuro antes que otros, y algunos se desvanecen a blanco demasiado tarde.
En este siguiente ejemplo, el negro se transforma en azul porque es un espacio de problemas conocido para los gradientes. La mayoría de los espacios de color se acercan al púrpura durante la interpolación de color o, como me gusta pensar, a medida que los colores viajan dentro de su espacio de color desde el punto A al punto B. Dado que el gradiente tomará una línea recta desde el punto A hasta el punto B, la forma del espacio de color cambia drásticamente las paradas que toma la ruta en el camino.
Para obtener más información, ejemplos y comentarios, consulta este hilo de Twitter.
Recursos
- Especificación de interpolación de gradiente
- Demostración comparativa de gradientes en espacios
- Notebook de Observable que compara gradientes
inert
Antes de inert
, era una práctica recomendada guiar el enfoque del usuario hacia las áreas de la página o la app que necesitaban atención inmediata. Esta estrategia de enfoque guiado se conoció como captura de enfoque porque los desarrolladores colocaban el enfoque en un espacio interactivo, detectaban los eventos de cambio de enfoque y, si el enfoque salía del espacio interactivo, se lo forzaba a volver. Los usuarios que usan teclados o lectores de pantalla vuelven al espacio interactivo para asegurarse de que la tarea se complete antes de continuar.
Después de inert
, no se requiere ninguna trampa porque puedes congelar o proteger secciones completas de la página o la app. Los clics y los intentos de cambio de enfoque simplemente no están disponibles mientras esas partes de un documento son inertes. También se puede pensar en esto como guardias en lugar de una trampa, en la que a inert
no le interesa que te quedes en un lugar, sino que otros lugares no estén disponibles.
Un buen ejemplo de esto es la función alert()
de JavaScript:
Observa en el video anterior cómo se podía acceder a la página con el mouse y el teclado hasta que se llamó a un alert()
. Una vez que se mostró la ventana emergente del diálogo de alerta, el resto de la página quedó inmovilizado o inert
. El enfoque del usuario se coloca dentro del diálogo de alerta y no tiene a dónde ir. Una vez que el usuario interactúa y completa la solicitud de la función de alerta, la página vuelve a ser interactiva. inert
permite que los desarrolladores logren esta misma experiencia de enfoque guiado con facilidad.
A continuación, se incluye un pequeño ejemplo de código para mostrar cómo funciona:
<body>
<div class="modal">
<h2>Modal Title</h2>
<p>...<p>
<button>Save</button>
<button>Discard</button>
</div>
<main inert>
<!-- cannot be keyboard focused or clicked -->
</main>
</body>
Un diálogo es un gran ejemplo, pero inert
también es útil para elementos como la experiencia del usuario del menú lateral desplegable. Cuando un usuario desliza el menú lateral, no es correcto permitir que el mouse o el teclado interactúen con la página que se encuentra detrás, ya que esto puede ser un poco complicado para los usuarios. En cambio, cuando se muestra el menú lateral, la página se vuelve inerte, y los usuarios deben cerrar el menú lateral o navegar dentro de él, y nunca se perderán en otro lugar de la página con un menú abierto.
Recursos
Fuentes COLRv1
Antes de las fuentes COLRv1, la Web tenía fuentes OT-SVG, que también son un formato abierto para fuentes con degradados y colores y efectos integrados. Sin embargo, podían crecer mucho y, si bien permitían editar el texto, no había mucho margen para la personalización.
Después de las fuentes COLRv1, la Web tiene fuentes más pequeñas, escalables vectorialmente, reposicionables, con degradados y con modos de fusión que aceptan parámetros para personalizar la fuente según el caso de uso o para que coincida con una marca.

Este es un ejemplo de la entrada de blog para desarrolladores de Chrome sobre emojis. Quizás notaste que, si aumentas el tamaño de la fuente de un emoji, no se mantiene nítido. Es una imagen, no arte vectorial. A menudo, en las aplicaciones, cuando se usa un emoji, se reemplaza por un recurso de mayor calidad. Con las fuentes COLRv1, los emojis son vectoriales y atractivos:
Las fuentes de íconos podrían hacer cosas increíbles con este formato, como ofrecer paletas de colores de dos tonos personalizadas y mucho más. Cargar una fuente COLRv1 es igual que cargar cualquier otro archivo de fuente:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
La personalización de la fuente COLRv1 se realiza con @font-palette-values
, una regla @ especial de CSS para agrupar y nombrar un conjunto de opciones de personalización en un paquete para su referencia posterior. Observa cómo especificas un nombre personalizado de la misma manera que una propiedad personalizada, comenzando con --
:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
Con --colorized
como alias para las personalizaciones, el último paso es aplicar la paleta a un elemento que usa la familia de fuentes de color:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
.spicy {
font-family: "Bungee Spice";
font-palette: --colorized;
}

Con la disponibilidad cada vez mayor de fuentes variables y fuentes de color, la tipografía web se encuentra en un camino muy magnífico hacia la personalización enriquecida y la expresión creativa.
Recursos
- Especificación de Colrv1 en GitHub
- Chrome Developers: Colrv1 Fonts (Chrome Developers: Fuentes Colrv1)
- Video explicativo para desarrolladores de BlinkOn
Unidades de viewport
Antes de las nuevas variantes del viewport, la Web ofrecía unidades físicas para ayudar a ajustar los viewports. Había uno para la altura, el ancho, el tamaño más pequeño (vmin) y el lado más grande (vmax). Funcionaron bien para muchas cosas, pero los navegadores para dispositivos móviles introdujeron una complejidad.
En dispositivos móviles, cuando se carga una página, se muestra la barra de estado con la URL, y esta barra consume parte del espacio de la ventana gráfica. Después de unos segundos y algo de interactividad, es posible que la barra de estado se deslice para permitir una experiencia de ventana gráfica más grande para el usuario. Sin embargo, cuando esa barra se desliza hacia afuera, la altura del viewport cambia, y cualquier unidad vh
se desplazaría y cambiaría de tamaño a medida que cambiara su tamaño objetivo.
En años posteriores, la unidad vh
necesitaba decidir específicamente cuál de los dos tamaños de viewport iba a usar, ya que causaba problemas visuales de diseño en los dispositivos móviles. Se determinó que vh
siempre representaría el viewport más grande.
.original-viewport-units {
height: 100vh;
width: 100vw;
--size: 100vmin;
--size: 100vmax;
}
Después de las nuevas variantes de viewport, se encuentran disponibles las unidades de viewport pequeñas, grandes y dinámicas, además de los equivalentes lógicos de los físicos. La idea es brindarles a los desarrolladores y diseñadores la capacidad de elegir qué unidad quieren usar para su situación específica. Quizás sea aceptable tener un pequeño cambio de diseño brusco cuando desaparece la barra de estado, por lo que dvh
(altura dinámica del viewport) se podría usar sin problemas.
A continuación, se incluye una lista completa de todas las opciones nuevas de unidades de viewport disponibles con las nuevas variantes de viewport:
.new-height-viewport-units { height: 100vh; height: 100dvh; height: 100svh; height: 100lvh; block-size: 100vb; block-size: 100dvb; block-size: 100svb; block-size: 100lvb; }
.new-width-viewport-units { width: 100vw; width: 100dvw; width: 100svw; width: 100lvw; inline-size: 100vi; inline-size: 100dvi; inline-size: 100svi; inline-size: 100lvi; }
.new-min-viewport-units { --size: 100vmin; --size: 100dvmin; --size: 100svmin; --size: 100lvmin; }
.new-max-viewport-units { --size: 100vmax; --size: 100dvmax; --size: 100svmax; --size: 100lvmax; }
Esperamos que esto les brinde a los desarrolladores y diseñadores la flexibilidad necesaria para lograr sus diseños adaptables a la ventana gráfica.
Recursos
:has()
Antes de :has()
, el sujeto de un selector siempre estaba al final. Por ejemplo, el sujeto de este selector es un elemento de lista: ul > li
. Los pseudoselectores pueden alterar el selector, pero no cambian el sujeto: ul > li:hover
o ul >
li:not(.selected)
.
Después de :has()
, un sujeto más alto en el árbol de elementos puede seguir siendo el sujeto mientras proporciona una búsqueda sobre los hijos: ul:has(> li)
. Es fácil comprender por qué :has()
recibió el nombre común de "selector principal", ya que el sujeto del selector ahora es el elemento principal en este caso.
Este es un ejemplo de sintaxis básica en el que la clase .parent
sigue siendo el sujeto, pero solo se selecciona si un elemento secundario tiene la clase .child
:
.parent:has(.child) {...}
Este es un ejemplo en el que un elemento <section>
es el sujeto, pero el selector solo coincide si uno de los elementos secundarios tiene :focus-visible
:
section:has(*:focus-visible) {...}
El selector :has()
comienza a convertirse en una herramienta fantástica una vez que se hacen evidentes los casos de uso más prácticos. Por ejemplo, actualmente no es posible seleccionar etiquetas <a>
cuando contienen imágenes, lo que dificulta enseñarle a la etiqueta de anclaje cómo cambiar sus estilos en ese caso de uso. Sin embargo, es posible con :has()
:
a:has(> img) {...}
Todos estos fueron ejemplos en los que :has()
solo parece un selector principal.
Considera el caso de uso de imágenes dentro de elementos <figure>
y ajusta los estilos en las imágenes si la figura tiene un <figcaption>
. En el siguiente ejemplo, se seleccionan figuras con leyendas y, luego, imágenes dentro de ese contexto. Se usa :has()
y no se cambia el tema, ya que el tema al que nos dirigimos son imágenes, no figuras:
figure:has(figcaption) img {...}
Las combinaciones parecen infinitas. Combina :has()
con consultas de cantidad y ajusta los diseños de cuadrícula CSS según la cantidad de elementos secundarios. Combina :has()
con estados de seudoclase interactivos y crea aplicaciones que respondan de formas creativas nuevas.
Comprobar la compatibilidad es sencillo con @supports
y su función selector()
, que prueba si el navegador comprende la sintaxis antes de usarla:
@supports (selector(:has(works))) {
/* safe to use :has() */
}
Recursos
- Especificación de:has()
- :has() en MDN
- El selector
:has()
de CSS es mucho más que un "selector principal"
2022 y años posteriores
Aún hay varias cosas que serán difíciles de hacer después de que se lancen todas estas increíbles funciones en 2022. En la siguiente sección, se analizan algunos de los problemas restantes y las soluciones que se están desarrollando de forma activa para resolverlos. Estas soluciones son experimentales, aunque se puedan especificar o estar disponibles detrás de marcas en los navegadores.
En las siguientes secciones, se debe tener la certeza de que muchas personas de muchas empresas buscan resolver los problemas mencionados, no que estas soluciones se lanzarán en 2023.
Propiedades personalizadas con escritura flexible
Las propiedades personalizadas de CSS son increíbles. Permiten almacenar todo tipo de elementos dentro de una variable con nombre, que luego se puede extender, calcular, compartir y mucho más. De hecho, son tan flexibles que sería bueno tener algunas que no lo fueran tanto.
Considera una situación en la que un box-shadow
usa propiedades personalizadas para sus valores:
box-shadow: var(--x) var(--y) var(--blur) var(--spread) var(--color);
Todo funciona bien hasta que una de las propiedades se cambia a un valor que CSS no acepta allí, como --x: red
. Toda la sombra se rompe si falta alguna de las variables anidadas o si se establece en un tipo de valor no válido.
Aquí es donde entra en juego @property
: --x
puede convertirse en una propiedad personalizada con tipo, ya no flexible y suelta, sino segura con algunos límites definidos:
@property --x {
syntax: '<length>';
initial-value: 0px;
inherits: false;
}
Ahora, cuando box-shadow
usa var(--x)
y, más tarde, se intenta usar --x: red
, se ignorará red
, ya que no es un <length>
. Esto significa que la sombra sigue funcionando, aunque se haya proporcionado un valor no válido para una de sus propiedades personalizadas.
En lugar de fallar, vuelve a su initial-value
de 0px
.
Animación
Además de la seguridad de tipos, también abre muchas puertas para la animación. La flexibilidad de la sintaxis de CSS hace que sea imposible animar algunas cosas, como los gradientes. @property
ayuda en este caso porque la propiedad CSS con tipo puede informar al navegador sobre la intención de un desarrollador dentro de una interpolación que, de otro modo, sería demasiado compleja. Básicamente, limita el alcance de las posibilidades de tal manera que un navegador puede animar aspectos de un diseño que antes no podía.
Considera este ejemplo de demostración, en el que se usa un gradiente radial para crear una parte de una capa superpuesta, lo que genera un efecto de foco de luz. JavaScript establece las coordenadas X e Y del mouse cuando se presiona la tecla Alt/Option y, luego, cambia el tamaño focal a un valor más pequeño, como el 25%, lo que crea el círculo de enfoque de luz en la posición del mouse:
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
}
Sin embargo, los gradientes no se pueden animar. Son demasiado flexibles y complejos para que el navegador "simplemente derive" cómo quieres que se animen. Sin embargo, con @property
, una propiedad se puede escribir y animar de forma aislada, por lo que el navegador puede comprender fácilmente la intención.
Los videojuegos que usan este efecto de enfoque siempre animan el círculo, desde un círculo grande hasta un círculo pequeño. A continuación, te mostramos cómo usar @property
con nuestra demostración para que el navegador anime la máscara de gradiente:
@property --focal-size {
syntax: '<length-percentage>';
initial-value: 100%;
inherits: false;
}
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
transition: --focal-size .3s ease;
}
Ahora el navegador puede animar el tamaño del gradiente porque redujimos la superficie de la modificación a una sola propiedad y escribimos el valor para que el navegador pueda interpolar de forma inteligente las longitudes.
@property
puede hacer mucho más, pero estas pequeñas habilitaciones pueden ser de gran utilidad.
Recursos
- @property specification
- @property en MDN
- @property en web.dev
- Demostración de enfoque con zoom
- CSS Tricks: Exploración de @property y sus poderes de animación
Estuvo en min-width
o max-width
Antes de los rangos de consultas de medios, una consulta de medios de CSS usaba min-width
y max-width
para expresar condiciones superiores e inferiores. Es posible que se vea de este modo:
@media (min-width: 320px) {
…
}
Después de los rangos de consultas de medios, la misma consulta de medios podría verse así:
@media (width >= 320px) {
…
}
Una consulta de medios CSS que usa min-width
y max-width
podría verse así:
@media (min-width: 320px) and (max-width: 1280px) {
…
}
Después de los rangos de consultas de medios, la misma consulta de medios podría verse así:
@media (320px <= width <= 1280px) {
…
}
Según tus conocimientos de programación, uno de ellos se verá mucho más legible que el otro. Gracias a las incorporaciones de especificaciones, los desarrolladores podrán elegir la que prefieran o incluso usarlas de forma intercambiable.
Recursos
- Especificación de la sintaxis del rango de consultas de medios
- Sintaxis del rango de consultas de medios en MDN
- Sintaxis de rangos de consultas de medios en el complemento de PostCSS
No hay variables de consultas de medios
Antes de @custom-media
, las consultas de medios debían repetirse una y otra vez, o bien depender de preprocesadores para generar el resultado adecuado en función de variables estáticas durante el tiempo de compilación.
Después de @custom-media
, CSS permite crear alias para las consultas de medios y hacer referencia a ellos, al igual que una propiedad personalizada.
Nombrar las cosas es muy importante: puede alinear el propósito con la sintaxis, lo que facilita compartir y usar las cosas en los equipos. Estas son algunas consultas de medios personalizadas que me acompañan entre proyectos:
@custom-media --OSdark (prefers-color-scheme: dark);
@custom-media --OSlight (prefers-color-scheme: light);
@custom-media --pointer (hover) and (pointer: coarse);
@custom-media --mouse (hover) and (pointer: fine);
@custom-media --xxs-and-above (width >= 240px);
@custom-media --xxs-and-below (width <= 240px);
Ahora que están definidos, puedo usar uno de ellos de la siguiente manera:
@media (--OSdark) {
:root {
…
}
}
Encuentra una lista completa de las consultas de medios personalizadas que uso en mi biblioteca de propiedades personalizadas de CSS Open Props.
Recursos
- Especificación de consultas de medios personalizadas
- Complemento de PostCSS para consultas de medios personalizadas
Anidar selectores es muy útil
Antes de @nest
, había mucha repetición en las hojas de estilo. Se volvió especialmente difícil de manejar cuando los selectores eran largos y cada uno apuntaba a pequeñas diferencias. La comodidad del anidamiento es uno de los motivos más comunes para adoptar un preprocesador.
Después de @nest
, la repetición desaparece. Casi todas las funciones del anidamiento habilitado para el preprocesador estarán disponibles integradas en CSS.
article {
color: darkgray;
}
article > a {
color: var(--link-color);
}
/* with @nest becomes */
article {
color: darkgray;
& > a {
color: var(--link-color);
}
}
Lo más importante de la anidación para mí, además de no repetir article
en el selector anidado, es que el contexto de diseño permanece dentro de un bloque de diseño.
En lugar de pasar de un selector y sus diseños a otro selector con diseños (ejemplo 1), el lector puede permanecer en el contexto de un artículo y ver los vínculos que contiene. La relación y la intención de estilo se agrupan, por lo que article
puede parecer que posee sus propios estilos.
La propiedad también se puede considerar como centralización. En lugar de buscar en una hoja de estilo los estilos pertinentes, todos se pueden encontrar anidados en un contexto. Esto funciona con relaciones de elemento superior a secundario, pero también con relaciones de elemento secundario a superior.
Considera un componente secundario que se quiere ajustar cuando está en un contexto superior diferente, en lugar de que el componente superior sea propietario del diseño y cambie un componente secundario:
/* parent owns this, adjusting children */
section:focus-within > article {
border: 1px solid hotpink;
}
/* with @nest becomes */
/* article owns this, adjusting itself when inside a section:focus-within */
article {
@nest section:focus-within > & {
border: 1px solid hotpink;
}
}
@nest
ayuda en general a organizar, centralizar y definir la propiedad de los estilos de forma más saludable. Los componentes pueden agrupar y poseer sus propios estilos, en lugar de tenerlos distribuidos entre otros bloques de estilos. Puede parecer pequeño en estos ejemplos, pero puede tener un gran impacto, tanto en la comodidad como en la legibilidad.
Recursos
Es muy difícil definir el alcance de los estilos
Antes de @scope
, existían muchas estrategias porque los estilos en CSS se aplican en cascada, se heredan y tienen un alcance global de forma predeterminada. Estas características de CSS son muy convenientes para muchas cosas, pero para sitios y aplicaciones complejos, con potencialmente muchos estilos diferentes de componentes, el espacio global y la naturaleza de la cascada pueden hacer que los estilos parezcan filtrarse.
Después de @scope
, los estilos no solo se pueden limitar a un contexto, como una clase, sino que también pueden indicar dónde terminan los estilos y no continúan en cascada ni se heredan.
En el siguiente ejemplo, el alcance de la convención de nomenclatura BEM se puede invertir en la intención real. El selector de BEM intenta definir el alcance del color de un elemento header
en un contenedor .card
con convenciones de nomenclatura. Esto requiere que el encabezado tenga este nombre de clase, lo que completa el objetivo. Con @scope
, no se requieren convenciones de nomenclatura para completar el mismo objetivo sin marcar el elemento de encabezado:
.card__header {
color: var(--text);
}
/* with @scope becomes */
@scope (.card) {
header {
color: var(--text);
}
}
Este es otro ejemplo, menos específico del componente y más sobre la naturaleza del alcance global de CSS. Los temas oscuro y claro deben coexistir dentro de una hoja de diseño, en la que el orden es importante para determinar un diseño ganador. Por lo general, esto significa que los estilos del tema oscuro se aplican después del tema claro, lo que establece el tema claro como el predeterminado y el oscuro como el estilo opcional. Evita la lucha por el orden y el alcance con @scope
:
@scope (.light-theme) {
a { color: purple; }
}
@scope (.dark-theme) {
a { color: plum; }
}
Para completar la historia aquí, @scope
también permite establecer dónde finaliza el alcance del diseño. Esto no se puede hacer con ninguna convención de nomenclatura ni con ningún preprocesador; es especial y solo lo puede hacer CSS integrado en el navegador. En el siguiente ejemplo, los estilos img
y .content
se aplican exclusivamente cuando un elemento secundario de un .media-block
es hermano o superior de .content
:
@scope (.media-block) to (.content) {
img {
border-radius: 50%;
}
.content {
padding: 1em;
}
}
Recursos
No hay forma de usar CSS para un diseño de mampostería
Antes de la disposición en mampostería con CSS y cuadrícula, JavaScript era la mejor manera de lograr un diseño de mampostería, ya que cualquiera de los métodos de CSS con columnas o Flexbox representaría de forma imprecisa el orden del contenido.
Después de la mampostería de CSS con cuadrícula, no se requerirán bibliotecas de JavaScript y el orden del contenido será correcto.

https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/
La demostración anterior se logró con el siguiente CSS:
.container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: masonry;
}
Es reconfortante saber que esta estrategia de diseño faltante está en la mira, además de que puedes probarla hoy mismo en Firefox.
Recursos
- Especificación del diseño de mampostería
- Diseño de mampostería en MDN
- Smashing Magazine: Diseño de mampostería de CSS nativo con CSS Grid
CSS no puede ayudar a los usuarios a reducir los datos
Antes de la consulta de medios prefers-reduced-data
, JavaScript y un servidor podían cambiar su comportamiento según el sistema operativo o la opción de "ahorro de datos" del navegador de un usuario, pero CSS no podía hacerlo.
Después de la consulta de medios prefers-reduced-data
, CSS puede unirse a la mejora de la experiencia del usuario y desempeñar su papel en el ahorro de datos.
@media (prefers-reduced-data: reduce) {
picture, video {
display: none;
}
}
El CSS anterior se usa en este componente de desplazamiento de medios, y los ahorros pueden ser enormes. Cuanto más grande sea el viewport de visita, más ahorros se obtendrán en la carga de la página. El guardado continúa mientras los usuarios interactúan con los controles deslizantes de medios. Todas las imágenes tienen atributos loading="lazy"
y, en combinación con el CSS que oculta el elemento por completo, esto significa que nunca se realiza una solicitud de red para la imagen.
En mis pruebas, en un viewport de tamaño mediano, se cargaron inicialmente 40 solicitudes y 700 KB de recursos. A medida que el usuario se desplaza por la selección de medios, se cargan más solicitudes y recursos. Con CSS y la consulta de medios de datos reducidos, se cargan 10 solicitudes y 172 KB de recursos. Esto equivale a medio megabyte de ahorro, y el usuario ni siquiera se desplazó por el contenido multimedia, por lo que no se realizaron solicitudes adicionales.
Esta experiencia de datos reducidos ofrece más ventajas que solo el ahorro de datos. Se pueden ver más títulos y no hay imágenes de portada que distraigan y roben la atención. Muchos usuarios navegan en un modo de ahorro de datos porque pagan por megabyte de datos, por lo que es muy bueno ver que CSS puede ayudar en este caso.
Recursos
- Especificación de prefers-reduced-data
- prefers-reduced-data en MDN
- Desafío de prefers-reduced-data en una GUI
- Smashing Magazine: Cómo mejorar las métricas web esenciales: un caso de estudio de Smashing Magazine
Las funciones de ajuste de desplazamiento son demasiado limitadas
Antes de estas propuestas de ajuste de desplazamiento, escribir tu propio código JavaScript para administrar un carrusel, un control deslizante o una galería podía volverse rápidamente complejo, con todos los observadores y la administración de estados. Además, si no se tiene cuidado, las velocidades de desplazamiento naturales podrían normalizarse con la secuencia de comandos, lo que haría que la interacción del usuario se sintiera un poco artificial y, posiblemente, torpe.
API nuevas
snapChanging()
Este evento se activa en cuanto el navegador libera un elemento secundario de ajuste. Esto permite que la IU refleje la falta de un elemento secundario de ajuste y el estado de ajuste indeterminado del desplazador, ya que ahora se está usando y se detendrá en algún lugar nuevo.
document.querySelector('.snap-carousel').addEventListener('snapchanging', event => {
console.log('Snap is changing', event.snappedTargetsList);
});
snapChanged()
Este evento se activa en cuanto el navegador se ajusta a un nuevo elemento secundario y el desplazador se detiene. Esto permite que cualquier IU que dependa del elemento secundario ajustado se actualice y refleje la conexión.
document.querySelector('.snap-carousel').addEventListener('snapchanged', event => {
console.log('Snap changed', event.snappedTargetsList);
});
scroll-start
El desplazamiento no siempre comienza al principio. Considera usar componentes deslizables en los que deslizar el dedo hacia la izquierda o la derecha active diferentes eventos, o una barra de búsqueda que, al cargar la página, esté oculta inicialmente hasta que te desplaces hacia la parte superior. Esta propiedad de CSS permite que los desarrolladores especifiquen que un elemento de desplazamiento debe comenzar en un punto específico.
:root { --nav-height: 100px }
.snap-scroll-y {
scroll-start-y: var(--nav-height);
}
:snap-target
Este selector CSS coincidirá con los elementos de un contenedor de ajuste de desplazamiento que el navegador haya ajustado actualmente.
.card {
--shadow-distance: 5px;
box-shadow: 0 var(--shadow-distance) 5px hsl(0 0% 0% / 25%);
transition: box-shadow 350ms ease;
}
.card:snapped {
--shadow-distance: 30px;
}
Después de estas propuestas de ajuste de desplazamiento, crear un control deslizante, un carrusel o una galería es mucho más fácil, ya que el navegador ahora ofrece comodidades para la tarea, lo que elimina los observadores y el código de orquestación de desplazamiento en favor del uso de APIs integradas.
Aún es muy pronto para estas funciones de CSS y JS, pero estate atento a los polyfills que pueden ayudar a adoptarlas y probarlas pronto.
Recursos
- Borrador de la especificación de Scroll Snap 2
- Explicaciones de Scroll Snap 2
- Demostraciones de Snap
Ciclo entre estados conocidos
Antes de toggle()
, solo se podían aprovechar los estados integrados en el navegador para el diseño y la interacción. Por ejemplo, la entrada de casilla de verificación tiene :checked
, un estado del navegador administrado internamente para la entrada que CSS puede usar para cambiar el elemento visualmente.
Después de toggle()
, se pueden crear estados personalizados en cualquier elemento para que CSS los cambie y los use para aplicar estilos. Permite agrupar, andar en bicicleta, activar o desactivar de forma dirigida y mucho más.
En el siguiente ejemplo, se logra el mismo efecto de tachado de un elemento de lista cuando se completa, pero sin ningún elemento de casilla de verificación:
<ul class='ingredients'>
<li>1 banana
<li>1 cup blueberries
...
</ul>
Y los estilos toggle()
de CSS pertinentes:
li {
toggle-root: check self;
}
li:toggle(check) {
text-decoration: line-through;
}
Si conoces las máquinas de estados, es posible que notes la gran cantidad de coincidencias con toggle()
. Esta función permitirá a los desarrolladores incorporar más estados en CSS, lo que, con suerte, generará formas más claras y semánticas de orquestar la interacción y el estado.
Recursos
Cómo personalizar elementos de selección
Antes de <selectmenu>
, CSS no podía personalizar los elementos <option>
con HTML enriquecido ni cambiar mucho la visualización de una lista de opciones.
Esto llevó a los desarrolladores a cargar bibliotecas externas que recreaban gran parte de la funcionalidad de un <select>
, lo que terminó siendo mucho trabajo.
Después de <selectmenu>
, los desarrolladores pueden proporcionar HTML enriquecido para los elementos de opciones y darles el estilo que necesiten, sin dejar de cumplir con los requisitos de accesibilidad y proporcionar HTML semántico.
En el siguiente ejemplo, extraído de la página de explicación de <selectmenu>
, se crea un nuevo menú de selección con algunas opciones básicas:
<selectmenu>
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</selectmenu>
El CSS puede segmentar y diseñar las partes del elemento:
.my-select-menu::part(button) {
color: white;
background-color: red;
padding: 5px;
border-radius: 5px;
}
.my-select-menu::part(listbox) {
padding: 10px;
margin-top: 5px;
border: 1px solid red;
border-radius: 5px;
}
Puedes probar el elemento <selectmenu>
en Chromium Canary con la marca de experimentos web habilitada. En 2023 y años posteriores, podrás personalizar los elementos del menú de selección.
Recursos
Cómo anclar un elemento a otro
Antes de anchor()
, las posiciones absoluta y relativa eran estrategias de posición que se proporcionaban a los desarrolladores para que los elementos secundarios se movieran dentro de un elemento principal.
Después de anchor()
, los desarrolladores pueden posicionar elementos en relación con otros, independientemente de si son secundarios o no. También permite que los desarrolladores especifiquen contra qué borde posicionar y otras opciones para crear relaciones de posición entre elementos.
En el explicador, se proporcionan algunos ejemplos y muestras de código excelentes si te interesa obtener más información.