README · by ansango
← Volver al libro

Basic visual formatting

El modelo de caja. Cómo CSS calcula el tamaño y posición de los elementos. Display, sizing, block vs inline, el containing block

~2 min de lectura
Resumen

Esta nota cubre el capítulo 6 del libro: el modelo de caja básico. Cómo CSS decide el tamaño y la posición de los elementos. Los conceptos de containing block, display, block vs inline, width/height, sizing algorithm y los cambios que introduce el box-sizing. La base para entender todos los capítulos de layout siguientes.

El modelo de caja

Todo elemento en CSS es una caja rectangular. Esta es la idea central:

La caja:

  ┌─────────────────────────────┐
  │           margin              │  ← espacio exterior
  │  ┌───────────────────────┐   │
  │  │      border           │   │  ← línea del borde
  │  │  ┌───────────────┐   │   │
  │  │  │   padding     │   │   │  ← espacio interior
  │  │  │  ┌─────────┐   │   │   │
  │  │  │  │ content │   │   │   │  ← el contenido
  │  │  │  └─────────┘   │   │   │
  │  │  └───────────────┘   │   │
  │  └───────────────────────┘   │
  └─────────────────────────────┘
Pieza por pieza

Las notas 06, 07 y 08 profundizan en cada parte. Esta nota da el marco.

Display

La propiedad display es la más importante de CSS. Define cómo se ve una caja:

display: block;             /* por defecto para <div>, <p>, <h1> */
display: inline;            /* por defecto para <span>, <a>, <em> */
display: inline-block;      /* híbrido */
display: flex;              /* flexbox */
display: grid;              /* grid */
display: none;              /* oculto, no ocupa espacio */
display: contents;          /* solo contenido, no la caja */
display: flow-root;         /* nuevo block formatting context */
“El display es el ADN del layout.”

El libro es claro: display define el comportamiento del elemento. Todo el layout depende de él.

Block vs inline

/* Block: ocupa todo el ancho, salto de línea */
div { display: block; }

/* Inline: solo el espacio del contenido */
span { display: inline; }
Block:

  - Salto de línea antes y después.
  - width y height se respetan.
  - padding, margin, border aplicados a los cuatro lados.
  - Por defecto: <div>, <p>, <h1>, <ul>, <li>, <section>.

Inline:

  - Sin salto de línea.
  - width y height NO se respetan.
  - padding y margin verticales NO afectan al line-height.
  - Por defecto: <span>, <a>, <em>, <strong>, <img>.

Inline-block

.button {
    display: inline-block;
    padding: 0.5em 1em;
    border: 1px solid #ccc;
}
Inline-block:

  - Inline por fuera (no fuerza newline).
  - Block por dentro (respeta width/height).
  - Muy útil para botones, badges.

Display none

.hidden {
    display: none;
}
display: none:

  - El elemento NO se renderiza.
  - NO ocupa espacio en el layout.
  - NO es accesible para screen readers.
  - Para accesibilidad, usar visibility: hidden o aria-hidden.

Visibility

.invisible {
    visibility: hidden;
}

.collapse {
    visibility: collapse;  /* table-specific */
}
visibility:

  - hidden: no visible, pero ocupa espacio.
  - visible: el default.
  - collapse: en tablas, quita la fila/columna.
  - Más accesible que display: none.

Containing block

El containing block es el rectángulo de referencia para el elemento:

Reglas:

  - El containing block del elemento raíz es el viewport.
  - Para elementos estáticos, es el content box del padre.
  - Para elementos con posición, depende del position.
.parent {
    width: 500px;
    padding: 20px;
}

.child {
    width: 50%;  /* 250px - relativo al content box del padre */
}
El containing block es el padre

Para la mayoría de cálculos, el containing block es el content box del padre (no el padding box ni el border box).

Box sizing

/* Default: content-box */
.box {
    box-sizing: content-box;
    width: 200px;
    padding: 20px;
    border: 1px solid #000;
    /* El width real es 200 + 40 + 2 = 242px */
}

/* Mejor: border-box */
.box {
    box-sizing: border-box;
    width: 200px;
    padding: 20px;
    border: 1px solid #000;
    /* El width real es 200px, content = 158px */
}
box-sizing:

  - content-box: width = solo content.
  - border-box: width = content + padding + border.
  - Con border-box, el width es lo que tú specifies.
  - Con content-box, el width es solo el contenido.

