Como su nombre lo indica, Flexbox es un modelo de cajas flexibles, esto significa que las dimensiones de las cajas son elásticas y pueden expandirse o encogerse. En otras palabras, aunque se definan un alto o ancho, estos valores no siempre serán respetados por el navegador al dibujar el documento.
Que a un elemento le asignemos width: 100px
y que su ancho final sea 160px
confunde mucho cuando comenzamos. Pero una vez que comprendemos cómo se calculan las dimensiones en Flexbox, podremos resolver problemas complejos de layout con facilidad.
Main size y cross size
Main size y cross size (tamaño principal y secundario) son las dimensiones de ancho y alto de los flex-items. Estos tamaños son siempre relativos a los ejes, por lo que main size podría ser width
o height
según la dirección del main axis (de igual manera con el cross size).
Debe tenerse en cuenta que, como en cualquier caja, los valores de padding
y border
suman al tamaño final (salvo que se use box-sizing: border-box
).
Una vez entendido esto, el problema es saber cómo hace el navegador para calcular las dimensiones finales de los items.
Para el cross size, hay tres escenarios:
- Si se ha definido (por
width
oheight
) ese tamaño se respetará. - Si no se ha definido, se utilizará todo el espacio disponible.
- Si no se ha definido y se utiliza un valor diferente de
stretch
paraalign-content
oalign-items
en el contenedor, se tomará el tamaño de su contenido.
Para el main-size, el cálculo es más complejo. Pero se basa en los siguientes principios:
- Si no se ha definido el tamaño, se calculará según el contenido.
- Si se ha definido (por
width
oheight
) esté podría respetarse, podría encogerse, o crecer.
Espacio disponible y espacio ocupado
Según lo anterior, el verdadero reto es determinar el main size. Para hacerlo, primero debemos entender los siguientes conceptos:
- El espacio ocupado es la suma de los main-size de todos los flex-items en la misma línea, más los márgenes si los hubiera.
- El espacio disponible es la diferencia entre el tamaño del contenedor y el espacio ocupado. Este valor podría ser positivo o negativo.
- Si el espacio disponible es negativo (es decir, el tamaño sumado de los items supera al del contenedor) el comportamiento predeterminado es que los flex-items se encojan para caber en una sola línea.
- Aunque el main-size puede encogerse, los márgenes nunca colapsan.
Tamaño base para los items: “flex-basis”
La propiedad flex-basis
, como su nombre lo indica, define el main-size base para un flex-item. Tamaño base principal (main size base) significa que no necesariamente ese será su tamaño al dibujarse por el navegador, pero que será un punto de partida para calcular el tamaño final.
En otras palabras, si el main axis es horizontal (predeterminado), flex-basis
será equivalente a width
; y si el main axis es vertical, flex-basis
será equivalente a height
.
Ten en cuenta que el tamaño definido por flex-basis
es, como su nombre lo dice, el tamaño base. Es decir, que podrá variar (crecer o encogerse), según los valores de flex-grow
y flex-shrink
que veremos más adelante.
Importante
flex-basis
siempre gana sobre el valor dewidth
oheight
.- Si no se define el valor de
flex-basis
o se establece enauto
, se tomará en cuenta el valor dewidth
oheight
según sea el caso. - Si no se define un valor para
flex-basis
y tampoco se especifica el tamaño porwidth
oheight
, se definirá el main-size según su contenido.
Crecimiento del main-size: “flex-grow”
La propiedad flex-grow
, como su nombre lo indica, controla que tanto crecerá el flex-item para rellenar el espacio disponible. Su valor solo puede ser un número entero (no negativo).
Esta propiedad solo se aplica si el espacio disponible es positivo (el tamaño del contenedor es mayor a la suma de los flex-items y sus márgenes).
¿Qué significa el número en flex-grow?
En flex-grow:x
el numero x indica cuantas unidades crecerá el item para calcular su tamaño final. Por ejemplo, flex-grow: 3
significa que el item crecerá 3 unidades.
¿Cuánto vale cada unidad?
Para el ejemplo anterior, sabemos que el item crecerá 3 unidades. ¿Pero cuanto vale cada unidad? La forma para calcularlo es bastante sencilla. Simplemente hay que dividir el espacio disponible entre la suma de los flex-grow
de todos los items (en la misma linea). Así:
unit grow = espacio disponible / suma de flex-grow
Veamoslo con un ejemplo
.container { width: 500px; } .item-1 { flex-basis: 100px ; flex-grow: 1 } .item-2 { flex-basis: 100px ; flex-grow: 2 } .item-3 { flex-basis: 100px ; flex-grow: 1 } .item-4 { flex-basis: 100px ; flex-grow: 1 }
En este caso el espacio disponible es de 100px
(tamaño del contenedor menos la suma del tamaño de los items) y este debe distribuirse entre los items de la siguiente forma:
100px/(1+2+1+1) = 20px ->; Este es el valor de la unidad (unit grow).
Luego esta unidad de crecimiento se multiplicará por el valor de flex-grow
para determinar cuanto crecerá cada item.
item1->; 20px * 1 = 20px item2->; 20px * 2 = 40px item3->; 20px * 1 = 20px item4->; 20px * 1 = 20px
Finalmente, el main size de cada item al dibujarse por el navegador será:
item1 ->; 120px item2 ->; 140px item3 ->; 120px item4 ->; 120px
Ten en cuenta que si los items tuvieran márgenes, el espacio disponible sería menor (habría que restarle el tamaño total de los márgenes). Por ejemplo, si para el caso anterior todos los items tuvieran margin: 5px
, el espacio disponible sería:
500px - (100px+100px+100px+100px) - (5px+5px+5px+5px+5px+5px+5px+5px) = 60px
Encogimiento del main-size: “flex-shrink”
Si el espacio disponible es negativo (el tamaño del contenedor es menor a la suma de los tamaños de los items), de forma predeterminada los items se encogen en proporciones iguales para caber en una sola línea (en un próximo artículo trabajaremos flexbox con varias líneas de items). Con la propiedad flex-shrink
se controla cómo se encogerán los elementos.
Para calcular el tamaño final de un item que se ha encogido, se usan los mismos principios que con flex-grow solo que en el sentido opuesto. Veamoslo con un ejemplo:
.container { width: 500px; } .item-1 { flex-basis: 150px ; flex-shrink: 1 } .item-2 { flex-basis: 150px ; flex-shrink: 2 } .item-3 { flex-basis: 150px ; flex-shrink: 1 } .item-4 { flex-basis: 150px ; flex-shrink: 1 }
- En este caso, el espacio disponible es negativo (–100px) ya que todos los items sumados dan 600px y el contenedor tiene solo 500px.
- La unidad (unit shrink) se define dividiendo el espacio disponible entre la suma de los valores de
flex-shrink
, es decir:-100px/5 = -20px
- Luego, los tamaños finales serán:
item-1: 130px (150-20px*1) item-2: 110px (150-20px*2) item-3: 130px (150-20px*1) item-4: 130px (150-20px*1)
En la siguiente página web puedes probar con los valores de flex-grow
, flex-shrink
y flex-basis
:
http://madebymike.com.au/demos/flexbox-tester/
Ten en cuenta Un item no se reducirá más de su contenido mínimo (la palabra más corta o el elemento más pequeño con un tamaño determinado). Se puede cambiar esto con min-width
o min-height
.
Propiedad abreviada: “flex”
flex
es el shorthand (propiedad abreviada) para flex-grow
, flex-shrink
y flex-basis
(en ese orden específico).
Entonces:
.item { flex: 2 1 200px; }
Es igual a
.item { flex-grow: 2; flex-shrink: 1; flex-basis: 200px; }
El valor predeterminado de flex
(si no se especifica) es:
flex: 0 1 auto;
Es decir que por defecto los items no van a crecer pero si reducirse de manera proporcional para ajustarse al espacio. Además, que flex-basis se establece en auto (respecto a su contenido).
Otros ajustes:
flex: auto;
Equivale a flex: 1 1 auto
. Los items pueden crecer o reducirse según el caso y su flex-basis es calculado según el contenido.
flex: none
Equivale a: flex: 0 0 auto
. Los items no crecen ni se reducen y flex-basis
se calcula según el contenido.
flex: ;
Equivale a flex: 1 0
. Esto significa que el item recibe el valor de espacio disponible proporcional a . Si todos los items usan este principio, sus **main-size** se verían definidos directamente por el
.