Hacer un gráfico de barras con CSS Grid | Programar Plus

Nota del editor: esta publicación es solo un experimento para jugar con nuevas propiedades CSS, por lo que el código a continuación no debe usarse sin mejoras serias en la accesibilidad.

Tengo una obsesión peculiar con los gráficos y, por alguna razón, quiero descubrir todas las formas de hacerlos con CSS. Supongo que es por dos razones. En primer lugar, creo que es interesante que haya un millón de formas diferentes de diseñar gráficos y datos en la web. En segundo lugar, es excelente para aprender sobre tecnologías nuevas y desconocidas. En este caso: CSS Grid!

Así que esta obsesión mía por los gráficos me hizo pensar: ¿cómo harías para hacer un gráfico de barras simple y receptivo con CSS Grid, como este?

Vea el cuadro de cuadrícula de Pen CSS final de Robin Rendle (@robinrendle) en CodePen.

¡Veamos cómo llegué allí!

El enfoque rápido y fácil

Dado que Grid puede ser confuso y extraño a primera vista, centrémonos en hacer un prototipo realmente extraño para empezar. Para comenzar, necesitamos escribir el marcado para nuestro gráfico:

<div class="chart">
  <div class="bar-1"></div>
  <div class="bar-2"></div>
  <div class="bar-3"></div>
  <div class="bar-4"></div>
  <!--  all the way up to bar-12 -->
</div>

cada uno de esos bar- las clases formarán una barra completa en nuestro gráfico y, por asqueroso que parezca, por ahora no nos preocuparemos demasiado por la semántica o el etiquetado de la cuadrícula o los datos. Eso vendrá más adelante. Centrémonos en el CSS para que podamos aprender más sobre Grid.

¡Bien, con eso ahora podemos obtener estilo! Necesitamos 12 barras en nuestro gráfico con un espacio de 5 px entre ellas para que podamos configurar nuestra clase principal .chart con las propiedades relevantes de CSS Grid:

.chart {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-column-gap: 5px;
}

Eso es bastante sencillo si está familiarizado con Grid, pero lo que describe efectivamente es esto: “Quiero 12 columnas con cada uno de los elementos secundarios que tienen el mismo ancho (1 fracción) con un espacio de 5px entre ellos”.

Pero ahora, aquí está la parte disimulada: con Grid podemos usar el grid-template-rows propiedad para establecer la altura de cada barra de nuestro gráfico:

.chart {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-template-rows: repeat(100, 1fr);
  grid-column-gap: 5px;
}

Podemos usar esa propiedad nueva y ordenada para hacer 100 filas en nuestra cuadrícula y de esta manera podemos establecer que cada una de nuestras barras sea un porcentaje de esa altura y nos facilitará las matemáticas. Nuevamente, estamos usando eso repeat() para que cada una de nuestras filas tenga la misma altura.

Antes de explicarlo todo con más detalle, demos a nuestro gráfico un ancho máximo y configurémoslo en el centro de la pantalla con flex:

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background-color: #eee;
  display: flex;
  justify-content: center;
}

.chart {
  height: 100vh;
  width: 70vw;
  /* other chart styles go here */
}

En este punto, nuestro gráfico aún estará vacío porque no le hemos dicho a nuestros elementos secundarios que ocupen ningún espacio en la cuadrícula. ¡Así que arreglemos eso! Vamos a seleccionar cada clase que contenga bar y usa el grid-row-start y grid-row-end properties para hacer que llenen el espacio vertical en nuestra cuadrícula y eventualmente terminaremos cambiando una de estas propiedades para definir la altura personalizada de cada barra:

[class*="bar"] {
  grid-row-start: 1;
  grid-row-end: 101;
  border-radius: 5px 5px 0 0;
  background-color: #ff4136;
}

Consulte el cuadro de cuadrícula 1 de Pen CSS de Robin Rendle (@robinrendle) en CodePen.