Reset recomendado

* {
    box-sizing: border-box;
}

*, *::before, *::after {
    box-sizing: border-box;
}
Reset:

  - Aplicar border-box a todos los elementos.
  - Hace el width más predecible.
  - Es el comportamiento que la mayoría quiere.

Width y height

.box {
    width: 100px;
    height: 50px;
}

.box-fluid {
    width: 100%;
    max-width: 800px;
    min-width: 200px;
}
Width/Height:

  - Aceptan length, percentage, auto.
  - max-width: límite superior.
  - min-width: límite inferior.
  - auto: el navegador decide.

Auto

.box {
    width: auto;     /* toma el espacio disponible */
    height: auto;    /* toma el contenido */
}
Auto:

  - En block: ocupa todo el ancho disponible.
  - En inline: solo el contenido.
  - En flex/grid: lo que el algoritmo decida.
  - En absolute: el contenido si no hay width.

Replaced elements

img {
    width: 100%;
    height: auto;
}
Replaced elements:

  - Su contenido es externo (img, video, input).
  - CSS no afecta al contenido.
  - Si no pones width/height, el tamaño es el natural.
  - Con width: 100%, height: auto, escalan proporcionalmente.
Imágenes responsive

El libro recomienda: img { max-width: 100%; height: auto; } para que las imágenes escalen pero no excedan su tamaño natural.

Width algorithm

CSS calcula el width de un elemento con un algoritmo:

Algoritmo:

  1. width: explícito.
  2. Si no hay width, depende de display:
     - block: ocupa todo el width disponible.
     - inline: solo el contenido.
  3. max-width: limita el width.
  4. min-width: limita el width.
  5. Si nada de eso, shrink-to-fit.
.box {
    /* El navegador aplica: */
    /* max(min(max-width, width), min(min-width, available)) */
}
No memorices el algoritmo

El libro dice: “entiende la idea, no memorices cada paso”. El navegador hace los cálculos por ti.

Height

.parent {
    height: 100vh;
}

.child {
    height: 100%;  /* 100% del height del padre */
}
Height: 100% tiene truco

El height del padre debe estar definido para que height: 100% funcione. Si el padre tiene height: auto, el hijo tiene height: 0.

Min-height y max-height

.section {
    min-height: 100vh;  /* al menos la altura del viewport */
    max-height: 500px;   /* como máximo 500px */
}
Min-height:

  - Útil para "esta sección debe ocupar la pantalla".
  - Si el contenido es más, se expande.
  - Si el contenido es menos, mantiene el tamaño.

Max-height:

  - Limita el crecimiento.
  - Útil para contenedores que no deben ser gigantes.

Display: flow-root

.container {
    display: flow-root;
}
flow-root:

  - Crea un nuevo block formatting context.
  - Contiene los floats.
  - Sin trucos de overflow: hidden.
  - Solución limpia para el clásico problema de floats.
flow-root > clearfix

El libro recomienda: usa display: flow-root en lugar de .clearfix { content: ""; display: block; clear: both; }. Es la solución moderna.

Display: contents

.wrapper {
    display: contents;
}
contents:

  - El wrapper es "transparente".
  - Solo sus hijos son visibles para el layout.
  - Útil para grouping sin afectar al layout.
Accesibilidad

El libro advierte: display: contents puede romper la accesibilidad porque el wrapper desaparece del árbol de accesibilidad. Úsalo con cuidado.

Inline formatting

span {
    display: inline;
    padding: 0.5em;  /* horizontal sí, vertical no afecta al line-height */
    margin: 0.5em;   /* horizontal sí, vertical no */
}
Inline:

  - El line-height determina la altura de la línea.
  - padding y margin horizontales funcionan.
  - padding y margin verticales NO afectan al line-height (pero sí al background).
  - border sí se ve en los cuatro lados.

Subrayados visuales

a {
    text-decoration: none;
    border-bottom: 1px solid currentColor;
    padding-bottom: 2px;
}
Subrayados:

  - text-decoration: underline, line-through, etc.
  - Tienen su propio color y estilo.
  - Para subrayados custom: border-bottom.

Box dimensions

.box {
    width: 200px;
    height: 100px;
    padding: 1em;
    border: 2px solid;
    margin: 1em;
}
Dimensiones:

  - width, height: el contenido.
  - padding: espacio dentro del border.
  - border: la línea del borde.
  - margin: espacio fuera del border.

