Pixel art con CSS

Genera pixels utilizando box-shadow


Existe una técnica muy curiosa con la que se puede hacer pixel art sólo con CSS (o incluso combinar con bucles Javascript y hacerlo más flexible). A grandes rasgos, se trata de crear un elemento de un tamaño muy específico (por ejemplo, 32 pixels) y crear sombras sin desenfoque con el desplazamiento adecuado que simulen los pixels.

Creación de un píxel base

El primer paso, obviamente, será crear el pixel base en nuestro documento:

.pixel {
  background: black;
  width: 32px;
  height: 32px;
}
<div class="pixel"></div>

Una vez lo tenemos, todo se basará en utilizar box-shadow para crear nuevos píxels con desplazamiento.

Creación de siguientes píxels

Aquí puedes ver como creamos una sombra roja (se creará del mismo tamaño que el píxel base) y la desplazamos exactamente 32px a la derecha, por lo que aparecerá justo al lado del píxel base. Lo mismo con el siguiente píxel (color dorado):

.pixel {
  background: black;
  width: 32px;
  height: 32px;

  box-shadow:
    32px 0 0 red,
    64px 0 0 gold;
}
<div class="pixel"></div>

Para hacer el código más flexible y fácil de mantener, podemos hacer uso de variables CSS y organizar/reescribir un poco el código. Quizás puede ser más difícil de leer si no tienes cierta soltura con CSS, pero es mucho más flexible si necesitamos cambiar tamaños o similar:

.pixel {
  --size: 32px;

  background: black;
  width: var(--size);
  height: var(--size);

  box-shadow:
    calc(1 * var(--size)) 0 0 gold,
    calc(2 * var(--size)) 0 0 blue,
    0 calc(1 * var(--size)) 0 red,
    calc(1 * var(--size)) calc(1 * var(--size)) 0 hotpink;
}
<div class="pixel"></div>

Ahora podríamos cambiar el valor de la CSS custom property --size y el resto del código se adaptaría automáticamente, gracias a que hemos utilizado cálculos con la función calc() y variables css con la función var().

Usando Javascript para reutilizar

A continuación puedes ver un ejemplo más elaborado, donde utilizamos Javascript para simplificar nuestro código HTML y CSS, y generar los fragmentos repetibles. Observa que el HTML/CSS sólo tiene los detalles genéricos, y el resto lo creamos desde Javascript:

body {
  height: 350px;
  background: #44a;
}

.avatar {
  width: 256px;
  margin: 2em auto;
  height: 256px;
  background: linear-gradient(#8A4BEC, #E91DCF);
  overflow: hidden;
  border: 10px solid #fff;
  border-bottom-width: 50px;
  box-shadow:
    2px 2px 8px #0006,
    4px 4px 25px #0008 inset;
  transform: rotate(-5deg);
}

.pixel {
  height: 17px;
  width: 17px;
  box-shadow: var(--shadow);
  transform: rotate(-5deg) translate(-10px, 22px);
  filter: drop-shadow(2px 2px 10px #0007);
}
<div class="avatar">
  <div class="pixel"></div>
</div>
const COLORS = {
  0: "transparent",
  1: "#000",
  2: "#fff",
  3: "#ffcc80",
  4: "#cc984f",
  5: "#1a1a1a",
  6: "#ebb267",
  7: "#0d2061",
  8: "#17ffff",
  9: "#cc2554",
  10: "#e65100"
}

const PIXEL_ART = [
  0,0,0,0,2,2,2,2,2,2,2,2,0,0,0,0,
  0,0,0,2,2,1,1,1,1,1,1,2,2,2,0,0,
  0,0,2,2,1,1,1,1,1,1,1,1,1,2,0,0,
  0,0,2,1,1,1,4,4,4,4,5,1,1,2,0,0,
  0,0,2,1,1,5,3,3,3,3,6,6,2,2,0,0,
  0,0,2,1,5,3,3,1,3,3,1,3,2,0,0,0,
  0,0,2,1,5,3,3,1,3,3,1,3,2,0,0,0,
  0,0,2,1,1,3,3,3,6,6,6,3,2,0,0,0,
  0,0,2,1,1,4,3,3,3,3,3,3,2,0,0,0,
  0,0,2,2,1,1,4,4,4,1,1,3,2,0,0,0,
  0,0,0,2,2,1,1,1,4,4,1,4,2,0,0,0,
  0,0,2,2,1,5,1,1,1,1,1,1,2,0,0,0,
  0,0,2,1,5,1,1,1,1,1,1,1,2,0,0,0,
  0,0,2,1,5,1,1,1,8,1,1,5,2,0,0,0,
  0,0,2,5,1,1,1,9,7,7,1,5,2,0,0,0,
  0,0,2,4,4,1,1,7,10,8,1,5,2,0,0,0
];

const boxShadow = PIXEL_ART.map((pixel, index) => {
  const x = 16 * (index % 16);
  const y = 16 * ~~(index / 16);
  return `${x}px ${y}px ${COLORS[pixel]}`;
}).join(",\n");

const avatar = document.querySelector(".avatar");
avatar.style.setProperty("--shadow", boxShadow);

A grandes rasgos, hemos hecho lo siguiente:

  • 1️⃣ La constante COLORS es la paleta de colores (cada color es un número).
  • 2️⃣ La constante PIXEL_ART es el lienzo y los colores que se usan.
  • 3️⃣ En las siguientes líneas, recorremos el array PIXEL_ART para crear los valores de la propiedad box-shadow de CSS, de forma automática.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev