Tutorial de Flexbox y Sass Grid: cómo optimizar el diseño receptivo

Publicado: 2022-03-11

Recientemente, me desafiaron a crear mi propio sistema de cuadrícula y, dado que reinventar la rueda siempre es útil como experiencia de aprendizaje, lo hice. Sabía que sería un desafío interesante, ¡pero me sorprendió lo fácil que resultó ser!

Tutorial de cuadrícula Sass y Flexbox

En este experimento, veremos los diseños de Flexbox y cómo permiten implementaciones elegantes de diseños sin hacer ningún truco loco. Además, si no está familiarizado con Sass, veremos cómo funciona y usaremos algunas utilidades útiles de Sass. Incluso podría aprender algo nuevo sobre las cuadrículas CSS como la que forma parte de Bootstrap.

Una introducción muy breve de Sass y Flexbox

Sass es básicamente una herramienta que le permite evitar algunas de las deficiencias de CSS, es un lenguaje de secuencias de comandos que se interpreta en CSS. La sintaxis parece muy familiar si ya está escribiendo estilos CSS, pero su caja de herramientas incluye variables, mixins para reutilización y directivas if, for, each y while, entre otras. Una de las cosas más útiles de Sass es que cualquier código CSS válido es Sass válido, por lo que puede transformar progresivamente su base de código.

Un ejemplo simple de un bucle for:

 @for $i from 1 through 3 { .a-numbered-class-#{$i} { width: (20 * $i) * 1px; } }

Este ciclo simple itera de 1 a 3 y crea clases. El índice de la iteración se almacenará cómodamente en $i . También podemos hacer matemáticas e imprimir el .a-numbered-class-X tres veces con un ancho diferente cada vez. Este código genera:

 .a-numbered-class-1 { width: 20px; } .a-numbered-class-2 { width: 40px; } .a-numbered-class-3 { width: 60px; }

Como podemos ver, podemos abstraer mucho del trabajo que tendría que hacer en CSS. En CSS, tendrías que copiar y pegar y modificar manualmente, lo que obviamente es más propenso a errores y menos elegante. Si aún no lo has probado, ¡no pierdas más tiempo!

Flexbox significa Flexible Box, un sistema de diseño CSS3 que posiciona y distribuye elementos dinámicamente. Es una herramienta muy poderosa que permite diseños flexibles con un mínimo esfuerzo. Para obtener más detalles sobre cómo aprender Flexbox, consulte la Guía completa de Flexbox de Chris Coyier.

La cuadrícula

Pasando a la cuadrícula en sí, comencemos con sus elementos básicos. Estarán inspirados en los elementos de la cuadrícula de Bootstrap: Contenedores, Filas y Columnas, cada uno contenido dentro del primero.

Usaremos las convenciones de nomenclatura BEM para los nombres de las clases. Las convenciones BEM son bastante simples de usar y agregan mucha información sobre el elemento y su contexto. En pocas palabras, usted tiene:

  • Bloques , que “encapsulan una entidad independiente que es significativa por sí misma”: .block .
  • Elementos , que son "partes de un bloque y no tienen un significado independiente", que se indican con el nombre del bloque, dos guiones bajos y el elemento: .block__elem
  • Modificadores , como "Banderas en bloques o elementos", que se representan con dos guiones: .block .block--mod .

Contenedores, Filas y Columnas

Contenedores

Este es el elemento más externo de la cuadrícula, contendrá nuestros elementos de fila. Hay dos tipos de contenedores: .container y .container--fluid .

El comportamiento de .container se define por tener el 100% del ancho por debajo de cierto punto, tener un ancho máximo fijo por encima y tener márgenes iguales a la izquierda y a la derecha:

 $grid__bp-md: 768; .container { max-width: $grid__bp-md * 1px; margin: 0 auto; }

Juega con él aquí expandiendo y contrayendo la ventana de "salida"

Para el contenedor de fluidos, que siempre tiene un ancho del 100 %, simplemente anulamos esas propiedades con un modificador:

 &--fluid { margin: 0; max-width: 100%; }

Juega con eso aquí.

¡Eso fue fácil! Ahora tenemos ambos contenedores implementados. Pasemos al siguiente elemento.

filas

Las filas serán los organizadores horizontales de nuestro contenido.

Usaremos Flexbox para colocar los elementos secundarios de una fila, haciéndolos ajustar para que no se desborden y dándoles un 100 % de ancho dentro de la fila (para que podamos anidarlos más tarde).

 &__row { display: flex; flex-wrap: wrap; width: 100%; }

Esto colocará los elementos secundarios uno al lado del otro y los envolverá en nuevas líneas si la suma de su ancho es mayor que él mismo. Ahora solo necesitamos agregar algunos divs y se verá así:

Elementos de fila

Juega con él aquí expandiendo y contrayendo la ventana de "salida".

Las cosas están empezando a tomar forma, pero esto todavía no es una grilla CSS. Esta perdido…

columnas

Las columnas son donde vive el contenido del sitio. Definen en cuántas partes se divide la fila y cuánto ocupan. Vamos a hacer un diseño de doce columnas. Esto significa que podemos dividir la fila en una o hasta en doce partes.

Para empezar, algunas matemáticas básicas. Cuando queremos tener una columna, su ancho debe ser del 100%. Si queremos doce columnas. Entonces cada uno debe ocupar 8.333…% o 100/12 del ancho.

Con Flexbox, para distribuir contenido de esta manera, podemos usar flex-basis .

Para dividir en cuatro columnas, ahora agregaríamos algo como:

 flex-basis: (100 / 4 ) * 1%;

De esta manera, podemos hacer que los elementos ocupen cada uno el 25 % del ancho, o el porcentaje que queramos.

Juega con eso aquí.

Hagámoslo más dinámico. Como queremos que esto refleje nuestras posibles clases, llamemos .col-1 , una clase para una columna div que tendrá el 8,333 % del ancho, ya que deben caber doce de ellas antes de que tengan que ajustarse a una nueva línea. El porcentaje se incrementará a lo largo .col-12 , que ocupará el 100%.

 $grid__cols: 12; @for $i from 1 through $grid__cols { .col-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } }

Solo para aclarar lo que está pasando, digamos que queremos dividir el ancho en cuatro partes iguales. Necesitaríamos .col-3 ya que cabe 4 veces en 12, eso significa que .col-3 debería tener un 25% de base flexible:

 100 / ($grid__cols / $i) 100 / (12 / 3) = 25

¡Esto ya empieza a parecerse a una cuadrícula!

¡Parece una rejilla!

Juega con eso aquí.

Columnas dependientes del ancho de pantalla

Ahora queremos poder tener un elemento que tenga un cierto ancho en el móvil pero uno diferente en las tabletas y así sucesivamente. Usaremos ciertos puntos de interrupción dependiendo del ancho de la ventana. Nuestra interfaz de usuario reaccionará en esos puntos de interrupción y se adaptará a un diseño ideal para los tamaños de pantalla de diferentes dispositivos. Nombraremos los puntos de ruptura por tamaño: pequeño (sm), mediano (md) y así sucesivamente, .col-sm-12 será un elemento que ocupará 12 columnas como mínimo hasta el punto de ruptura sm .

Cambiemos el nombre de la clase .col- .col-* .col-sm-* . Dado que nuestra cuadrícula será móvil primero, aplicaremos sus propiedades a todos los tamaños de pantalla. Para los que necesitamos comportarse de manera diferente con pantallas más grandes, agregaremos la clase: .col-md-* .

Imagina un elemento con .col-sm-12 y .col-md-4 . El comportamiento esperado será que por debajo del punto de interrupción "md" (medio) tendrá un ancho del 100 % y por encima tendrá un 33,333 %, algo muy común, ya que en dispositivos móviles es posible que necesite apilar elementos en la parte superior en lugar de al lado. entre sí cuando su ancho es mucho más limitado.

Apilar columnas después de alcanzar un punto de interrupción

Para esto, necesitaremos agregar una consulta de medios (una expresión que contiene código que solo se ejecutará por encima o por debajo de un cierto ancho o en un dispositivo específico) en el punto de interrupción y crear nuestras columnas md como hicimos antes para sm :

 @media screen and (min-width: $grid__bp-md * 1px) { @for $i from 1 through $grid__cols { &__col-md-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } } }

Juega con eso aquí.

Eso ya se está acercando a algo útil. Eso es bastante HÚMEDO (¿Entiendes? No es SECO…), así que hagámoslo más abstracto.

Como vimos, vamos a necesitar una consulta de medios para cada punto de interrupción, así que creemos un mixin que reciba un punto de interrupción que cree dinámicamente consultas de medios. Podría verse algo como esto:

 @mixin create-mq($breakpoint) { @if($breakpoint == 0) { @content; } @else { @media screen and (min-width: $breakpoint *1px) { @content; } } }