Cálculo del tamaño total

.box {
    width: 200px;
    padding: 20px;
    border: 5px;
    margin: 10px;
}

/* Con content-box:
   Total = 200 + 40 + 10 + 20 = 270px (ancho real)
   El elemento ocupa 250px (content + padding + border)
   + 20px de margin (espacio exterior)

   Con border-box:
   El width es 200px TOTAL.
   El content = 200 - 40 - 10 = 150px
*/

El algoritmo de block sizing

/* El navegador hace estos pasos: */

/* 1. width preferido */
.box { width: 200px; }

/* 2. Si no hay width, block ocupa todo el espacio disponible */
.box { width: auto; }  /* toma el espacio */

/* 3. max-width limita */
.box { max-width: 300px; }

/* 4. min-width garantiza */
.box { min-width: 100px; }

Min-width: 0 por defecto

.grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
}

.item {
    /* Por defecto, min-width: auto = no shrink más allá del contenido */
    /* Para que los items se encojan, hay que poner min-width: 0 */
    min-width: 0;
}
Flexbox y Grid tienen min-width: auto

El libro advierte: por defecto, los items de flexbox/grid no se encogen más allá de su contenido. Para layouts flexibles, usa min-width: 0.

Margin collapsing

.box1 { margin-bottom: 20px; }
.box2 { margin-top: 30px; }

/* El espacio entre ambos es 30px, no 50px. */
Margin collapsing:

  - Los margins verticales de elementos adyacentes se "combinan".
  - El espacio final es el mayor, no la suma.
  - NO aplica a horizontal.
  - NO aplica a flexbox/grid/inline.
  - NO aplica a elementos con padding o border.
Herramientas contra el margin collapsing

El libro apunta: display: flex, overflow: hidden, padding: 1px en el padre, o margin: 0 en el hijo. Personalmente, prefiero flex.

Centrar elementos

/* Centrar horizontal (block con width) */
.box {
    margin: 0 auto;
    width: 80%;
}

/* Centrar absoluto */
.box {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

/* Centrar con flexbox */
.parent {
    display: flex;
    justify-content: center;
    align-items: center;
}

/* Centrar con grid */
.parent {
    display: grid;
    place-items: center;
}

Vertical alignment

/* inline */ 
span {
    vertical-align: middle;  /* baseline, sub, super, top, text-top, middle, bottom, text-bottom */
}

/* table-cell */
.cell {
    vertical-align: middle;
}

/* flex/grid */
.cell {
    display: flex;
    align-items: center;
}
Vertical-align no hace lo que crees

El libro es claro: vertical-align solo aplica a inline elements y table cells. Para centrar verticalmente divs, usa flexbox o grid.

Overflow

.box {
    overflow: visible;   /* default */
    overflow: hidden;    /* esconde el exceso */
    overflow: scroll;    /* scroll siempre */
    overflow: auto;      /* scroll si es necesario */
}
Overflow:

  - visible: el contenido se sale de la caja.
  - hidden: el contenido se corta.
  - scroll: siempre hay scrollbar.
  - auto: scroll solo cuando es necesario.

Overflow-x y overflow-y

.box {
    overflow-x: auto;
    overflow-y: hidden;
}
Overflow-x y -y:

  - Específicos para horizontal y vertical.
  - Si uno es visible y el otro no, el visible se convierte en auto.

Display: inline-block quirks

.parent {
    font-size: 0;  /* truco para eliminar el espacio entre inline-blocks */
}

.parent .child {
    display: inline-block;
    font-size: 16px;  /* reset */
}
El espacio entre inline-blocks

El libro apunta: alinear inline-blocks deja un espacio en blanco. Truco: font-size: 0 en el padre.

Tabla de display

display          Caso de uso
─────────────────────────────────────────────────────
block            Secciones, párrafos.
inline           Texto.
inline-block     Botones, badges.
flex             Layout 1D.
grid             Layout 2D.
none             Ocultar.
flow-root        Contener floats.
contents         Grouping invisible.
table            Tablas.
inline-table     Tablas inline.
table-row        Filas de tabla.
table-cell       Celdas de tabla.
list-item        Items de lista.

Resumen en tres frases

Próximos pasos