Skip to content

CSS: El modelo de caja

Partes de la caja

El modelo de caja, es la base para la maquetación (layout).

Considera que cada elemento es una caja que tiene que albergar 4 niveles de espaciado:

  • un contenido con un ancho y un alto
  • un relleno (padding) alrededor del contenido
  • un borde (border) alrededor del relleno que delimita la caja
  • un margen (margin) alrededor del borde que no pueden ocupar otras cajas

La caja también puede tener otros elementos que se ignoran de cara a la maquetación:

  • un contorno (outline) que hace de segundo borde por fuera
  • una sombra (box-shadow) que replica de la forma de la caja desplazada y difuminada
Content

En este ejemplo, vemos todos estos elementos: la caja (gris) que incluye contenido, relleno y borde (en azul). Fuera de la caja, el contorno (rojo) y la sombra (verde) que queda por detrás. El margen es transparente y mantiene al resto de elementos a 20px de distancia del contenido en gris. Esto incluye el borde negro del contenedor que nos da una idea del alcance del margen.

Content

Este otro ejemplo muestra que, si expandimos la sombra o el contorno más allá del margen, estos empiezan a solaparse con los elementos contíguos, pero no afecta en nada a la disposición de la caja ni de su entorno, que es la misma que en el anteriór ejemplo.

Orientaciones física y lógica

Al indicar las propiedades de una caja podremos asignar distintos valores para cada uno de los cuatro puntos cardinales.

Las cuatro orientaciones físicas (o de papel) son top, left, bottom y right.

Cuando planteamos un diseño multiidioma hay que tener presente hay idiomas que se escriben de derecha a izquierda (como el árabe y el hebreo) e incluso algunos que se escriben verticalmente (como muchos asiáticos).

Muchas de las decisiones de diseño no dependen tanto de las orientaciones físicas sinó de cual es el flujo de lectura.

Por eso, en esos casos, conviene usar las direcciones lógicas (o de flujo de lectura) que se mapean a una o otra orientación física dependiendo del modo de escritura del idioma. Esas direcciones son: inline-start, inline-end, block-start, block-end.

Colocamos las letras de inline-start a inline-end formando una linea o columna. Cuando esta se completa vamos creando más en dirección de block-start a block-end.

dirección logica física en latino fisica en árabe física tategaki
inline-start left right top
inline-end right left bottom
block-start top top right
block-end bottom bottom left
block vertical vertical horizontal
inline horizontal horizontal vertical

Cuando mencionemos propiedad-{direction}, {direction} será cualquiera de estas direcciónes físicas y lógicas.

Algunas propiedades son atajos para dar valor a varias direcciones. Dependiendo del número de valores, se repartiran de la siguiente manera:

  • 4 valores: top right bottom left (sentido horario desde las 12)
  • 3 valores: top right/left bottom (las horizontales juntas)
  • 2 valores: top/bottom right/left (tambien las verticales, queda: vertical y horizontal)
  • 1 valor: el mismo valor para las cuatro direcciones

Como extension de lo anterior siempre que especifiquemos cosas vertical y horizontal, siempre primero vertical y despues horizontal. Por ejemplo, para indicar una esquina, usaremos bottom-left y no left-bottom.

Vemos un ejemplo con la propiedad padding y el resto son equivalentes.

Disposición interna y externa

Cada elemento tiene un modo de despliegue interno y otro modo interno. Ambos estan controlados por su atributo display.

La disposición interna es la que define como se dispondran los hijos dentro suyo. Por defecto, se disponen en modo flow, pero existen otros: flex, grid, table...

El modo de despliegue externo determina como el elemento se comporta dentro de otro elemento contenedor y hay dos modos:

  • Block:

    • La caja empezara en una línea (o columna) nueva.
    • Se respetara los atributos width y height.
    • Los margenes, bordes y padding, expulsan otros elementos.
    • La caja se expandira en la dirección inline todo lo posible.
  • Inline:

    • La caja se mantendrá en la línea empezada.
    • Las propiedades width y height se ignoran.
    • Margenes, bordes, padding... se dibujan pero solo expulsan otros elementos en horizontal, no en vertical
    • La caja se divide en varias líneas. (Cada linea que ocupe el elemento tendra borde)