Ahora, envolvamos lo que teníamos para crear las clases __col en un mixin llamado create-col-classes y usemos el mixin create-mq .

 @mixin create-col-classes($modifier, $grid__cols, $breakpoint) { @include create-mq($breakpoint) { @for $i from 1 through $grid__cols { &__col#{$modifier}-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } } } }

Y eso es. Para usarlo, ahora definimos nuestros puntos de interrupción en un mapa Sass y los iteramos.

 $map-grid-props: ('-sm': 0, '-md': $grid__bp-md, '-lg': $grid__bp-lg); @each $modifier , $breakpoint in $map-grid-props { @include create-col-classes($modifier, $grid__cols, $breakpoint); }

¡Nuestro sistema de cuadrícula está básicamente listo! Hemos definido una .container__col-sm-* que será la predeterminada y podemos modificar su comportamiento en pantallas más grandes con container__col-md-* y container__col-lg-* .

¡Incluso podemos anidar filas! Juega con eso aquí.

Lo bueno de esto es que si ahora quisiéramos que tuviera los mismos puntos de interrupción que Bootstrap v4, solo tendríamos que hacer lo siguiente:

 $grid__bp-sm: 576; $grid__bp-md: 768; $grid__bp-lg: 992; $grid__bp-xl: 1200; $map-grid-props: ( '': 0, '-sm': $grid__bp-sm, '-md': $grid__bp-md, '-lg': $grid__bp-lg, '-xl': $grid__bp-xl );

¡Y eso es! Juega con eso aquí.

Observe cómo Bootstrap adopta un enfoque móvil primero más completo de lo que discutimos inicialmente. Los tamaños de ventana más pequeños no tienen sufijos como sm o md , el razonamiento es que la clase equivalente a .container__col-X no solo se aplicará desde un ancho de ventana de 0 a 576px; si no lo sobrescribimos explícitamente, será ese número de columnas en cada tamaño de ventana. De lo contrario, podríamos agregar la clase .container__col-sm-Y para que tenga un ancho de Y columnas entre los puntos de interrupción de sm .

Compensaciones

Las compensaciones agregarán un margen a la izquierda con respecto a la columna anterior. Un .container__col-offset-4 agregará un margin-left: 33.333% en todos los tamaños de pantalla. .container__col-md-offset-4 hará lo mismo pero por encima del punto de interrupción md .

La implementación ahora es trivial; agregamos una propiedad -offset en el mismo ciclo que creamos las clases, pero en lugar de flex-bases , escribimos la propiedad margin-left . También tenemos que hacer uno adicional para -offset-0 , ya que es posible que queramos borrar el margen en pantallas más grandes:

 @mixin create-col-classes($modifier, $grid-cols, $breakpoint) { @include create-mq($breakpoint) { &__col#{$modifier}-offset-0 { margin-left: 0; } @for $i from 1 through $grid-cols { &__col#{$modifier}-#{$i} { flex-basis: (100 / ($grid-cols / $i) ) * 1%; } &__col#{$modifier}-offset-#{$i} { margin-left: (100 / ($grid-cols / $i) ) * 1%; } } } }

¡Ahora tenemos compensaciones completamente funcionales! Juega con eso aquí.

Visualización

A veces queremos mostrar/ocultar un elemento por debajo o por encima de cierto punto. Para ello, podemos poner a disposición clases como las de Bootstrap v4.

Por ejemplo, la clase .hidden-md-up ocultará cualquier elemento con esta clase desde el punto de interrupción md hacia arriba; por el contrario, .hidden-md-down lo ocultará desde el punto de interrupción hacia abajo.

El código para esto es simple una vez más: simplemente iteramos nuestros puntos de interrupción y creamos una clase .hidden-* con un for each punto de interrupción. Sin embargo, modificamos la clase create-mq para que sea un poco más abstracta:

 @each $modifier , $breakpoint in $map-grid-props { @if($modifier == '') { $modifier: '-xs'; } @include create-mq($breakpoint - 1, 'max') { .hidden#{$modifier}-down { display: none !important; } } @include create-mq($breakpoint, 'min') { .hidden#{$modifier}-up { display: none !important; } } }

Como nota al margen, ¿no es este uno de los pocos buenos usos de !important ? Tenga en cuenta que el elemento puede tener una especificidad arbitrariamente mayor con una regla de display: block , pero aun así querríamos ocultarlo debajo o arriba del punto de interrupción. Si no estás de acuerdo con este enfoque, ¡házmelo saber en los comentarios!

Eso es todo: ahora tenemos un sistema de visualización.

Juega con eso aquí.

Conclusión

Si bien este "marco" no está listo para la producción, muestra cuán poderosos pueden ser los diseños de Flexbox y cuán útil es Sass. Con solo unas pocas líneas de código, implementamos la funcionalidad central de un marco/cuadrícula CSS.

Que también sirva como lección que una versión básica de prácticamente cualquier software se puede implementar muy fácilmente. Son los problemas concretos del mundo real los que empiezan a sumarse y dificultarlo.

Creé un repositorio de GitHub donde puede enviar problemas o solicitudes de extracción.

¿Qué características le gustaría ver implementadas? ¿Podría simplificarse la implementación o ser más elegante?

Siéntase libre de dejarme saber su opinión en los comentarios a continuación.