
Diseños adaptables y propiedades CSS personalizados: creación de un sistema de cuadrícula flexible

- Un sistema de cuadrícula CSS simple
- Construyendo un sistema de red con Sass
- Construyendo un sistema de parrilla con propiedades CSS personalizadas
- Agregar un punto de interrupción a la cuadrícula
- Variables CSS y opciones de respaldo
- Agregar más puntos de interrupción
- Reducir las cadenas de respaldo
- ¿Por qué tan complicado?
- ¿Por qué debería molestarme de todos los modos?
- Rendimiento de las variables CSS
- No sólo sistemas de red
La última vez, analizamos algunos enfoques posibles para declarar y utilizar propiedades CSS personalizadas en diseños responsivos. En este artículo, veremos más acerca de las variables CSS y cómo usarlas en componentes y módulos reutilizables. Aprenderemos cómo hacer que nuestras variables sean opcionales y establecer valores alternativos.
Como ejemplo, construiremos un sistema de cuadrícula simple basado en flexbox. Los sistemas grid juegan un papel vital en los diseños responsivos. Sin embargo, construir un sistema de red que sea flexible y liviano al mismo tiempo puede ser una tarea complicada. Veamos cuáles son los enfoques comunes hacia los sistemas grid y cómo las propiedades personalizadas de CSS pueden ayudarnos a construirlos.
Serie de artículos:
- Definición de variables y puntos de interrupción
- Construyendo un sistema de red flexible (esta publicación)
Un sistema de cuadrícula CSS simple
Comenzamos con un sistema de cuadrícula de 12 columnas:
.container {max-width: 960px;margin: 0 auto;display: flex;}.col-1 { flex-basis: 8.333%; }.col-2 { flex-basis: 16.666%; }.col-3 { flex-basis: 25%; }.col-4 { flex-basis: 33.333%; }.col-5 { flex-basis: 41.666%; }.col-6 { flex-basis: 50%; }/* and so on up to 12... */
Aquí hay bastantes repeticiones y valores codificados. Sin mencionar cuántos más se generarán una vez que agreguemos más puntos de interrupción, clases de compensación, etc.
Construyendo un sistema de red con Sass
Para que nuestro ejemplo de cuadrícula sea más legible y fácil de mantener, usamos Sass para preprocesar nuestro CSS:
$columns: 12; // Number of columns in the grid system.container {display: flex;flex-wrap: wrap;margin: 0 auto;max-width: 960px;}@for $width from 1 through $columns {.col-#{$width} {flex-basis: $width / $columns * 100%;} }
Definitivamente es mucho más fácil trabajar con esto. A medida que desarrollamos más nuestra cuadrícula y, digamos, nos gustaría cambiarla de 12 columnas a 16 columnas, todo lo que tenemos que hacer es actualizar una sola variable (en comparación con docenas de clases y valores). Pero… mientras nuestro Sass sea más corto y más fácil de mantener ahora, el código compilado es idéntico al primer ejemplo. Todavía vamos a terminar con una enorme cantidad de código en el archivo CSS final. Exploramos qué sucede si intentamos reemplazar las variables Sass con propiedades personalizadas de CSS.
Construyendo un sistema de parrilla con propiedades CSS personalizadas
Antes de empezar a jugar con propiedades CSS personalizadas, comencemos primero con algo de HTML. Este es el diseño al que apuntamos:
Consta de tres elementos: un encabezado, una sección de contenido y una barra lateral. Creemos un marcado para esta vista, dándole a cada uno de los elementos una clase semántica única ( ,, header
) y una clase que indica que este elemento es parte de un sistema de cuadrícula:content
sidebar
column
divheaderheader/headermaincontent/mainasidesidebar/aside/div
Nuestro sistema de cuadrícula, como antes, se basa en un diseño de 12 columnas. Puedes imaginarlo como una superposición que cubre nuestras áreas de contenido:
Entonces .header
, toma las 12 columnas, .content
ocho columnas (66,(6)% del ancho total) y .sidebar
cuatro columnas (33,(3)% del ancho total). En nuestro CSS, nos gustaría poder controlar el ancho de cada sección cambiando una única propiedad personalizada:
.header {--width: 12;}.content {--width: 8;}.sidebar {--width: 4;}
Para que funcione, todo lo que necesitamos hacer es escribir una regla para la .column
clase. ¡Por suerte para nosotros, la mayor parte del trabajo ya está hecho! Podemos reutilizar Sass del capítulo anterior y reemplazar las variables de Sass con propiedades personalizadas de CSS:
.container {display: flex;flex-wrap: wrap;margin: 0 auto;max-width: 960px;}.column {--columns: 12; /* Number of columns in the grid system */--width: 0; /* Default width of the element */flex-basis: calc(var(--width) / var(--columns) * 100%);}
Observe dos cambios importantes aquí:
- Ahora la
--columns
variable se declara dentro de la.column
regla. El motivo es que no se debe utilizar fuera del ámbito de esta clase. - La ecuación matemática que realizamos en la
flex-basis
propiedad ahora está incluida dentro de unacalc()
función. Los cálculos matemáticos que se escriben en Sass son compilados por el preprocesador y no necesitan sintaxis adicional.calc()
, por otro lado, nos permite realizar cálculos matemáticos en CSS en vivo. La ecuación siempre debe estar incluida dentro de unacalc()
función.
En un nivel muy básico, ¡eso es todo! Acabamos de crear un sistema de cuadrícula de 12 columnas con propiedades CSS personalizadas. ¡Felicidades! Podríamos dar por finalizado el día y terminar este artículo ahora mismo, pero… generalmente necesitamos un sistema de cuadrícula que sea un poco más cómodo. Y aquí es cuando las cosas se ponen realmente interesantes.
Agregar un punto de interrupción a la cuadrícula
La mayoría de las veces, necesitamos que los diseños se vean diferentes en distintos tamaños de pantalla. Digamos que, en nuestro caso, queremos que el diseño permanezca tal como está en una ventana gráfica grande (por ejemplo, una computadora de escritorio), pero que los tres elementos ocupan todo el ancho en pantallas más pequeñas (por ejemplo, dispositivos móviles) .
Entonces, en este caso, nos gustaría que nuestras variables se vieran así:
.header {--width-mobile: 12;}.content {--width-mobile: 12;--width-tablet: 8; /* Tablet and larger */}.sidebar {--width-mobile: 12;--width-tablet: 4; /* Tablet and larger */}
.content
y .sidebar
ahora cada uno contiene dos variables. La primera variable ( --width-mobile
) es el número de columnas que un elemento debe ocupar de forma predeterminada, y la segunda ( --width-tablet
) es el número de columnas que un elemento debe ocupar en pantallas más grandes. El .header
elemento no cambia; siempre ocupa el ancho completo. En pantallas más grandes, el encabezado simplemente debe heredar el ancho que tiene en los dispositivos móviles.
Ahora, actualizamos nuestra .column
clase.
Variables CSS y opciones de respaldo
Para que la versión móvil funcione como se espera, necesitamos modificar la .column
clase de la siguiente manera:
.column {--columns: 12; /* Number of columns in the grid system */--width: var(--width-mobile, 0); /* Default width of the element */flex-basis: calc(var(--width) / var(--columns) * 100%);}
Básicamente, reemplazamos el valor de la --width
variable con --width-mobile
. Observe que la var()
función ahora toma dos argumentos. El primero de ellos es un valor predeterminado. Dice: “Si una --width-mobile
variable existe en un ámbito determinado, asigna su valor a la --width
variable”. El segundo argumento es un retroceso. En otras palabras: “Si una --width-mobile
variable no se declara en un ámbito determinado, asigne este valor alternativo a la --width
variable”. Configuramos este respaldo para prepararnos para un escenario en el que algunos elementos de la cuadrícula no tendrán un ancho específico.
Por ejemplo, nuestro .header
elemento tiene una --width-mobile
variable declarada, lo que significa que la --width
variable será igual a él y la flex-basis
propiedad de este elemento se calculará como 100%
:
.header {--width-mobile: 12;}.column {--columns: 12;--width: var(--width-mobile, 0); /* 12, takes the value of --width-mobile */flex-basis: calc(var(--width) / var(--columns) * 100%); /* 12 ÷ 12 × 100% = 100% */}
Si eliminamos la --width-mobile
variable de la .header
regla, la --width
variable utilizará un valor de respaldo:
.header {/* Nothing here... */}.column {--columns: 12;--width: var(--width-mobile, 0); /* 0, takes the the fallback value */flex-basis: calc(var(--width) / var(--columns) * 100%); /* 0 ÷ 12 × 100% = 0% */}
Ahora que entendemos cómo establecer una reserva para las propiedades CSS personalizadas, podemos crear un punto de interrupción agregando una consulta de medios a nuestro código:
.column {--columns: 12; /* Number of columns in the grid system */--width: var(--width-mobile, 0); /* Default width of the element */flex-basis: calc(var(--width) / var(--columns) * 100%);}@media (min-width: 576px) {.column {--width: var(--width-tablet); /* Width of the element on tablet and up */}}
Esto funciona exactamente como se espera, pero solo para el contenido y la barra lateral, es decir, para los elementos que tienen especificados tanto --width-mobile
y --width-tablet
. ¿Por qué?
La consulta de medios que creamos se aplica a todos .column
los elementos, incluso aquellos que no tienen una --width-tablet
variable declarada en su alcance. ¿Qué pasa si usamos una variable que no está declarada? La referencia a la variable no declarada en una var()
función se considera entonces inválida en el momento del valor calculado, es decir, inválida en el momento en que un agente de usuario intenta calcularla en el contexto de una declaración determinada.
Lo ideal sería que, en tal caso, --width: var(--width-tablet);
se ignorara la declaración y --width: var(--width-mobile, 0);
se utilizara en su lugar la declaración anterior de . Pero así no es como funcionan las propiedades personalizadas. De hecho, la --width-tablet
variable no válida se seguirá utilizando en la flex-basis
declaración. Una propiedad que contiene una var()
función no válida siempre se calcula como su valor inicial. Por lo tanto, como flex-basis: calc(var(--width) / var(--columns) * 100%);
contiene una var()
función no válida, toda la propiedad se calculará como auto
(el valor inicial de flex-basis
).
¿Qué más podemos hacer entonces? ¡Establecer un valor de reserva! Como aprendimos antes, una var()
función que contiene una referencia a la variable no declarada calcula su valor de reserva, siempre que se especifique. Por lo tanto, en este caso, podemos simplemente establecer un valor de reserva para la --width-tablet
variable:
.column {--columns: 12; /* Number of columns in the grid system */--width: var(--width-mobile, 0); /* Default width of the element */flex-basis: calc(var(--width) / var(--columns) * 100%);}@media (min-width: 576px) {.column {--width: var(--width-tablet, var(--width-mobile, 0));}}
Esto creará una cadena de valores alternativos, haciendo que la --width
propiedad se use --width-tablet
cuando esté disponible, luego --width-mobile
si --width-tablet
no se declara y, finalmente, 0
si ninguna de las variables está declarada. Este enfoque nos permite realizar numerosas combinaciones:
.section-1 {/* Flexible on all resolutions */}.section-2 {/* Full-width on mobile, half of the container's width on tablet and up */--width-mobile: 12;--width-tablet: 6;}.section-3 {/* Full-width on all resolutions */--width-mobile: 12;}.section-4 {/* Flexible on mobile, 25% of the container's width on tablet and up */--width-tablet: 3;}
Otra cosa que podemos hacer aquí es convertir el 0
valor predeterminado en otra variable para evitar la repetición. Esto hace que el código sea un poco más largo, pero más fácil de actualizar:
.column {--columns: 12; /* Number of columns in the grid system */--width-default: 0; /* Default width, makes it flexible */--width: var(--width-mobile, var(--width-default)); /* Width of the element */flex-basis: calc(var(--width) / var(--columns) * 100%);}@media (min-width: 576px) {.column {--width: var(--width-tablet, var(--width-mobile, var(--width-default)));}}
¡Ahora tenemos una roja flexible y completamente funcional! ¿Qué tal si agregamos algunos puntos de interrupción más?
Agregar más puntos de interrupción
Nuestra red ya es bastante poderosa pero a menudo necesitamos más de un punto de interrupción. Afortunadamente, agregar más puntos de interrupción a nuestro código no podría ser más sencillo. Todo lo que tenemos que hacer es reutilizar el código que ya tenemos y agregar una variable más:
.column {--columns: 12; /* Number of columns in the grid system */--width-default: 0; /* Default width, makes it flexible */--width: var(--width-mobile, var(--width-default)); /* Width of the element */flex-basis: calc(var(--width) / var(--columns) * 100%);}@media (min-width: 576px) {.column {--width: var(--width-tablet, var(--width-mobile, var(--width-default)));}}@media (min-width: 768px) {.column {--width: var(--width-desktop, var(--width-tablet, var(--width-mobile, var(--width-default))));}}
Reducir las cadenas de respaldo
Una cosa que no se ve tan bien en nuestro código es que las cadenas de retroalimentación se hacen cada vez más largas con cada punto de interrupción. Si queremos abordar este problema, podemos cambiar nuestro enfoque a algo como esto:
.column {--columns: 12; /* Number of columns in the grid system */--width: var(--width-mobile, 0); /* Width of the element */flex-basis: calc(var(--width) / var(--columns) * 100%);}@media (min-width: 576px) {.column {--width-tablet: var(--width-mobile);--width: var(--width-tablet);}}@media (min-width: 768px) {.column {--width-desktop: var(--width-tablet);--width: var(--width-desktop);}}
Este código hace exactamente el mismo trabajo, pero de una manera ligeramente diferente. En lugar de crear una cadena de respaldo completa para cada punto de interrupción, establecemos un valor de cada variable en la variable del punto de interrupción anterior como valor predeterminado.
¿Por qué tan complicado?
Parece que hemos trabajado bastante para completar una tarea relativamente simple. ¿Por qué? La respuesta principal es: hacer que el resto de nuestro código sea más simple y fácil de mantener. De hecho, podríamos construir el mismo diseño utilizando las técnicas descritas en la parte anterior de este artículo:
.container {display: flex;flex-wrap: wrap;margin: 0 auto;max-width: 960px;}.column {--columns: 12; /* Number of columns in the grid system */--width: 0; /* Default width of the element */flex-basis: calc(var(--width) / var(--columns) * 100%);}.header {--width: 12;}.content {--width: 12;}.sidebar {--width: 12;}@media (min-width: 576px) {.content {--width: 6;}.sidebar {--width: 6;}}@media (min-width: 768px) {.content {--width: 8;}.sidebar {--width: 4;}}
En un proyecto pequeño, este enfoque podría funcionar perfectamente. Sin embargo, para las soluciones más complejas, sugeriría considerar una solución más escalable.
¿Por qué debería molestarme de todos los modos?
Si el código presentado hace un trabajo muy similar al que podemos lograr con preprocesadores como Sass, ¿por qué deberíamos molestarnos en hacerlo? ¿Son mejores las propiedades personalizadas? La respuesta, como siempre, es: depende. Una ventaja de usar Sass es una mejor compatibilidad con los navegadores. Sin embargo, usar propiedades personalizadas también tiene algunas ventajas:
- Es CSS simple. En otras palabras, es una solución más estandarizada y confiable, independiente de terceros. Sin compilación, sin versiones de paquetes, sin problemas extraños. Simplemente funciona (aparte de los navegadores donde simplemente no funciona).
- Es más fácil depurar. Esto es cuestionable, ya que se puede argumentar que Sass proporciona retroalimentación a través de mensajes de consola y CSS no. Sin embargo, no puede ver y depurar el código preprocesado directamente en un navegador; Mientras trabaja con variables CSS, todo el código está disponible (¡y en vivo!) directamente en DevTools.
- Es más fácil de mantener. Las propiedades personalizadas nos permiten hacer cosas que son simplemente imposibles con cualquier preprocesador. Nos permite hacer que nuestras variables sean más contextuales y, por lo tanto, más fáciles de mantener. Además, se pueden seleccionar mediante JavaScript, algo que no ocurre con las variables de Sass.
- Es más flexible. Observe que el sistema de cuadrícula que hemos construido es extremadamente flexible. ¿Le gustaría utilizar una cuadrícula de 12 columnas en una página y una cuadrícula de 15 columnas en otra? Sea mi invitado: es una cuestión de una sola variable. Se puede utilizar el mismo código en ambas páginas. Un preprocesador requeriría generar código para dos sistemas de red separados.
- Ocupa menos espacio. Mientras que el peso de los archivos CSS no suele ser el principal obstáculo en el rendimiento de carga de la página, no hace falta decir que debemos intentar optimizar los archivos CSS cuando sea posible. Para dar una mejor imagen de cuánto se puede ahorrar, hice un pequeño experimento. Tomé el sistema grid de Bootstrap y lo reconstruí desde cero con propiedades personalizadas. Los resultados son los siguientes: la configuración básica de la parrilla Bootstrap genera más de 54 KB de CSS, mientras que una parrilla similar creada con propiedades personalizadas tiene solo 3 KB. ¡Esa es una diferencia del 94%! Es más, agregar más columnas a la cuadrícula Bootstrap hace que el archivo sea aún más grande. Con las variables CSS, podemos usar tantas columnas como queramos sin afectar en absoluto el tamaño del archivo.
Los archivos se pueden comprimir para minimizar un poco la diferencia. La cuadrícula de Bootstrap comprimida ocupa 6,4 KB en comparación con los 0,9 KB de la cuadrícula de propiedades personalizadas. ¡Esta sigue siendo una diferencia del 86%!
Rendimiento de las variables CSS
En resumen, el uso de propiedades personalizadas CSS tiene muchas ventajas, pero si estamos obligando al navegador a realizar todos los cálculos que han realizado los preprocesadores, ¿estamos afectando negativamente al rendimiento de nuestro sitio? Es cierto que el uso de propiedades y calc()
funciones personalizadas consumirá más potencia de procesamiento, pero en casos similares a los ejemplos que analizamos en este artículo, la diferencia normalmente será imperceptible. Si quieres aprender más sobre este tema, te recomiendo leer este excelente artículo de Lisi Linhart.
No sólo sistemas de red
Después de todo, comprender los entresijos de las propiedades personalizadas puede no ser tan fácil como parece. Definitivamente llevará tiempo, pero vale la pena. Las variables CSS pueden ser de gran ayuda cuando se trabaja con componentes reutilizables, sistemas de diseño, temas y soluciones personalizables. Saber cómo manejar los valores de reserva y las variables no declaradas puede resultar muy útil en ese caso.
¡Gracias por leer y buena suerte en tu propio viaje con propiedades personalizadas de CSS!
Deja una respuesta