Así que si estás desconcertado por esos grid-row propiedades entonces está bien! Le estamos diciendo a cada una de nuestras barras que comience en la parte superior de la cuadrícula (1) y luego termine en la parte inferior (101). Pero, ¿por qué usamos 101 como valor para esa propiedad cuando solo le dijimos a nuestra cuadrícula que contuviera 100 filas? ¡Exploremos eso un poco antes de continuar!

Líneas de cuadrícula

Una de las cosas peculiares de Grid que no había considerado antes de trabajar en esta demostración fue el concepto de líneas de cuadrícula, que es muy importante para comprender esta nueva herramienta de diseño. Aquí hay una ilustración de cómo se trazan las líneas de cuadrícula en una cuadrícula de cuatro columnas y cuatro filas:

Este nuevo ejemplo contiene cuatro columnas y cuatro filas con los siguientes estilos:

.grid {
  grid-gap: 5px;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
}

.special-col {
  grid-row: 2 / 4;
  background-color: #222;
}

grid-row es una propiedad abreviada para grid-row-start y grid-row-end con el primer valor donde queremos que el elemento comience en la grilla y el valor final donde queremos que termine. ¡Pero! Esto significa que queremos que ese elemento especial aquí comience en la línea de cuadrícula 2 y termine en la línea de cuadrícula 4: no al final de la fila 4. Si quisiéramos que el cuadro negro llenara las 4 filas, necesitaríamos que terminara en la línea 5 o grid-row: 2 / 5 lo cual tiene mucho sentido si lo piensas.

En otras palabras, no deberíamos pensar en elementos que ocupen filas o columnas enteras en una cuadrícula, sino que solo se extiendan entre estas líneas de cuadrícula. Me tomó un tiempo entenderlo conceptualmente y acostumbrarme después de sumergirme en un tutorial reciente de Jen Simmons sobre el tema.

¡De todos modos!

Volver a la demostración

Esa es la razón por la que en nuestra demostración de gráfico terminamos todas las columnas en la línea 101 y no en la 100, porque queremos que llene la última fila (100), así que tenemos que enviarla a esa línea de cuadrícula en particular (101).

Ahora bien, desde nuestro .chart class usa unidades vw/vh, también tenemos un gráfico que responde muy bien sin tener que hacer mucho trabajo. Si cambia el tamaño de ese gráfico a continuación, encontrará que se empaqueta o se estira muy bien para ocupar siempre toda la ventana gráfica:

Consulte el cuadro de cuadrícula 1 de Pen CSS de Robin Rendle (@robinrendle) en CodePen.

Desde aquí, podemos comenzar a diseñar cada una de las barras individuales para darles los datos correctos, y hay muchas formas diferentes de hacerlo. Echemos un vistazo a sólo uno de ellos.

Primero, imaginemos que queremos la primera barra en nuestro gráfico, .bar-1, para ser 50/100 o la mitad de la altura del gráfico. Podríamos escribir el siguiente CSS y listo:

[class*="bar"] {
  grid-row-end: 101;
}

.bar-1 {
  grid-row-start: 50;
}

Consulte Pen CSS Grid Chart 2 de Robin Rendle (@robinrendle) en CodePen.

¡Eso se ve bien! Pero, aquí está el problema: lo que realmente estamos declarando con eso grid-row-start es que la barra comience en “50” y termine en “101”, pero eso no es realmente lo que queremos. Aquí hay un ejemplo: digamos que los datos cambian en este ejemplo hipotético y necesitamos que ahora sea 20/100. Volvamos atrás y cambiemos el valor:

.bar-1 {
  grid-row-start: 20;
}

Consulte Pen CSS Grid Chart 3 de Robin Rendle (@robinrendle) en CodePen.

¡Eso no está bien! Queremos que la barra no comience en la cuadrícula en 30, sino que tenga un 30 % de la altura de la altura del gráfico. Podríamos cambiar nuestro valor a grid-row-start: 20; o podemos usar el grid-row-end propiedad en su lugar, ¿verdad? Bueno, no del todo:

.bar-1 {
  grid-row-end: 20;
}

Consulte Pen CSS Grid Chart 4 de Robin Rendle (@robinrendle) en CodePen.

El tamaño de la barra es correcto pero la posición es incorrecta porque le estamos diciendo a la barra que termine en 30/100. Entonces, ¿cómo solucionamos esto y hacemos que nuestro código sea muy fácil de leer? Bueno, un enfoque es usar Sass para hacer los cálculos por nosotros. Idealmente, nos gustaría escribir algo como lo siguiente:

.bar-1 {
  // makes a bar that's 60/100 and positioned at the bottom of our chart
  @include chartValue(60);
}

Y no importa qué valor le demos a esa mezcla, siempre queremos obtener la altura y la posición correctas del gráfico en la cuadrícula. Las matemáticas que impulsan esta combinación son bastante simples: todo lo que tenemos que hacer es tomar nuestro valor, deducirlo del número total de filas y luego adjuntarlo al grid-row-start propiedad, así:

@mixin chartValue($data) {
  $totalRows: 101;
  $result: $totalRows - $data;
  grid-row-start: $result;
}

.bar-1 {
  @include chartValue(20);
}

Consulte Pen CSS Grid Chart 5 de Robin Rendle (@robinrendle) en CodePen.

Entonces, el valor final que produce nuestra mezcla Sass es grid-row-start: 81 ¡pero nuestro código es súper legible! Ni siquiera tenemos que mirar nuestra cuadrícula para saber qué va a pasar: el elemento del gráfico se colocará en la parte inferior de la cuadrícula y el valor siempre será correcto.

Sin embargo, ¿cómo creamos todas esas clases de cuadrícula? Creo que un buen enfoque es simplemente dejar que Sass genere todas esas clases automáticamente para nosotros. Con solo una pequeña modificación a nuestro código podríamos hacer algo como esto:

$totalRows: 101;

@mixin chartValue($data) {
  $result: $totalRows - $data;
  grid-row-start: $result;
}

@for $i from 1 through $totalRows {
  .bar-#{$i} {
    @include chartValue($i);
  }
}

Esto iterará sobre todas las filas de nuestro gráfico y generará una clase individual para ese tamaño de fila. Y ahora podríamos actualizar nuestro marcado así:

<div class="bar-45"></div>
<div class="bar-100"></div>
<div class="bar-63"></div>
<div class="bar-11"></div>

Consulte Pen CSS Grid Chart 6 de Robin Rendle (@robinrendle) en CodePen.

¡Y ahí lo tenemos! No tenemos que escribir clases individuales para cada uno de nuestros elementos a mano y podemos actualizar fácilmente nuestro gráfico simplemente cambiando el marcado. Este ciclo Sass arrojará muchas clases que no se usan, pero hay muchas herramientas para eliminarlas.

Una última cosa que podemos hacer con nuestra cuadrícula es diseñar cada columna con un color par/impar:

[class*="bar"]:nth-child(odd) {
  background-color: #ff4136; 
}

[class*="bar"]:nth-child(even) {
  background-color: #0074d9;
}

Consulte Pen CSS Grid Chart 7 de Robin Rendle (@robinrendle) en CodePen.

¡Y ahí lo tenemos! Un gráfico receptivo creado con CSS Grid. Sin embargo, hay muchas cosas que podríamos hacer para ordenar este código. Lo primero que probablemente deberíamos hacer es asegurarnos de que estamos usando el marcado semántico y usar una herramienta para eliminar todas esas clases que nuestro bucle Sass está emitiendo. También podríamos profundizar en cómo se representa este gráfico en dispositivos móviles y pensar en cómo deberíamos etiquetar cada columna y eje del gráfico.

Pero por ahora, esto es solo el comienzo. El TL; DR de esta publicación: CSS Grid se puede usar para todo tipo de cosas en lugar de simplemente colocar texto e imágenes uno al lado del otro. Abre una rama completamente nueva del diseño web para que experimentemos.