Diseños de CSS y diseño responsivo

  1. 1 Aspectos básicos
    1. ¿Qué modo de diseño usar?
    2. Principios de funcionamiento
  2. 2 Flexbox
  3. 3 Cuadrícula y subcuadrícula
    1. Ejemplo de código: cuadrícula y subcuadrícula
  4. 4 Consultas de contenedores
    1. Ejemplo de código: Tipografía fluida con unidades de consulta de contenedor
  5. 5 Superposiciones nativas, posicionamiento de anclas y contextos de apilamiento
  6. 6 Seguimiento del desbordamiento y estabilidad del diseño
  7. 7 Mecánica de la ventana de visualización y distribución de pistas
  8. 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.

  1. ¿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.
  2. ¿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.
  3. ¿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.
  4. ¿El contenido es un flujo largo de prosa que debería dividirse en columnas equilibradas? Usa varias columnas: flujo 1D, estilo periódico.
  5. ¿Hay elementos de diferentes alturas que se deben empaquetar de forma compacta? Usa grid con grid-auto-flow: dense hoy; 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).
  6. ¿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-name en el activador y position-anchor en 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 de width/height para tener menos consultas de medios y diseños más resilientes.
  • NO uses overflow: hidden para enmascarar problemas de diseño; corrígelos en la fuente. Por ejemplo, ciertos elementos reemplazados, como <canvas>, <img>, <svg>, <video> y <iframe>, usan display: inline de forma predeterminada, lo que puede agregar un espacio en ciertos diseños. En lugar de recortar el espacio con overflow, quítalo aplicando un valor de visualización externa de bloque (p. ej., display: block, grid, flex, etc.).
  • Usa aspect-ratio para 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: flex y el eje principal con flex-direction (row predeterminado).
  • Usa flex-wrap: wrap siempre que sea posible que se produzca un desbordamiento; nowrap sin overflow: auto/hidden se desbordará en viewports estrechos.
  • Aplica la capa flex-wrap: balance después de flex-wrap: wrap en 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 a wrap.
  • Usa la abreviatura <grow> <shrink> <basis> de flex (p.ej., flex: 1 1 250px) en los elementos en lugar de configurar flex-grow/flex-shrink/flex-basis de forma individual.
  • Usa gap (o la forma larga row-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 (o margin-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-items para centrar todos los elementos en el eje transversal; usa margin: auto en un solo elemento para centrarlo en ambos ejes de forma independiente; usa align-content solo cuando el contenedor se ajuste y tenga espacio adicional entre las filas.
  • Establece min-inline-size: 0 (o min-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-self en 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 order ni flex-direction: *-reverse para 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) con space-evenly (espacios iguales antes, entre y después).
  • No olvides el cambio de eje: cuando flex-direction: column, justify-content se alinea en el eje de bloque y align-items se 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-basis y width/inline-size en el mismo elemento, ya que flex-basis tiene prioridad en un contexto flexible y se ignora width. Usa flex-basis (o la abreviatura flex) 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-areas para 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
  • ¿Necesitas colocar un elemento en una ubicación específica?
    • Sí: Usa grid-column: <start> / <end> o grid-area: <name>
    • No (solo abarca varias pistas, la posición del flujo no importa): usa grid-column: span <n>
  • ¿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-columns para 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-areas para 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, o auto-fill para conservar las pistas repetidas vacías en su tamaño mínimo.
  • Usa fr para la distribución proporcional de pistas y minmax(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 o grid-area: <name> para regiones con nombre.
  • Usa subgrid (grid-template-columns: subgrid o grid-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/-columns explí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-fill provenga del contenido del elemento, sino del argumento de tamaño repeat().
  • No uses grid-auto-flow: dense en 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-columns para el eje implícito.
  • No confundas justify-items/align-items (alinea el contenido del elemento dentro de su pista) con justify-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 un inline-size definido en el contenedor. Dentro de display: inline-grid o 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) o container-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 abreviatura container: 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-size definido al contenedor cada vez que se use container-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-size como valor de container-type, ya que no es válido. Usa size para 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 popover para 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 de z-index.
  • Usa <dialog> con .showModal() para interacciones modales que requieran captura de enfoque y un fondo inerte.
  • No combines popover y .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 (o anchor() en inserciones) y anchor-size() para posicionar y ajustar el tamaño de una superposición en relación con su activador.
  • Usa position-try-fallbacks: flip-block (o flip-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: auto para que las barras de desplazamiento aparezcan solo cuando el contenido se desborde.
  • Usa overflow: clip para recortar contenido sin establecer un contenedor de desplazamiento. Elige el desbordamiento con overflow-clip-margin.
  • Usa scrollbar-gutter: stable para reservar espacio para las barras de desplazamiento y evitar cambios en el diseño cuando el contenido crece.
  • Usa overscroll-behavior: contain (o none) en regiones de desplazamiento anidadas (como barras laterales, modales y listas) para evitar que las cadenas de desplazamiento se propaguen a la página, o overscroll-behavior: chain en 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: vertical para el truncamiento de varias líneas. A pesar del prefijo, este patrón está completamente especificado y no está obsoleto. Declara la abreviatura line-clamp sin 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: scroll cuando auto sea suficiente, ya que scroll fuerza las barras de desplazamiento incluso cuando no hay nada para desplazar.

  • No uses overflow: hidden cuando solo quieras recortar; hidden establece 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: clip y overflow-clip-margin, consulta Control de recorte de desbordamiento. Para obtener información sobre la transferencia de desplazamiento anidado con overscroll-behavior: chain en 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/dvw para 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 100vw para el diseño de ancho completo, ya que ignora el ancho de la barra de desplazamiento y provoca un desbordamiento horizontal. En su lugar, usa 100%, 100dvw o 100svw.

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: dense para 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: masonry solo como una mejora progresiva: detecta funciones con @supports.

No hagas lo siguiente:

  • No envíes grid-template-rows: masonry como 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;
  }
}