Ambas se controlan con la propiedad display. En CSS moderno deberiamos usar dos valores: uno para el modo interno y otro para el externo. Pero, por legado, los aspectos interno y externos no estan bien separados. Y hay palabras que usadas solas establecen los dos modos:

  • Cuando definimos display como block o inline, estamos poniendo el interno implicitamente a flow.
  • Cuando definimos display como flex o grid estamos definiendo el externo como block.
  • Los valores inline-flex y inline-grid establecen inline y grid o flex

Tamaño (size)

Por defecto el tamaño de la caja lo determina el navegador según el layout.

  • En el layout flow, una caja block se expandirá 100% en dirección horizontal (inline) y, verticalmente, se ajustará a lo que ocupe el contenido.

A partir de ahí, podemos explicitar o restringir con algunas propiedades.

  • Las propiedades width y height pueden explicitar ese tamaño.
  • Las propiedades max/min-width/height limitan tanto el valor calculado por el navegador como el que explicitemos con width o height.
  • La propiedad aspect-ratio fija una relación entre width y height, al menos que las dos estén explícitadas o les afecte una limitación.
  • Si queremos usar direcciones de flujo, usaremos las propiedades [max/min-]block/inline-size.

Los valores que pueden tomar los atributos de tamaño son:

  • auto: Valor por defecto. Lo que diga el navegador.
  • Una longitud con unidades (o una formula usando max, min, clamp, calc...)
  • Los porcentajes son relativos al tamaño del contenedor en la dirección
    • Si el tamaño del contenedor depende del contenido, es como si lo dejamos a auto.
    • Por ejemplo, en flow, si no explicitamos la altura del contenedor.
  • min-content: El mínimo que pide el contenido. Por ejemplo, la palabra más larga de un parrafo.
  • max-content: El máximo que pide el contenido. Por ejemplo, lo que ocupa todo el parrafo expandido en una línea.
  • fit-content(value): cogera el valor, limitado por min/max-content
  • fit-content: lo que diga el navegador, limitado por max/min-content (fit-content(auto))

Box sizing hasta el borde

El tamaño que fijamos con estas propiedades se refiere por defecto a lo que ocupará el contenido, excluyendo padding y borde. A menudo eso dificulta los calculos para el layout, por eso a menudo se define box-sizing: border-box que hace que se cuenten borde y padding para el tamaño.

Si definimos el box-sizing de forma global, se rompen los componentes definidos de la forma tradicional.

La solución es definirlo globalmente así:

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

Y para el componente antiguo, definir:

.my_old_component {
  box-sizing: content-box;
}

Relleno (padding)

El padding es un relleno o cojín entre el contenido y el borde de la caja. La metáfora sería el relleno que se pone en un paquete para que el contenido no dé golpes.

Se puede especificar un relleno diferente en cada una de las cuatro direcciones.

Formas de especificarlo:

.midiv {
    /* direcciones especificas, el resto acaba dando valores a estas */
    padding-top: 3px;
    padding-right: 3px;
    padding-bottom: 3px;
    padding-left: 3px;

    /* atajos */
    padding: 2px; /* el mismo valor en las 4 direcciones */
    padding: 1px 2px 3px 4px; /* top left bottom right, clock-wise order */
    padding: 100px 30px;  /* top/bottom left/right */
    padding: 100px 30px 1px;  /* top left/right bottom */

    /* direcciones lógicas específicas */
    padding-inline-start: 1rem; /* inicio en dirección de linea (left para latino) */
    padding-inline-end: 1rem; /* final en dirección de linea (right para latino) */
    padding-block-start: 1rem; /* inicio en direción de bloque (top para latino) */
    padding-block-end: 1rem; /* fin en direción de bloque (bottom para latino) */

    /* atajos direcciones lógicas */
    padding-block: 2rem; /* a la vez direcciones de bloque (up y bottom para latino) */
    padding-inline: 40px; /* a la vez direcciones de linea (left y right para latino) */
    /* experimental */
    padding: logical 2px; /* el mismo en las 4 direcciones, no cal */
    padding: logical 1px 2px 3px 4px; /* block-start line-end block-end line-start, clock-wise order if latin */
    padding: logical 100px 30px;  /* block inline */
    padding: logical 100px 30px 1px;  /* block-start inline block-end */
}

