La release Firefox 70 notes recoge la nueva sintaxis para la propiedad de css display, admitiendo dos valores: uno para el display del padre y otro para el de los hijos, ambos en una misma propiedad.

En este post vamos a hacer un recorrido por la nueva sintaxis, los diferentes valores de la propiedad display, las diferentes combinaciones que se pueden hacer con estos valores y ejemplos de casos de uso.

Antes de entrar en detalle lo primero es definir qué hace la propiedad display. Como todos sabemos, todo elemento HTML en la web está representado por cajas. La propiedad display es la responsable de controlar cómo se ven esas cajas y de cómo interactúan entre ellas, pudiendo cambiar su apariencia modificando el valor.

Los elementos tienen un display por defecto que puede ser inline o block. Con CSS2 llegaron los siguientes valores:

Y cuando andábamos haciendo malabares con las alineaciones aparecen flex y grid como caídos del cielo. La principal diferencia que hay entre flex y grid con el resto de valores es que a través de ellos controlamos el display de los hijos, creándose un flex/grid formatting context, por lo que los hijos se convierten en flex y grid items respectivamente.

Con el siguiente código obtendríamos un elemento flex container:

.container {
  display: flex;
  justify-content: space-between;
  padding: 30px;
  border: 1px dotted #ccc;
}

Y veremos esto:

Tenemos un container que es un bloque y unos hijos que son flex-items. Esto es exactamente lo mismo que poner display: block flex, como podemos ver en el ejemplo, refiriéndonos con block al display del padre y con flex a los hijos.

.container {
  display: block flex;
  justify-content: space-between;
  padding: 30px;
  border: 1px dotted #ccc;
}

Nota: todos los ejemplos con la nueva sintaxis hay que verlos en Firefox70.

Así que cuando nosotros utilizamos display: flex estamos creando un padre con formato de bloque y unos hijos flex-items. Hasta ahora, sin saberlo, ya estábamos utilizando los dos valores de esta propiedad, pero de forma implícita. Con la nueva sintaxis lo haremos de forma explícita, obteniendo un código más legible, más entendible y en el que aparece reflejado lo que hace la propiedad por sí misma.

Outer/Inner values

Tanto el padre como los hijos van a tomar unos valores determinados, que van a ser los siguientes:

Si no indicásemos alguno de estos valores, por defecto serán los siguientes:

¿Qué significa esto? Exactamente lo que hemos visto en el ejemplo de flex. Si nosotros declaramos la propiedad display: flex, flex es un valor que afecta a los hijos. Si no indicamos el valor del padre, por defecto será block, y lo mismo ocurre con los hijos.

Así que si tenemos display: block, este valor corresponde al padre, por lo que sería lo mismo que poner display: block flow. Si declaramos la propiedad con uno de los valores que corresponde al padre, esta propiedad pondrá a los hijos el valor que tienen por defecto. Sin embargo, cuando declaramos la propiedad con el valor correspondiente a los hijos, el padre tomará el que se establece por defecto, en este caso block.

La especificación de nivel 3 clasifica los valores de display en las siguientes categorías (ojo, que solo son categorías para clasificarlos, esto no significa que sea una nueva propiedad de display. Es decir, no podemos poner display-outside: block):

Los valores admitidos por cada una de las categorías son los siguientes:

Categoría de display Valores
display-outside block | inline | run-in
display-inline flow | flow-root | table | grid | flex | ruby
display-listitems display outside && flow | flow-root | list-item
display-internal table-row-group | table-header-group | table-footer-group | table-row | table-cell | table-column-group | table-column | table-caption | ruby-base | ruby-text | ruby-base-container | ruby-text-container
display-box contents | none
display-legacy inline-block | inline-flex | inline-grid | inline-table

En la siguiente tabla podemos ver cómo quedarían los valores de display, de forma resumida, con la nueva sintaxis:

Short display Full display
block block flow
flow-root block flow-root
inline inline flow
inline-block inline flow-root
flex block flex
inline-flex inline flex
grid block grid
inline-grid inline-grid

Si tenéis curiosidad, en este enlace podéis ver el resto de valores de display.

Ejemplos

Vamos a ver cómo quedaría la nueva sintaxis con algunos ejemplos.

Un caso que me parece muy interesante, aunque cada vez lo utilicemos menos, es el de elementos flotados. ¿Qué ocurre con estos elementos? Vamos a verlo con un ejemplo.

Al estar flotados están fuera del flujo, por lo que si no limpiamos los floats, el elemento no estaría contenido en el container.

Hasta ahora este problema lo solucionábamos con clearfix o con overflow: auto / hidden. Pero en realidad la propiedad overflow no es para esto. Seguro que a todos nos ha pasado que al utilizar overflow: hidden nos ha desaparecido alguna sombra, o un scroll que no deseamos con overflow: auto.

Para solucionar este problema, tenemos una propiedad de display que es flow-root.

Flow-root crea un block formatting context, un mini-layout dentro del componente donde están contenidos los elementos flotados y donde estos interactúan. Exactamente esto mismo es lo que hace la propiedad overflow, pero con flow-root conseguimos una propiedad que nos permite trabajar con floats sin tener que utilizar estos hacks.

Hasta ahora solo hemos hablado de los dos valores que admite la propiedad display. Sin embargo, hay un caso que permite hasta 3 valores. Este es el caso de list-item, aquí tenemos un ejemplo, creando un elemento inline o de bloque con un :marker adicional.

.wrapper-inline {
  display: inline flow list-item;
}
.wrapper-block {
  display: block flow list-item;
}

¿Por qué admite 3 valores? En todo momento estamos hablando del valor de display del padre y del hijo, sin embargo list-item lo único que nos hace es generarnos el marker, por lo que admitiría, además, los valores de display para el padre y el hijo.

Hay dos valores de display que no van a cambiar con la nueva sintaxis, contents y none, que seguirán declarándose propiedad con un solo valor.

Tengo que reconocer que hasta que no me puse a investigar para escribir este post display: contents era algo totalmente desconocido para mí. ¿Qué hace esta propiedad? Al aplicarla, el padre es reemplazado por sus hijos y pseudoelementos. Es decir, aunque en el dom sigue apareciendo, visualmente no lo vemos, ya que no genera caja. Y sus hijos pasarían a ser hijos del padre del elemento reemplazado.

En este ejemplo, tenemos un elemento que tiene display: block flex. Este elemento tiene 5 hijos y uno de ellos, a su vez, tiene otros dos hijos y un pseudoelemento.

Si clickamos en el checkbox, al segundo hijo le aplica display: content y conseguimos lo siguiente:

Como vemos, el segundo hijo ha desaparecido, visualmente hablando. También ha desaparecido el padding y el borde. Si nos fijamos en la consola, en el css del hijo 2 encontramos lo siguiente:

Al aplicar display: contents, vemos que obvia las propiedades que afectan directamente al padre. Tan sólo está aplicando aquellas propiedades que los hijos heredan, que son el color y el font-size.

Un caso de uso sería una lista en la que tenemos un ul que tiene a su vez li, y necesitamos que esos li se vean afectados por las propiedades del padre, que engloba a todos los elementos.

Aquí os dejo un ejemplo visualmente muy instructivo sobre cómo funciona display: contents.

Conclusiones

Referencias

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.