Bandas duras, repeticiones y degradados usados como patrón
Cómo se dibujan rayas, dameros y cuadrículas con la sintaxis de doble parada, qué unidad marca el periodo de un repeating, y dónde están sus límites reales.
Un degradado con todas sus transiciones de longitud cero deja de ser un degradado y pasa a ser un dibujo vectorial de bandas. Sobre esa idea se construye la mitad de los patrones de fondo que ves en la web sin una sola imagen: rayas, dameros, cuadrículas, papel milimetrado, cintas de aviso. Cuesta menos que un SVG, escala sin pérdida y se parametriza con custom properties.
- Dibujar bandas duras con la sintaxis de doble parada.
- Componer patrones bidimensionales apilando capas de fondo.
- Controlar el periodo de un
repeating-y saber cuándo usarbackground-sizeen su lugar. - Reconocer los tres límites de esta técnica.
La parada doble
Una transición de longitud cero se consigue poniendo dos paradas en la misma posición. La sintaxis de doble posición lo escribe de forma legible:
.rayas {
background: linear-gradient(
90deg,
#89b4fa 0 20px,
#cba6f7 20px 40px
);
background-size: 40px 100%;
}
#89b4fa 0 20px declara dos paradas azules, una en 0 y otra en 20px. #cba6f7 20px 40px hace lo mismo con el morado. Entre las dos hay un salto de color en una distancia de cero, es decir un borde duro.
Fíjate en que aquí el degradado no se repite solo: lo que se repite es la imagen de 40 píxeles de ancha, gracias a background-size y a que background-repeat vale repeat por defecto. Esa es una de las dos formas de conseguir un patrón, y suele ser la más manejable.
La otra forma: repeating
La alternativa es que el propio degradado se repita:
.rayas-2 {
background: repeating-linear-gradient(
90deg,
#89b4fa 0 20px,
#cba6f7 20px 40px
);
}
Un repeating- toma la lista de paradas, calcula el intervalo entre la primera y la última, y lo repite indefinidamente. El periodo es la distancia entre la primera y la última parada, no el tamaño de la caja.
Las dos versiones se ven igual y no son equivalentes. La diferencia práctica:
background-size |
repeating- |
|
|---|---|---|
| Periodo | El tamaño de la imagen | La distancia entre paradas |
| Última parada en porcentaje | Se resuelve contra el tamaño de la imagen | Se resuelve contra el degradado, y no se repite bien |
Combina con background-position |
Sí, mueve el patrón | Sí |
| Rayas diagonales | Hay que calcular el tamaño a mano | Sale directo |
La regla que funciona: para rayas rectas usa background-size, para rayas diagonales usa repeating-. El motivo es que en diagonal el tamaño de mosaico que hace que las rayas cuadren no es el ancho de la raya sino su proyección, y calcularlo a mano es una trigonometría innecesaria cuando repeating-linear-gradient ya lo resuelve sobre la línea del degradado.
repeating-linear-gradient(90deg, red 0 10%, blue 10% 20%) produce cinco repeticiones porque el 20% del ancho de la caja se repite cinco veces. Cambia el ancho y sigue habiendo cinco: el patrón se estira en vez de repetirse más. Si querías rayas de tamaño fijo, usa longitudes.
Patrones bidimensionales
Un solo degradado da bandas en una dirección. Para un patrón en dos dimensiones se apilan capas, y ahí es donde background se vuelve un lenguaje de dibujo.
Una cuadrícula son dos capas de rayas finas, una en cada eje, sobre un fondo:
.cuadricula {
--paso: 24px;
--linea: color-mix(in oklab, CanvasText 12%, transparent);
background-image:
linear-gradient(90deg, var(--linea) 0 1px, transparent 1px),
linear-gradient( var(--linea) 0 1px, transparent 1px);
background-size: var(--paso) var(--paso);
}
Un damero son dos degradados diagonales desplazados medio mosaico:
.damero {
--paso: 32px;
--a: #313244;
--b: #45475a;
background-color: var(--a);
background-image:
linear-gradient(45deg, var(--b) 25%, transparent 25% 75%, var(--b) 75%),
linear-gradient(45deg, var(--b) 25%, transparent 25% 75%, var(--b) 75%);
background-size: var(--paso) var(--paso);
background-position: 0 0, calc(var(--paso) / 2) calc(var(--paso) / 2);
}
Puntos son un radial con parada dura:
.puntos {
--paso: 20px;
background-image: radial-gradient(
circle at center,
color-mix(in oklab, CanvasText 20%, transparent) 0 2px,
transparent 2px
);
background-size: var(--paso) var(--paso);
}
Una cinta de aviso son rayas diagonales con repeating-:
.cinta {
background: repeating-linear-gradient(
45deg,
#f9e2af 0 12px,
#11111b 12px 24px
);
}
Los cuatro comparten la misma estructura: un degradado con paradas duras, un tamaño de mosaico, y opcionalmente una posición para desplazar. Parametrizando el paso y los colores con custom properties, un patrón se convierte en un componente reutilizable.
Los tres límites
No hay antialiasing en el borde duro. Una transición de longitud cero produce un salto que el rasterizador no suaviza igual que suavizaría un trazo vectorial. En bordes horizontales y verticales no se nota; en diagonales sí, y las rayas a 45 grados salen ligeramente dentadas en algunas combinaciones de tamaño y densidad de píxel. Si el borde tiene que verse perfecto, deja un píxel de transición: red 0 20px, blue 21px en lugar de blue 20px.
El coste crece con el número de capas. Cada capa de background-image es una imagen que hay que rasterizar y componer. Cuatro o cinco capas en un elemento grande y a pantalla completa se notan en el tiempo de pintado, sobre todo si el elemento cambia de tamaño.
No hay forma de que el patrón dependa de la posición del contenido. Un degradado se ancla al área de fondo del elemento, punto. Cualquier patrón que tenga que alinearse con algo que hay dentro necesita que ese algo tenga tamaño conocido, o no se alinea.
Hay un fallo de una sutileza desproporcionada que aparece en toda cuadrícula dibujada con degradados y que casi nadie diagnostica bien: las líneas se ven grises, borrosas y de grosor desigual aunque el CSS diga 0 1px. La causa es que el degradado se rasteriza en la rejilla del dispositivo, no en la de CSS, y esas dos rejillas casi nunca están alineadas. Si el paso de la cuadrícula es de 24 píxeles CSS y el factor de escala del dispositivo es 1.5, cada línea cae cada 36 píxeles físicos, que sí es entero; pero con un factor de 1.25 cae cada 30, y con un elemento desplazado por un transform con decimales, o dentro de un contenedor cuyo ancho no es entero, las líneas caen en posiciones fraccionarias. Un borde duro que cae a mitad de píxel físico se reparte entre dos píxeles al 50% cada uno, y lo que ves es dos líneas del doble de anchas y la mitad de opacas, es decir gris borroso. Alternando líneas nítidas y líneas borrosas según dónde caiga cada una, aparece además un patrón de interferencia a baja frecuencia: la cuadrícula parece tener zonas más oscuras que otras. Las tres defensas, en orden de eficacia. Usa pasos que sean múltiplos de los factores de escala habituales —16, 20, 24, 32 funcionan bien con 1, 1.5, 2 y 3—, evitando números primos y decimales. No pongas el patrón en un elemento transformado con desplazamientos fraccionarios, porque el transform se aplica después de rasterizar y arrastra la rejilla entera. Y si aun así hace falta que se vea impecable a cualquier escala, acepta un píxel de transición en cada borde: la línea deja de ser un salto duro y pasa a ser un trapecio de un píxel de rampa, con lo que el rasterizador tiene margen para colocarla sin partirla, y la degradación es suave en lugar de a saltos. Es la misma lógica por la que un borde de un píxel se dibuja mejor con box-shadow: inset 0 0 0 1px que con un degradado: cuanto más control le des al rasterizador sobre el reparto subpíxel, mejor lo hace.
- Dibuja rayas verticales de 20 píxeles con
background-sizey conrepeating-y compara el código. - Cambia el ancho del contenedor y comprueba cuál de los dos mantiene el tamaño de raya.
- Haz un damero parametrizado con dos custom properties de color y una de paso.
- Pon una cuadrícula de 24 píxeles y busca las líneas borrosas cambiando el zoom del navegador.
- Aplica el píxel de transición y vuelve a mirar al mismo zoom.