Error típico

Usar porcentajes para hacer el padding vertical proporcional a la altura del contenedor

Cuando especificamos un padding vertical (block) con un porcentage, no se toma el alto del contenedor como referencia, sinó su ancho (inline).

XXXXX

En el siguiente ejemplo, el padding de la caja interna está fijado al 20% en todas las direcciones. Se observa que resulta el mismo padding horizontal y vertical, aunque la caja contenedora sea el doble de alta que de ancha. Se está tomando el 20% del ancho en todas las direcciones.

<div style="
    width: 100px;
    height: 200px;
    background: #f77;
    float: right; margin-inline: 1rem; padding:2px;
">
    <div style="background: #7f7; padding: 20% 20%;">XXXXX</div>
</div>

Borde (border)

El borde es una línea que decora el extremo de la caja marcando su límite. Está fuera del padding pero sigue siendo parte de la caja de cara al maquetado.

También por ser parte de la caja, se le aplica el fondo (background) de la caja, aunque, a menudo, el mismo borde lo tape.

La línea de borde tiene 3 atributos: ancho width, estilo style y color color.

El estilo por defecto es none. Eso quiere decir que si no cambiamos ese valor, no se añadira ningún borde, aunque cambiemos los otros atributos.

El color por defecto es la propiedad color del elemento.

Y la anchura, que puede ser una longitud positiva o una de las palabras thin, medium, thick, tiene como valor por defecto medium. Cabe decir que no está especificado a que longitud corresponde medium, así que si quieres resultados coherentes entre navegadores, siempre asignale un valor con unidades.

Los estilos posibles son:

Solid
Dotted
Dashed
Double
  • Invisibles:
    • none: Sin borde (por defecto).
    • hidden: Sin borde. Pero con prioridad collapsando en tablas.
  • Planas:
    • solid: Una linea plana
    • dotted: Puntos
    • dashed: Rayas
    • double: Dos lineas paralelas
Ridge
Groove
Inset
Outset
  • Sombreadas: Usa un tono más oscuro del color base para generar un efecto sombreado 3D noventero.
    • ridge: Simula un marco sobresaliente /\______/\
    • groove: Simula un surco alrededor del contenido \/--------\/
    • inset: Simula que el contenido està hundido \______/
    • outset: Simula que el contenido sobresale /--------\
    • Los colores que no sean negros, usa una version del color oscurecido.
    • Al menos en Firefox, el negro se comporta diferente, usando tonos de gris.

Para especificar los atributos width, style, color en cada dirección: border{-direction}{-attribute}. Las direcciones son las mismas que para el padding: top, right, bottom, left, las multicultis inline/block[-start/end].

Los atajos border{-attribute} permiten fijar el atributo en las cuatro direcciones a la vez. Se pueden usar 4, 3, 2 o 1 valores igual que con el padding:

  • 4: con las agujas del reloj empezando a las 12
  • 3: el left toma el valor del right
  • 2: block inline
  • 1: para todas las direcciones

Los atajos border{-direction} permiten fijar los tres atributos a la vez en una direccion.

El atajo border permite especificar los 3 atributos en las 4 direcciones a la vez, pero no permite especificar distintos valores para cada dirección como permiten padding o border{-attribute}.

Error típico

Content

Usar propiedades especificas de dirección para setear solo un atributo

border-color: red; border-left: solid;

Si no damos uno de los valores a una propiedad que se espera valores para los tres atributos, cogera los valores por defecto. Es lo que pasa en la segunda declaración, que sobrescribe el rojo con el color del elemento (negro). Si solo ponemos el color o el grosor, seria más catastrófico, porque estaria cogiendo el estilo por defecto que es none.

Solución en este caso, explicitar los otros valores o usar border-left-style

Error típico

Usar porcentajes para el grosor del borde

CSS no soporta porcentajes en los bordes. Una declaración que incluya porcentaje se ignorará.

Como los bordes se suelen declarar en atajos con varias propiedades es más complicado detectar que el problema está en el porcentaje.

Border image

