Tabla de Contenidos
6. Flex y Grid
En este tema vamos a explicar principalmente el layout en CSS con flexbox y grid.
Flexbox
Flex se utiliza para colocar cosas de forma horizontal o vertical.
Vamos a explicar flex con el siguiente ejemplo:
<div class="l-flex l-flex--direction-row l-flex--justify-content-center"> <div class="l-flex__area">Item1</div> <div class="l-flex__area">Item2</div> <div class="l-flex__area l-flex__area--grow-2">Item3</div> <div class="l-flex__area">Item4</div> <div class="l-flex__area">Item5</div> </div>
.l-flex {
display: flex;
&--direction-row {
flex-direction: row;
}
&--justify-content-center {
justify-content: center;
}
&__area {
// Si tuvieras más propiedades para el área, las pondrías aquí
&--grow2 {
flex-grow: 2;
}
}
}
Como vemos hay dos tipos de elementos, el contenedor y los items que hay centro. El contenedor siempre tendrá la siguiente línea display:flex;.
* Veamos otro ejemplo:
<div class="l-flex l-flex--direction-row l-flex--justify-content-center"> <div class="l-flex-area"> <div class="l-flex l-flex--direction-row l-flex--justify-content-center"> <div class="l-flex-area"></div> <div class="l-flex-area"></div> </div> </div> <div class="l-flex__area">Item2</div> <div class="l-flex__area l-flex__area--grow2">Item3</div> <div class="l-flex__area">Item4</div> <div class="l-flex__area">Item5</div> </div>
Ahora veremos algunas de las opciones que permite flex.
flex-direction
Para hacer que los item se muestren de forma vertical u horizontal. Sus valores son
* flex-direction:row Los items se colocan en horizontal. Es decir en una única línea.
* flex-direction:column Los items que solocal en vertical. Es decir en una única línea.
flex-wrap
Para hacer que si no caben en una línea, se pasen a la línea siguiente.
* flex-wrap:wrap Si se añade se pasa de línea en vez de mantenerse en la misma
justify-content
Es como se distribuye el espacio sobrante en horizontal. Hacía la izquierda, derecha, ocupando todo el espacio, etc, etc.
Alguno de sus posibles valores son:
* justify-content:flex-start
* justify-content:flex-end
* justify-content:center
* justify-content:space-between
* justify-content:space-around
* justify-content:space-evenly
align-content
Es como se distribuye el espacio sobrante en vertical. Hacía arriba, abajo, ocupando todo el espacio, etc, etc.
Alguno de sus posibles valores son:
* align-content:flex-start
* align-content:flex-end
* align-content:center
* align-content:strech
* align-content:space-between
* align-content:space-around
align-items
Si los elementos se justifican hacía arriba, abajo, ocupando todo el espacio, etc, etc.
Alguno de sus posibles valores son:
* align-items:flex-start
* align-items:flex-end
* align-items:center
* align-items:stretch
* align-items:baseline
flex-grow
Permite que crezca el item si hay mas espacio. Por defecto el valor es 0 que significa que no crece, sino que se queda con el espacio que necesita para su contenido.
* flex-grow:1: Todos los items con este valor crecerán para ocupar más espacio pero todos los que tengan este valor tendrán el mismo tamaño entre ellos
* flex-grow:2: Como al anterior pero todos los que tengan este valor tendrán el mismo tamaño entre ellos pero el doble que los de flex-grow:1
* flex-grow:3: Como al anterior pero todos los que tengan este valor tendrán el mismo tamaño entre ellos pero el triple que los de flex-grow:2
En el siguiente ejemplo, AAAAA tendrá el espacio mínimo para que quepa el texto mientras que BBBBB y CCCCC se expandirán hasta ocupar todo el espacio disponible pero CCCCC ocupará el doble que BBBBB
<div style="display: flex;"> <div style="flex-grow: 0;border:1px solid red">AAAAA</div> <div style="flex-grow: 1;border:1px solid red">BBBBB</div> <div style="flex-grow: 2;border:1px solid red">CCCCC</div> </div>
flex-grow, el item crecerá hasta tener un tamaño mayor o justo el den contenido, así que no tiene sentido usar flex-shrink:1 ya que ya se podría hacer más pequeño ni usar flex-basis ya que no tendrá un tamaño fijo.
flex-shrink
Indica que un item puede reducir su tamaño en comparación con otros items cuando el contenedor es más pequeño que el tamaño total de los elementos.
* flex-shrink:1: Los items con este valor pueden reducir su tamaño para ajustarse al contenedor.
* flex-shrink:0: Los items con este valor no se reducirá, independientemente del tamaño del contenedor.
Ejemplo: Si tienes tres elementos en un contenedor y uno tiene flex-shrink: 0, este no se reducirá, mientras que los otros dos se reducirán según sea necesario para encajar en el contenedor.
flex-shrink:1 si se indica flex-basis y si valor no es auto.
Ya que si flex-basis:auto el item ya tendré el tamaño mínimo del contenido así que no se podrá hacer más pequeño y por lo tanto no se necesita flex-shrink:1
flex-basis
Define el tamaño inicial de un item antes de que se aplique el crecimiento o la reducción. Es el tamaño en el que se basa el elemento antes de que el espacio adicional sea distribuido (con flex-grow) o el espacio sea reducido (con flex-shrink). El tamaño inicial se puede establecer en px, %, em, etc. Por defecto el tamaño inicial es auto y significa que el tamaño es el del contenido.
Veamos ahora un ejemplo completo de las 3 propiedades:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ejemplo de Flexbox</title>
<style>
.container {
display: flex;
}
.item {
border: 1px solid #FF0000;
}
.item1 {
flex-basis: 300px;
flex-shrink: 1;
}
.item2 {
flex-basis: 300px;
flex-shrink: 0;
}
.item3 {
flex-grow:1
}
</style>
</head>
<body>
<div class="container">
<div class="item item1">AAAAAAAAAAAAAAA</div>
<div class="item item2">BBBBBBBBBBBBBBB</div>
<div class="item item3">CCCCCCCCCCCCCCC</div>
</div>
</body>
</html>
La explicación es:
* El item1 empieza con un tamaño de 300px (por flex-basis: 300px;) pero se puede hacer más pequeño si es necesario (por flex-shrink: 1;)
* El item2 empieza con un tamaño de 300px (por flex-basis: 300px;) pero NO se puede hacer más pequeño (por flex-shrink: 0;)
* El item3 ocupará todo el espacio que haya libre (por flex-grow:1) y eso incluye hacerlo más grande o pequeño
flex
Es poner en una misma linea flex-grow, flex-shrink y flex-basis
Mas información en: * Understanding flex-grow, flex-shrink, and flex-basis * Diferencia entre flex basis y width * Guia definitiva de Flexbox (2): Flex basis, flex-frow, flex-shrink * Las propiedades flex-grow, flex-shrink y flex-basis
margin y auto
Una utilidad de flexbox es hacer menús pero a veces queremos mover algunos item hacia la derecha.El truco para hacerlo es usar margin-left: auto; En los siguientes páginas se indica como hacerlos.
<div style="display:flex"> <div >Item1</div> <div >Item2</div> <div >Item3</div> <div style="margin-left:auto">Item4</div> <div >Item5</div> </div>
En el ejemplo, los items 1 , 2 y 3 estarán pegados a la izquierda y los items 4 y 5 estarán pegados a la derecha.
Mas información en:
* The Most Popular Navigation Bars created with Flexbox * Understanding Flexbox - auto-margin
Para aprender flexbox puede jugar a Flexbox Froggy - A game for learning CSS flexbox
Grid
Grid permite colocar cosas en dos dimensiones. Como si fuera una rejilla (un grid en inglés).
* Guías completas de Grid: * Getting Started with CSS Grid * A Complete Guide to Grid * CSS Grid is a two-dimensional layout system created specifically to tackle grid-based user interfaces on the web. * The Ultimate CSS Grid Tutorial for Beginners (With Interactive Examples) * css_grid_layout_cheatsheet.pdf * Grid vs FlexBox: * Video:l-flexbox vs. CSS Grid — Which is Better? * Does CSS Grid Replace l-flexbox? * Mas información: * justify-items * Los 9 grandes errores con CSS Grid * Things I’ve Learned About CSS Grid Layout * Notes on using CSS Grid in production: Tiene de interesante el uso de "@movil" y el uso de bucles en SASS * Grid by Example
.container {
display:grid;
grid-template-columns: 1fr 1fr 2fr;
grid-template-rows: 1fr 2fr;
}
.item {
border:1px solid red;
}
<div class="container"> <div class="item">Item1</div> <div class="item">Item2</div> <div class="item">Item3</div> <div class="item">Item4</div> <div class="item">Item5</div> <div class="item">Item6</div> </div>
grid-template-columns
Indica el tamaño de cada columna
Las unidades pueden ser: * Tamaño fijo: Usar px * auto: Coje el menos tamaño posible * fr: Es una fracción del espacio libre después de quitar las columnas de tamaño fijo (Las 2 formas anteriores, px y auto)
Ejemplos:
* grid-template-columns: 1fr 1fr 2fr La última columna tendrá el doble de tamaño que las anteriores
* grid-template-columns: 1fr 1fr 50px La segunda columna tendrá el mismo de tamaño que la primera. La última siempre 50px
* grid-template-columns: 1fr 2fr 80px auto La última tendrá un tamaño mínimo posible, la tercera tendrá 80px, la segunda el doble que la primera.
repeat
Si hay muchas columnas y todas del mismo tamaño en vez de
.container {
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
}
se puede escribir:
grid-template-columns: repeat(6, 1fr);
o en vez de
.container {
grid-template-columns: 100px 100px 100px 100px 100px 100px ;
}
se puede escribir:
grid-template-columns: repeat(6, 100px );
auto-fit
Si el tamaño de las columnas es fijo se puede hacer lo siguiente para no especificar el número de columnas y que sea variable según el ancho de la ventana:
.container {
grid-template-columns: repeat(auto-fit, 100px );
}
En ese caso ocupará todas las filas que sea necesario para poder poner ponerlo todo. Es una forma de hacer las cosas responsivas.
Por último se puede usar la función minmax de CSS para hacerlo de la siguiente forma
.container {
grid-template-columns: repeat( auto-fit, minmax( 100px, 1fr ) );
}
Que hará que cada columna ocupe como mínimo 100px y si hay mas espacio crecerá hasta ocupar todo. Pero se crearán tantas filas como sea necesario. Mas información en repeat,auto-fit,minmax,1fr y en MinMax in CSS Grid — 3/3 Flexibility
minmax es similar a las propiedades css de:
* min-width
* min-height
* max-width
* max-height
Ejemplo
Veamos ahora un ejemplo de la diferencia entre repeat(4,1fr) , repeat(auto-fit,100px) y repeat( auto-fit, minmax( 100px, 1fr ) )
.container {
display:grid;
grid-template-columns: repeat(4,1fr);
}
.container2 {
display:grid;
grid-template-columns: repeat(auto-fit,100px);
}
.container3 {
display:grid;
grid-template-columns: repeat( auto-fit, minmax( 100px, 1fr ) );
}
.container4 {
display:grid;
grid-template-columns: repeat( 4, minmax( 100px, 1fr ) );
}
.item {
border:1px solid red;
}
.item2 {
border:1px solid green;
}
.item3 {
border:1px solid blue;
}
.item4 {
border:1px solid pink;
}
<p>repeat(4,1fr)</p> <div class="container"> <div class="item">Item1</div> <div class="item">Item2</div> <div class="item">Item3</div> <div class="item">Item4</div> <div class="item">Item5</div> <div class="item">Item6</div> <div class="item">Item7</div> <div class="item">Item8</div> </div> <br> <p>repeat(auto-fit,100px)</p> <div class="container2"> <div class="item2">Item1</div> <div class="item2">Item2</div> <div class="item2">Item3</div> <div class="item2">Item4</div> <div class="item2">Item5</div> <div class="item2">Item6</div> <div class="item2">Item7</div> <div class="item2">Item8</div> </div> <br> <p>repeat( auto-fit, minmax( 100px, 1fr ) )</p> <div class="container3"> <div class="item3">Item1</div> <div class="item3">Item2</div> <div class="item3">Item3</div> <div class="item3">Item4</div> <div class="item3">Item5</div> <div class="item3">Item6</div> <div class="item3">Item7</div> <div class="item3">Item8</div> </div> <p>repeat( 4, minmax( 100px, 1fr ) )</p> <div class="container4"> <div class="item4">Item1</div> <div class="item4">Item2</div> <div class="item4">Item3</div> <div class="item4">Item4</div> <div class="item4">Item5</div> <div class="item4">Item6</div> <div class="item4">Item7</div> <div class="item4">Item8</div> </div>
grid-template-rows
Es lo mismo que grid-template-columns pero referido a las filas.
gap
Indica la separación entre cada una de las celdas del grid.
.container {
gap: 15px 10px;
}
gap también funciona con l-flex
Bloque de Layout por columnas
Ejemplo de Layout con BEM por columnas.
.l-columns {
display: grid;
grid-template-columns: repeat(1, 1fr);
}
.l-columns--2 {
grid-template-columns: repeat(2, 1fr);
}
.l-columns--3 {
grid-template-columns: repeat(3, 1fr);
}
.l-columns--4 {
grid-template-columns: repeat(4, 1fr);
}
<div class="l-columns l-columns--3"> <div> <h2>Column A </h2> </div> <div > <h2>Column B</h2> </div> <div> <h2>Column C </h2> </div> <div> <h2>Column D</h2> </div> <div> <h2>Column E</h2> </div> <div> <h2>Column F</h2> </div> </div>
span
Se puede hacer que un elemento ocupe más de una columna con grid-column: span x; siendo x el número de columnas que quieres que se expanda.
.l-columns {
display: grid;
&--4 {
grid-template-columns: repeat(4, 1fr);
}
&__area {
// Si tuvieras más estilos para el área, irían aquí
&--span2 {
grid-column: span 2;
}
}
}
<div class="l-columns l-columns--4"> <div class="l-columns__area"></div> <div class="l-columns__area"></div> <div class="l-columns__area"></div> <div class="l-columns__area"></div> <div class="l-columns__area"></div> <div class="l-columns__area l-columns__area--span2"></div> <div class="l-columns__area"></div> </div>
* Mas información * How to Build Web Form Layouts With CSS Grid * Tutorial: A Responsive Form Layout with CSS Grid
grid-template-areas
la propiedad grid-template-areas permite especificar exactamente como colocar los div en un contenedor. Para explicarlo lo vamos a ver con un ejemplo.
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.contenedor {
display: grid;
grid-template-areas:
"cabecera cabecera cabecera cabecera cabecera"
"lateral-izquierdo cuerpo cuerpo cuerpo lateral-derecho"
"pie pie pie pie pie";
}
.cabecera {
grid-area: cabecera;
}
.cuerpo {
grid-area: cuerpo;
}
.lateral-izquierdo {
grid-area: lateral-izquierdo;
}
.lateral-derecho {
grid-area: lateral-derecho;
}
.pie {
grid-area: pie;
}
</style>
</head>
<body>
<div class="contenedor">
<div class="cabecera">CABECERA</div>
<div class="lateral-izquierdo">IZQUIERDA</div>
<div class="cuerpo">CUERPO</div>
<div class="lateral-derecho">DERECHA</div>
<div class="pie">PIE</div>
</div>
</body>
</html>
Mas información: * grid-template-areas * Understanding CSS Grid: Grid Template Areas
Reglas de Layout
Para hacer una clase de Layout hay que seguir las siguientes reglas:
* Siempre con dos elementos.
* El div principal, al que llamaremos "padre"
* Los div hijos que llamaremos "áreas" (Es para seguir la nomenclatura de grid)
* El CSS solo debe tener cosas para modificar la posición (y a veces tamaño) de las Áreas pero no cambiar ni sus colores, fuentes, etc.
* Puede ser optativo poner en las areas la clase del elemento si no tiene utilidad.
* Las clases CSS de los elementos que son area se llamará &-area o &-areaYYYY.
.l-extremo {
display:flex
&__area-izquierda {
margin-right: auto;
}
&__area-derecha {
margin-left: auto;
}
}
.l-columns {
display: grid;
grid-template-columns: repeat(1, 1fr);
@for $i from 1 to 12 {
&--#{$i} {
grid-template-columns: repeat($i, 1fr);
}
}
&__area {
}
}
<div class="l-extremo"> <div class="l-extremo__area-izquierda"> <div class="c-button">Pulsar Izquierda</div> </div> <div class="l-extremo__area-derecha"> <div class="c-button">Pulsar Derecha</div> </div> </div>
* En un área se podría poner un componente ya que sus propiedades CSS no van a chocar.
<div class="l-extremo"> <div class="l-extremo__area-izquierda c-button">Pulsar Izquierda</div> <div class="l-extremo__area-derecha c-button">Pulsar Derecha</div> </div>
Artículos en general sobre Layout * 1-Line Layouts.10 Modern CSS layout and sizing techniques * Modern CSS Solutions
Ejercicios
Ejercicio 1
Crea los componentes que necesites para que funcione lo siguiente:
<landing-page> <landing-page__cabecera>CABECERA</landing-page__cabecera> <landing-page__lateral-izquierdo>IZQUIERDA</landing-page__lateral-izquierdo> <landing-page__cuerpo>CUERPO</landing-page__cuerpo> <landing-page__lateralDerecho>DERECHA</landing-page__lateral-derecho> <landing-page__pie>PIE</landing-page__pie> </landing-page>








