- 1 Aspectos básicos
- 2 Flexbox
- 3 Cuadrícula y subcuadrícula
- 4 Consultas de contenedores
- 5 Superposiciones nativas, posicionamiento de anclas y contextos de apilamiento
- 6 Seguimiento del desbordamiento y estabilidad del diseño
- 7 Mecánica de la ventana de visualización y distribución de pistas
- 8 carriles de cuadrícula (también conocido como mampostería)
1 Aspectos básicos
Cuando sea posible, utiliza el motor de diseño del navegador para obtener un mejor rendimiento. Usa el tamaño intrínseco, las propiedades lógicas y aspect-ratio antes de recurrir a dimensiones codificadas o consultas de medios complicadas.
1.1 ¿Qué modo de diseño usar?
Recorre el árbol de decisión de arriba abajo y detente en la primera coincidencia. Ten en cuenta que los diseños se pueden anidar entre sí y que cada decisión se basa en el caso de uso de ese contenedor.
- ¿Es una fila O columna simple de elementos? Usa flexbox: 1D, primero el contenido, el contenido se distribuye a lo largo de un solo eje.
- ¿Un elemento anidado debe alinearse con las pistas de la cuadrícula de su elemento principal? Usa subgrid: 2D, prioriza las relaciones, hereda las pistas de los elementos superiores para que los elementos secundarios puedan alinearse con los elementos hermanos.
- ¿Es una estructura de página o componente compleja con filas Y columnas? Usa grid: es bidimensional, se enfoca en el diseño, tú defines el esqueleto y el contenido lo completa.
- ¿El contenido es un flujo largo de prosa que debería dividirse en columnas equilibradas? Usa varias columnas: flujo 1D, estilo periódico.
- ¿Hay elementos de diferentes alturas que se deben empaquetar de forma compacta? Usa grid con
grid-auto-flow: densehoy; recurre a la mampostería nativa (también conocida como "carriles de cuadrícula") solo cuando se envíe en tu objetivo de Baseline (consulta §8). - ¿Un elemento necesita flotar sobre la página y permanecer vinculado espacialmente a un activador, incluso a través de los límites del DOM o los contextos de apilamiento? Usa el posicionamiento de anclaje:
anchor-nameen el activador yposition-anchoren la superposición (consulta el artículo 5).
1.2 Principios de funcionamiento
- Usa propiedades lógicas (
inline-size,block-size,margin-inline,padding-block,inset-inline-start) para las dimensiones y el espaciado del diseño. Consulta CSS: Arquitectura moderna para obtener una cobertura completa. - Aplica el modelo mental de contenido primero frente a diseño primero: flexbox cuando los elementos dictan el flujo, cuadrícula cuando defines primero el esqueleto.
- Usa las abreviaturas de
place-*(place-content,place-items,place-self) para alinear en ambos ejes en una declaración. - Usa el tamaño intrínseco (
min-content,max-content,fit-content()) y las pistas flexibles (fr,minmax()) antes de los valores fijos dewidth/heightpara tener menos consultas de medios y diseños más resilientes. - NO uses
overflow: hiddenpara enmascarar problemas de diseño; corrígelos en la fuente. Por ejemplo, ciertos elementos reemplazados, como<canvas>,<img>,<svg>,<video>y<iframe>, usandisplay: inlinede forma predeterminada, lo que puede agregar un espacio en ciertos diseños. En lugar de recortar el espacio conoverflow, quítalo aplicando un valor de visualización externa de bloque (p. ej.,display: block,grid,flex, etc.). - Usa
aspect-ratiopara reservar espacio para el contenido multimedia y evitar cambios en el diseño antes de que se carguen los recursos.
.sidebar { inline-size: max-content; } /* Size to longest unbreakable token. */
.main-content { inline-size: fit-content; } /* Grow to available space, no further. */
.media { aspect-ratio: 16 / 9; inline-size: 100%; block-size: auto; }
body.centered { display: grid; place-content: center; min-block-size: 100dvb; }
Para obtener información sobre
calc-size()y el tamaño intrínseco que tiene en cuenta las restricciones, consulta Cómo calcular con tamaños intrínsecos.
2 Flexbox
Diseño unidimensional: Los elementos fluyen a lo largo de un solo eje principal con alineación en el eje transversal. Úsala para barras de navegación, barras de herramientas, filas de elementos y cualquier distribución de una sola fila o columna.
Qué debes hacer:
- Establece un contexto con
display: flexy el eje principal conflex-direction(rowpredeterminado). - Usa
flex-wrap: wrapsiempre que sea posible que se produzca un desbordamiento;nowrapsinoverflow: auto/hiddense desbordará en viewports estrechos. - Aplica la capa
flex-wrap: balancedespués deflex-wrap: wrapen las filas ajustadas de elementos compactos (como nubes de etiquetas, pastillas de filtro, grupos de botones o vínculos de navegación) para distribuir los elementos de manera uniforme entre las líneas y evitar que quede un solo elemento huérfano en la fila final. Los navegadores que no admiten esta función recurren awrap. - Usa la abreviatura
<grow> <shrink> <basis>deflex(p.ej.,flex: 1 1 250px) en los elementos en lugar de configurarflex-grow/flex-shrink/flex-basisde forma individual. - Usa
gap(o la forma largarow-gap/column-gap) para el espaciado entre elementos en lugar de los márgenes secundarios. - Agrega el prefijo de alineación posicional con
safe(p.ej.,align-items: safe center) para que el contenido enfocable no se recorte cuando el contenedor sea más estrecho que su contenido. - Empuja un solo elemento al extremo del eje principal con
margin-inline-start: auto(omargin-block-start: auto), que es la salida de emergencia estándar. - Anula la alineación del eje transversal por elemento con
align-self. - Usa
align-itemspara centrar todos los elementos en el eje transversal; usamargin: autoen un solo elemento para centrarlo en ambos ejes de forma independiente; usaalign-contentsolo cuando el contenedor se ajuste y tenga espacio adicional entre las filas. - Establece
min-inline-size: 0(omin-width: 0) en los elementos flexibles que contengan contenido largo que no se pueda dividir (URLs, código, cadenas largas). De forma predeterminada, los elementos flexibles no se reducirán por debajo del tamaño de su contenido, lo que provocará un desbordamiento.
No hagas lo siguiente:
- No uses
justify-selfen elementos flexibles, ya que solo funciona en diseños de cuadrícula, de bloque y con posicionamiento absoluto. En su lugar, usa márgenes automáticos. - No uses
orderniflex-direction: *-reversepara reordenar el contenido interactivo. Solo cambian el orden visual; el orden del DOM sigue controlando el enfoque secuencial, por lo que el flujo de tabulación del teclado no coincidirá con lo que ve el usuario. - No confundas
space-around(medio espacio en los extremos) conspace-evenly(espacios iguales antes, entre y después). - No olvides el cambio de eje: cuando
flex-direction: column,justify-contentse alinea en el eje de bloque yalign-itemsse alinea en el eje intercalado, lo opuesto al valor predeterminado. - No configures el tamaño del contenedor y de sus elementos secundarios para que se llenen entre sí, ya que esto suele provocar desbordamientos y resultados inesperados. Asigna un tamaño definido a un lado.
- No establezcas
flex-basisywidth/inline-sizeen el mismo elemento, ya queflex-basistiene prioridad en un contexto flexible y se ignorawidth. Usaflex-basis(o la abreviaturaflex) como la fuente única de información para ajustar el tamaño de los elementos flexibles.
.card-grid { display: flex; flex-flow: row wrap; gap: 1rem; }
.card-item { flex: 1 1 250px; } /* grow, shrink, basis */
.card-item-action { margin-inline-start: auto; } /* Push to main-axis end. */
.toolbar { display: flex; align-items: safe center; }
.tag-list { display: flex; flex-wrap: wrap; flex-wrap: balance; gap: 0.5rem; }
3 Cuadrícula y subcuadrícula
Diseño bidimensional: Define filas Y columnas de forma explícita, o deja que el motor las derive. Subgrid permite que una cuadrícula anidada herede las pistas de su elemento superior para que los elementos secundarios se alineen con los elementos hermanos.
Cómo elegir las funciones de cuadrícula:
- ¿Sabes exactamente cuántas columnas necesitas?
- Sí: Usa pistas explícitas (
grid-template-columns: 200px 1fr,repeat(3, 1fr), etc.) - ¿Las diferentes columnas necesitan tamaños diferentes (barra lateral + principal, encabezado que abarque todo)? → Usa
grid-template-areaspara las regiones con nombre legibles. - ¿Todas las columnas son uniformes o se posicionan únicamente por número de línea? → Usa
repeat(N, ...)o líneas con nombre - No (responsivo, recuento de elementos desconocido): usa
repeat(auto-fit, minmax(min, 1fr)) - ¿Los elementos de la última fila deben estirarse para llenar el espacio restante? →
auto-fit - ¿Las pistas vacías de la última fila deben mantener su tamaño mínimo (conservando los espacios fantasma de las columnas)? →
auto-fill
- Sí: Usa pistas explícitas (
- ¿Necesitas colocar un elemento en una ubicación específica?
- Sí: Usa
grid-column: <start> / <end>ogrid-area: <name> - No (solo abarca varias pistas, la posición del flujo no importa): usa
grid-column: span <n>
- Sí: Usa
- ¿Los elementos secundarios deben heredar los tamaños de las pistas de la cuadrícula superior (alineación de bordes irregulares entre elementos hermanos)?
- Sí: Usa subgrid en el eje afectado.
- ¿La cantidad de niños por celda es variable? → subgrid solo en un eje; usa
grid-auto-rows/grid-auto-columnspara el otro - ¿Se corrigió el recuento de secundarios? → subgrid on both axes is fine
- No: Cuadrícula estándar, no se necesita una subcuadrícula
Qué debes hacer:
- Establece un contexto con
display: grid. - Usa
grid-template-areaspara diseños complejos a nivel de página: los nombres de las áreas se autodocumentan y la declaración se puede alinear en filas y columnas para facilitar la lectura. - Usa
repeat(auto-fit, minmax(200px, 1fr))para cuadrículas de tarjetas responsivas que estiran las pistas completas para llenar la fila, oauto-fillpara conservar las pistas repetidas vacías en su tamaño mínimo. - Usa
frpara la distribución proporcional de pistas yminmax(min, max)para las pistas flexibles, pero limitadas. - Posiciona elementos con
grid-column: span <n>para ajustar el tamaño en las pistas,grid-column: <start> / <end>para colocarlos en líneas específicas ogrid-area: <name>para regiones con nombre. - Usa subgrid (
grid-template-columns: subgridogrid-template-rows: subgrid) para resolver el problema de los "bordes irregulares" en las listas de tarjetas: los elementos internos, como los títulos, los metadatos y los CTA, se alinean entre los elementos hermanos. - Vincula una declaración de subcuadrícula con una declaración
grid-template-rows/-columnsexplícita anterior como resguardo de la misma cascada para navegadores más antiguos.
No hagas lo siguiente:
- No esperes que el tamaño de la pista
auto-fit/auto-fillprovenga del contenido del elemento, sino del argumento de tamañorepeat(). - No uses
grid-auto-flow: denseen contenido interactivo. Empaqueta los elementos de forma eficiente, pero los reordena visualmente, lo que interrumpe el flujo de pestañas del teclado en el orden del DOM. - No apliques la subcuadrícula a ambos ejes cuando el recuento de elementos secundarios sea variable. Los elementos adicionales se ubican en la última pista. En su lugar, usa
grid-auto-rows/grid-auto-columnspara el eje implícito. - No confundas
justify-items/align-items(alinea el contenido del elemento dentro de su pista) conjustify-content/align-content(alinea las pistas de la cuadrícula dentro del contenedor). Si usas la incorrecta, no tendrá ningún efecto. - No uses
repeat(auto-fit/auto-fill, ...)sin uninline-sizedefinido en el contenedor. Dentro dedisplay: inline-grido de un elemento flexible sin tamaño, el contenedor no tiene un ancho para dividir, lo que hace que los recuentos de pistas sean impredecibles.
3.1 Ejemplo de código: cuadrícula y subcuadrícula
Page shell: <main class="page-layout"> contiene <header>, <aside>, un <section class="card-grid"> con <div class="card"> elementos secundarios y <footer>.
/* Align grid-template-areas in rows and columns for readability. */
.page-layout {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
gap: 1.5rem;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
footer { grid-area: footer; }
.card-grid {
grid-area: main;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-template-rows: auto 1fr; /* title block, body block */
gap: 1rem;
}
.card {
grid-row: span 2;
display: grid;
/* Same-cascade fallback: ignored when subgrid is supported. */
grid-template-rows: auto 1fr;
grid-template-rows: subgrid;
}
4 Consultas de contenedor
Consulta el tamaño (o el estilo calculado) de un contenedor principal en lugar del viewport. Modelo mental: consultas de contenedores = contexto del componente; consultas de medios = diseño global de la página y preferencias del usuario (prefers-color-scheme, prefers-reduced-motion).
Qué debes hacer:
- Establece un contexto de contención con
container-type: inline-size(solo consultas de ancho) ocontainer-type: size(ambos ejes) en un wrapper antes de que se puedan consultar sus descendientes. - Asigna nombres a los contenedores con
container-name(o la abreviaturacontainer:container: card / inline-size) cuando los contextos anidados puedan entrar en conflicto. - Incluye unidades de consulta de contenedor en el cálculo del tipo y el espaciado fluidos:
cqi/cqb(en línea/bloque lógico),cqw/cqh(físico),cqmin/cqmax. - Asigna un
block-sizedefinido al contenedor cada vez que se usecontainer-type: size. De lo contrario, los descendientes se contraen porque la contención de tamaño obliga al contenedor a ignorar su contenido.
No hagas lo siguiente:
- No uses
block-sizecomo valor decontainer-type, ya que no es válido. Usasizepara ambos ejes. - No esperes que el tamaño intrínseco de los elementos secundarios influya en el contenedor después de declarar
container-type. El contenedor se calcula como si no tuviera elementos secundarios una vez que se activa la contención. - No dependas de las unidades de consulta de contenedor dentro de los descendientes de un ancestro que no cumple con los requisitos; recurren al viewport pequeño (
svw/svh).
4.1 Ejemplo de código: Tipografía fluida con unidades de consulta de contenedor
.card-wrapper {
container: card / inline-size; /* shorthand for container-name / container-type */
}
@container card (inline-size > 400px) {
.content {
display: flex;
gap: 2rem;
}
}
.title {
/* Fluid type bound to the container width, not the viewport. */
font-size: clamp(1rem, 4cqi, 2rem);
}
Para conocer los patrones de diseño responsivo basados en componentes, consulta Estilo adaptado al tamaño y Escalamiento fluido.
5 Superposiciones nativas, posicionamiento de anclas y contextos de apilamiento
Cuándo usar cada primitiva de superposición:
- Usa
popoverpara la IU transitoria no modal (menús flotantes, avisos emergentes, cuadros de información). Se encuentra en la capa superior y no se necesita administración dez-index. - Usa
<dialog>con.showModal()para interacciones modales que requieran captura de enfoque y un fondo inerte. - No combines
popovery.showModal()en el mismo elemento, ya que son estados de tiempo de ejecución mutuamente excluyentes.
Posicionamiento de los puntos de referencia (diseño espacial de las superposiciones):
- Usa
position-area(oanchor()en inserciones) yanchor-size()para posicionar y ajustar el tamaño de una superposición en relación con su activador. - Usa
position-try-fallbacks: flip-block(oflip-inline) para permitir que el navegador cambie la posición cuando la superposición desborde el viewport. - No mezcles palabras clave físicas y lógicas en un solo valor de
position-area; elige un sistema de coordenadas. - Detecta la función con
@supports (anchor-name: --x)y proporciona un resguardo de posición absoluta.
Para obtener detalles completos de la implementación, estrategias de polyfill y la referencia de valores de
popover, consulta Control declarativo de diálogos y ventanas emergentes y Información sobre herramientas que tiene en cuenta la posición. Para conocer el posicionamiento de anclaje aplicado a menús desplegables, ventanas emergentes y marcadores de pestañas, consulta Menús desplegables que se adaptan al viewport y Subrayado de pestañas con posicionamiento de anclaje.
6 Seguimiento del desbordamiento y estabilidad del diseño
Administra los cambios de diseño, las barras de desplazamiento y el recorte de forma predecible.
Qué debes hacer:
- Usa
overflow: autopara que las barras de desplazamiento aparezcan solo cuando el contenido se desborde. - Usa
overflow: clippara recortar contenido sin establecer un contenedor de desplazamiento. Elige el desbordamiento conoverflow-clip-margin. - Usa
scrollbar-gutter: stablepara reservar espacio para las barras de desplazamiento y evitar cambios en el diseño cuando el contenido crece. - Usa
overscroll-behavior: contain(onone) en regiones de desplazamiento anidadas (como barras laterales, modales y listas) para evitar que las cadenas de desplazamiento se propaguen a la página, ooverscroll-behavior: chainen contenedores de desplazamiento intermedios (como pistas de deslizamiento para revelar) cuando el desplazamiento excesivo deba propagarse a un desplazador superior sin activar un rebote de banda elástica local. Usa la tríada
-webkit-line-clamp+display: -webkit-box+-webkit-box-orient: verticalpara el truncamiento de varias líneas. A pesar del prefijo, este patrón está completamente especificado y no está obsoleto. Declara la abreviaturaline-clampsin prefijo junto a ella. Los navegadores que aún no la admiten ignoran la propiedad sin causar problemas. No hagas lo siguiente:No uses
overflow: scrollcuandoautosea suficiente, ya quescrollfuerza las barras de desplazamiento incluso cuando no hay nada para desplazar.No uses
overflow: hiddencuando solo quieras recortar;hiddenestablece un contenedor de desplazamiento que se puede desplazar de forma programática.
.scrollable-list {
max-block-size: 400px;
overflow-y: auto;
scrollbar-gutter: stable; /* Reserve scrollbar space. */
overscroll-behavior: contain; /* No scroll chaining into the page. */
}
.snippet {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
line-clamp: 3; /* Ignored where unsupported. */
overflow: clip;
}
Para obtener información detallada sobre
overflow: clipyoverflow-clip-margin, consulta Control de recorte de desbordamiento. Para obtener información sobre la transferencia de desplazamiento anidado conoverscroll-behavior: chainen la IU de deslizar para revelar, consulta Desliza para revelar. Para conocer el color, el tamaño y el tema de la barra de desplazamiento, consulta Personaliza el color o el grosor de una barra de desplazamiento, Modo oscuro y Adapta la barra de desplazamiento a las preferencias de contraste alto.
7 Mecánica de la ventana de visualización y distribución de pistas
- Usa
dvh/dvwpara los contenedores de diseño para dispositivos móviles que deben tener en cuenta los cambios en la IU del navegador (contraer o expandir la barra de URL). - No uses
100vwpara el diseño de ancho completo, ya que ignora el ancho de la barra de desplazamiento y provoca un desbordamiento horizontal. En su lugar, usa100%,100dvwo100svw.
Para conocer el punto de entrada del diseño responsivo (unidades de viewport dinámicas, reserva de espacio para contenido multimedia, tipografía fluida), consulta Diseño responsivo.
8 líneas de cuadrícula (también conocidas como mampostería)
La especificación está en desarrollo con el nombre "carriles de cuadrícula" (p.ej., display: grid-lanes), mientras que los prototipos experimentales anteriores usaban grid-template-rows: masonry.
Qué debes hacer:
- Usa la cuadrícula con
grid-auto-flow: densepara un empaquetado ajustado hoy, aceptando que el orden del DOM puede no coincidir con el orden visual. - Usa varias columnas (
columns: 3; column-gap: 1rem) para el flujo de tipo mampostería con mucho contenido cuando los elementos sean fragmentos de documentos en lugar de tarjetas de igual peso. - Trata
grid-template-rows: masonrysolo como una mejora progresiva: detecta funciones con@supports.
No hagas lo siguiente:
- No envíes
grid-template-rows: masonrycomo un requisito estricto hasta que tu objetivo de Baseline se ponga al día.
.gallery { columns: 3 200px; column-gap: 1rem; }
.gallery > * { break-inside: avoid; margin-block-end: 1rem; }
@supports (grid-template-rows: masonry) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
columns: unset;
}
}