Las imágenes de borde permiten establecer un estilo de borde personalizado a partir de una imagen.

TODO


TODO: Setting border{-direction} property sets border-image to none

Margen (margin)

El margen es una distancia mínima de exclusión que se establece para un bloque en cada dirección desde su borde hasta la caja adjacente en esa dirección o, en su defecto, hasta el límite del espacio disponible para colocar los elementos.

  • Es transparente, no se le aplica el background.
    • Al contrario del borde y el padding, que si se les aplica el background.
  • Los margenes expresados en porcentajes, tanto verticales como horizontales, son relativos a la anchura (¡horizontal!) del bloque contenedor.
  • Los margenes verticales de cajas adyacentes a menudo se solapan colapsandose.
    • De los dos, se toma el mas grande para separar.
    • Da igual que sea de otro nivel, si hay no hay contenido en medio
    • El margen no expande el contenedor

Formas de especificarlo:

.midiv {
    margin: 2px; /* el mismo margen en las 4 direcciones */
    margin: 1px 2px 3px 4px; /* top left bottom right, clock-wise order */
    margin: 100px 30px;  /* vertical horizontal */
    margin: 100px 30px 1px;  /* top horizontal bottom */
    margin-top: 3px;
    margin-right: 3px;
    margin-bottom: 3px;
    margin-left: 3px;
}
Content
Content

Los márgenes de dos cajas adjacentes en la dirección de bloque se colapsan. El resultado es que de dos cajas adjacentes, de sus margenes, se toma el mayor.

Error típico

Esperar que la distancia entre dos cajas sea la suma de los márgenes

Dentro de un contexto de flujo normal los margenes se colapsan. Los elementos de flex o grid o table estan aislados y no collapsan márgenes.

Content
Content

También se collapsan los márgenes en la dirección de bloque (vertical) de elementos anidados.

Un colapso que no se produce si entre los margenes hay un padding, un borde o contenido. En el ejemplo, se colapsa el margen inferior pero el superior no porque hay contenido de por medio.

Margen auto

margin-left: auto
margin-right: auto
margin-inline: auto

Los márgenes horizontales (inline) con valor auto se reparten el espacio disponible. Esto puede servir para centrar elementos, distribuirlos con separacion uniforme o proporcional, o justificarlos a un lado. Para que haya espacio disponible, la caja ha de tener un width no auto y menor que el disponible.

Esquinas redondeadas (border-radius)

Circular
Percent
Elliptical
Rampant

Border radius permite hacer redondeadas las esquinas de la caja.

  • Las 4 esquinas se enumeran empezando por la top-left en sentido de las manecillas del reloj
  • Cada esquina tiene dos radios, uno horizontal (inline) y otro vertical (block). 2 direcciones x 4 esquinas = 8 valores a calcular
  • Propiedades específicas:
    • border-{top|bottom}-{left|right}-radius: h-radius [v-radius]
    • Si no se especifica radio vertical, se supone igual que el horizontal
  • Propiedad atajo:
    • border-radius: tlh [trh [brh [blh]]] [ / tlv [trv [brv [blv]]]]
    • La barra separa los horizontales (h) de los verticales (v)
    • si no hay barra, se toman los valores horizontales también para los verticales
    • si falta bottom-left, se coge el valor de top-right
    • si falta bottom-right, se coge el valor de top-left
    • si falta top-right, todos tiene el valor de top-left
  • Los porcentajes se refieren al tamaño de la caja en su dirección
    • Si se da el mismo porcentaje para horizontal y vertical, las distancias derivadas pueden no ser iguales
  • Si los tamaños de los radios calculados en uno de los lados de la caja supera su tamaño, todos los radios, aunque no estén implicados en ese exceso, se ajustan proporcionalmente.
border-radius: 10pt 20pt; /* top-left/bottom-right a 10pt, bottom-left/top-right a 20pt */
border-radius: 10pt 20pt 30pt; /* top-left a 10pt, bottom-left/top-right a 20pt, bottom-right a 30pt */
border-radius: 10pt / 20pt; /* radios horizontales a 10pt, verticales a 20pt */

Error típico

Exceding border

No mantener un padding mínimo como el máximo border radius

El padding es la distancia entre el contenido y el borde, pero el borde sin redondear. Cuando redondeamos el borde, si no añadimos padding suficiente, puede que el contenido se vea fuera de la caja en las esquinas.

Contornos (outline)

Content

El contorno es una segunda línea resiguiendo por fuera el borde. Es el mismo elemento que usan los navegadores para indicar el foco del teclado. ¡Ojo! ¡Procura no interferir con esta funcionalidad de accesibilidad del navegador!

A diferencia del borde, la caja no se amplia para abarcarlo: no tiene background y su presencia o grosor no afecta a la maquetación.

Tiene los mismos atributos de línea que border: style, color y width. Se pueden setear por separado con outline-{attribute} o a la vez con el atajo outline. A diferencia de border, no se puede establecer valores diferentes para cada direccion. No tiene radius pero se adapta al border-radius de border como se ve en los ejemplos.

Content

Un atributo más, outline-offset, define la separación del borde al outline Se puede indicar un offset negativo para ponerlo dentro de la caja Si el offset negativo supera las dimensiones de la caja, el outline desaparece

Accesibilidad

Los navegadores usan el outline para indicar foco en los elementos que reciben eventos del teclado. Si una regla css quita incondicionalmente el outline (none o 0), por ejemplo porque es más específica que la que usa el navegador para el focus, los usuarios no verán dicha indicación y afectará a la accesibilidad.

Sombra (box-shadow)

Offset
Blur
Spread
Color
Inset
Multiple

box-shadow genera un efecto sombra de la caja, replicando el volumen de la caja detrás de ella. Tambien se usa para otros efectos como resplandores y relieves. Lo especificamos con:

box-shadow: [inset] [color] offset-v offset-h [blur [spread]]

  • El desplazamiento de la sombra (offset) es clave para simular de donde viene la luz o de que angulo miramos el objeto
  • El radio de difuminado (blur) añade realismo a la sombra emulando una fuente luminosa no puntual.
  • La expansion (spread) extiende la sombra una longitud en todas las direcciones simulando una luz próxima. Encoge si es negativo.
  • Si añadimos la palabra clave inset la sombra será interior, emulando que la caja esta por detras del papel en vez de por encima
    • Ojo: La sombra inset va por dentro del borde, el border quedará al nivel del papel.
  • Una caja puede tener varias sombras, podemos concatenarlas con comas
    • Ojo: Cada sombra va debajo de la anterior.

Sombras realistas:

  • A más amplitud angular de la fuente de luz, mayor difuminado
  • A más distancia de la caja a la sombra, mayor difuminado
  • A menor distancia de la luz a la caja, mayor expansión

Otros efectos con box-shadow:

Glow
Emboss
Glass
Blurder
Metal
Pile
  • Glow: Sin offset, con blur, un poco de spread y un color saturado tipo neon. En fondos claros funciona pero con colores chillones.
  • Emboss: Da relieve a la caja. Sombra inset sin offset, color saturado. Aclarar el background para que parezca iluminado. Con esquinas cuadradas le quita realismo al volumen.
  • Glass: Simula un material semi-transparente. Dos sombras. Una inset clara semi-transparente, sin offset y muy difuminada, simula difracción. Otra outset oscura sin offset más concentrada, da grosor. Background transparente, si el contenedor tiene un fondo no plano queda muy resultón usando backdrop-filter: blur(5px);
  • Blurder: Aplicar sombras inset y outset sin offset, con background transparente hace que el borde se difumine. Con colores brillantes en fondo oscuro, brille.
  • Metal: En los bordes de los metales se juntan muchas normales, y es probable que alguna coincida con una fuente de luz. Por eso un glow debil. Tambien tienen reflejos distorsionados de color del entorno. Se podria hacer con degradados pero con sombras inset en el borde se distorsiona y queda más realista.
  • Pile: Alternado sombras finas que hacen de sombras, con sombras tambien finas pero blancas que hacen de papel. Ahora si, profit: [ ($) ]

Fondo (background)

El fondo es el lienzo donde se coloca el contenido. CSS permite rellenarlo con varias capas que igual que las sombras podremos añadir con comas y igual que las sombras las ultimas van poniendose debajo.

TODO