Fondos y degradados
Lección 16 de 37 · 6 min
Un degradado es una imagen que el navegador dibuja: no pesa nada, se adapta a cualquier tamaño y se apila con otras capas. Con eso alcanza para rayados, cuadrículas, gráficos de torta y texto pintado.
Degradados lineales
linear-gradient() devuelve una imagen, así que va en background-image, no en background-color. Primero la dirección, después las paradas de color. La dirección es un ángulo (0deg apunta arriba y gira como un reloj) o una palabra clave como to right; si falta, vale to bottom.
.banda {background-image:linear-gradient(to right, oklch(0.55 0.2 262), oklch(0.88 0.17 92));}.diagonal {background-image:linear-gradient(135deg, oklch(0.55 0.2 262), oklch(0.88 0.17 92));}
El degradado recorre la línea del degradado, que pasa por el centro de la caja. Su largo no es el ancho ni el alto: termina donde una perpendicular toca la esquina más lejana, así los colores de las puntas caen justo en las esquinas. Por eso, en una caja rectangular, la línea de 45° es más larga que el lado.
Cada parada puede llevar una posición. Si dos paradas comparten la misma, no hay mezcla: el color cambia de golpe (un corte duro). Una parada también acepta dos posiciones, que pintan una franja sólida: azul 0 50% es lo mismo que azul 0, azul 50%.
Mové el ángulo y mirá la línea naranja: la flecha es la dirección, las marcas son las paradas y las punteadas muestran hasta qué esquina llega.
Muestra pintada con un degradado linear, de azul a amarillo, mezclado en srgb.
.muestra {/* sin soporte de `in`: mezcla en srgb */background-image: linear-gradient(135deg, oklch(0.55 0.2 262), oklch(0.88 0.17 92));background-image: linear-gradient(135deg in srgb, oklch(0.55 0.2 262), oklch(0.88 0.17 92));}
<div class="bg-linear-135/srgb from-[oklch(0.55_0.2_262)] to-[oklch(0.88_0.17_92)]"></div>
Radiales y cónicos
radial-gradient() sale desde un punto hacia afuera. Acepta forma (circle o ellipse, que es la de por defecto), tamaño y centro con at. El tamaño por defecto es farthest-corner: el último color llega a la esquina más lejana. También existen closest-side, closest-corner y farthest-side, o un largo fijo.
conic-gradient() gira alrededor del centro, como las agujas de un reloj. from dice dónde arranca y las paradas van en grados o porcentajes de la vuelta. Con cortes duros es un gráfico de torta sin una línea de JavaScript.
.foco {background-image:radial-gradient(circle at 30% 20%, oklch(0.95 0.05 90), transparent 60%);}/* 45% · 30% · 25%: cada parada empieza donde termina la anterior */.torta {border-radius: 50%;background-image: conic-gradient(oklch(0.6 0.18 262) 0 45%,oklch(0.75 0.15 160) 45% 75%,oklch(0.85 0.15 90) 75% 100%);}
En qué espacio se mezclan
Entre dos paradas el navegador interpola, y el resultado depende del espacio de color. En srgb, azul y amarillo se cruzan en un gris apagado. En oklab el medio mantiene la luminosidad pareja. En oklch el tono gira por el círculo cromático y pasa por el verde. Se elige con in, pegado a la dirección: linear-gradient(90deg in oklch, …).
Si no ponés in, los colores clásicos (hex, rgb(), hsl()) se mezclan en srgb, como siempre; cuando aparece alguno moderno, como oklch(), la especificación manda mezclar en oklab. En oklch también podés elegir el camino del tono: in oklch longer hue da la vuelta larga por el círculo.
La sintaxis in es Baseline desde junio de 2024 (Chrome 111, Safari 16.2, Firefox 127). Un navegador más viejo descarta la declaración entera, así que conviene escribir antes una versión sin in: el que no entiende la segunda se queda con la primera.
Degradados que se repiten
repeating-linear-gradient(), repeating-radial-gradient() y repeating-conic-gradient() repiten las paradas hasta llenar la caja. Las posiciones van en largos fijos (o grados), no en porcentajes del total. Con cortes duros salen rayas; con paradas suaves, ondas.
/* cinta de obra: franjas de 12px a 45° */.cinta {background-image: repeating-linear-gradient(45deg,oklch(0.85 0.17 90) 0 12px,oklch(0.25 0 0) 12px 24px);}
Varias capas
background-image acepta una lista separada por comas. La primera capa queda arriba y la última abajo, y debajo de todas va background-color. Cada propiedad de fondo también acepta una lista, y el valor en la posición 1 va con la capa 1. Si una lista es más corta, se repite.
- Tamaño
background-sizeEl tamaño de un mosaico.24px 24pxes una baldosa;coverycontainescalan una imagen a la caja. - Posición
background-positionDónde arranca el mosaico, comocenteroright 8px bottom 8px. - Repetición
background-repeatrepeat,no-repeat,repeat-x, y tambiénspaceyround, que ajustan para que no quede un mosaico cortado. - Anclaje
background-attachmentConscroll(por defecto) el fondo queda fijo a la caja; conlocalse mueve con el contenido que se desplaza adentro; confixedqueda fijo a la ventana.
La hoja de abajo no tiene ninguna imagen: los renglones son un degradado con un corte duro de 1px, repetido según el background-size, y el margen es otra capa encima. Desplazá la hoja con local y después con scroll: con local el texto sigue apoyado en sus renglones; con scroll los renglones se quedan quietos y el texto se les corre encima.
Medialunas
500 g de harina
250 g de manteca fría
2 huevos y un poco de leche
Almíbar para pintar
Horno a 200°, 15 minutos
Estirar y cortar en triángulos.
Enrollar desde la base.
Leudar una hora, tapadas.
Pintar apenas salen del horno.
- margen
- renglones
- color del papel
.hoja {--papel: oklch(0.985 0.012 95);--renglon: oklch(0.8 0.06 245);--margen: oklch(0.66 0.17 25);height: 232px;overflow-y: auto;padding: 24px 16px 0 52px;line-height: 24px;background-color: var(--papel);background-image:linear-gradient(to right, transparent 39px, var(--margen) 39px 40px, transparent 40px),linear-gradient(to bottom, transparent calc(100% - 1px), var(--renglon) 0);background-size: auto, 100% 24px;background-repeat: no-repeat, repeat;background-attachment: local;}@media (prefers-color-scheme: dark) {.hoja {--papel: oklch(0.26 0.01 250);--renglon: oklch(0.42 0.05 245);--margen: oklch(0.6 0.15 25);}}
<div class="[--papel:oklch(0.985_0.012_95)] [--renglon:oklch(0.8_0.06_245)] [--margen:oklch(0.66_0.17_25)] dark:[--papel:oklch(0.26_0.01_250)] dark:[--renglon:oklch(0.42_0.05_245)] dark:[--margen:oklch(0.6_0.15_25)] h-58 overflow-y-auto pt-[24px] pr-4 pl-13 leading-[24px] bg-(--papel) bg-[image:linear-gradient(to_right,transparent_39px,var(--margen)_39px_40px,transparent_40px),linear-gradient(to_bottom,transparent_calc(100%_-_1px),var(--renglon)_0)] bg-size-[auto,100%_24px] bg-[repeat:no-repeat,repeat] bg-local">…</div>
El atajo background junta todo en una capa por coma, con el tamaño después de la posición y una barra: background: url(papel.webp) center / cover no-repeat, oklch(0.98 0.01 95). El color solo puede ir en la última capa. local funciona en los navegadores principales; fixed todavía no funciona bien en Safari de iOS.
Hasta dónde llega el fondo
Dos propiedades parecidas que hacen cosas distintas. background-origin dice desde qué caja se posiciona y mide el fondo (por defecto, padding-box). background-clip dice hasta dónde se pinta (por defecto, border-box, o sea también debajo del borde).
Con background-clip: text el fondo se pinta solo dentro de las letras. Para verlo, el color del texto tiene que ser transparente. Si el navegador no lo entiende, ese color: transparent dejaría el texto invisible, así que va dentro de @supports y afuera queda un color sólido de respaldo. Probá cada valor de background-clip y cambiá el origen: la línea naranja marca hasta dónde se pinta el fondo.
La palabra Otoño sobre un degradado que se pinta hasta el border-box y se mide desde el padding-box.
.apertura {--desde: oklch(0.6 0.2 40);--hasta: oklch(0.42 0.2 300);padding: 16px;border: 12px dashed oklch(0.5 0 0 / 35%);border-radius: 8px;font-size: 56px;color: oklch(0.99 0 0);background-image: linear-gradient(135deg in oklch, var(--desde), var(--hasta));background-origin: padding-box;background-clip: border-box;}@media (prefers-color-scheme: dark) {.apertura {--desde: oklch(0.82 0.14 65);--hasta: oklch(0.74 0.16 320);color: oklch(0.2 0 0);}}
<h2 class="p-4 border-12 border-dashed border-neutral-500/35 rounded-lg text-[56px] bg-linear-135/oklch from-[oklch(0.6_0.2_40)] to-[oklch(0.42_0.2_300)] dark:from-[oklch(0.82_0.14_65)] dark:to-[oklch(0.74_0.16_320)] bg-origin-padding bg-clip-border text-[oklch(0.99_0_0)] dark:text-[oklch(0.2_0_0)]">Otoño</h2>
text sin prefijo llegó a Chrome en la versión 120 y a Safari en la 14; antes solo andaba -webkit-background-clip: text, que muchos todavía agregan por las dudas. Firefox lo soporta con limitaciones, así que no es Baseline: dejá siempre un color legible de respaldo.
En Tailwind
Tailwind arma los degradados con una clase de dirección y las paradas con from-*, via-* y to-*. El espacio de mezcla va como modificador después de la barra; sin modificador, Tailwind usa oklab. Repetidos y varias capas no tienen clase: van entre corchetes, como bg-[repeating-linear-gradient(45deg,…)].
| CSS | Tailwind |
|---|---|
| linear-gradient(135deg in oklch, …) | bg-linear-135/oklch |
| radial-gradient(at 30% 20%, …) | bg-radial-[at_30%_20%] |
| conic-gradient(from 90deg, …) | bg-conic-90 |
| paradas con corte duro | from-50% to-50% |
| background-size · attachment | bg-size-[24px_24px] · bg-local |
| background-clip: text | bg-clip-text |
<!-- texto con degradado y color de respaldo si no hay soporte --><h2 class="bg-linear-135/oklchfrom-[oklch(0.6_0.2_40)] to-[oklch(0.42_0.2_300)]bg-clip-text text-[oklch(0.42_0.2_300)]supports-[background-clip:text]:text-transparent">Otoño</h2>
Backgrounds and gradients
Lesson 16 of 37 · 5 min
A gradient is an image the browser draws: it weighs nothing, fits any size and stacks with other layers. That’s enough for stripes, grids, pie charts and painted text.
Linear gradients
linear-gradient() returns an image, so it goes in background-image, not background-color. Direction first, then the colour stops. The direction is an angle (0deg points up and turns clockwise) or a keyword like to right; without one, it’s to bottom.
.band {background-image:linear-gradient(to right, oklch(0.55 0.2 262), oklch(0.88 0.17 92));}.diagonal {background-image:linear-gradient(135deg, oklch(0.55 0.2 262), oklch(0.88 0.17 92));}
The colours run along the gradient line, through the centre of the box. Its length is neither the width nor the height: it ends where a perpendicular meets the farthest corner, so the end colours land exactly on the corners. That’s why, in a rectangular box, the 45° line is longer than the side.
Every stop can take a position. When two stops share one there’s no blend, the colour just switches (a hard stop). A stop also takes two positions to paint a solid band: blue 0 50% is the same as blue 0, blue 50%.
Move the angle and watch the orange line: the arrow is the direction, the ticks are the stops, and the dashed lines show which corner it reaches.
Swatch painted with a linear gradient from blue to yellow, mixed in srgb.
.swatch {/* no `in` support: mixes in srgb */background-image: linear-gradient(135deg, oklch(0.55 0.2 262), oklch(0.88 0.17 92));background-image: linear-gradient(135deg in srgb, oklch(0.55 0.2 262), oklch(0.88 0.17 92));}
<div class="bg-linear-135/srgb from-[oklch(0.55_0.2_262)] to-[oklch(0.88_0.17_92)]"></div>
Radial and conic
radial-gradient() spreads out from a point. It takes a shape (circle, or the default ellipse), a size and a centre with at. The default size is farthest-corner: the last colour reaches the farthest corner. There’s also closest-side, closest-corner and farthest-side, or a fixed length.
conic-gradient() sweeps around the centre like clock hands. from sets where it starts, and stops go in degrees or percentages of the turn. With hard stops it’s a pie chart with no JavaScript.
.spot {background-image:radial-gradient(circle at 30% 20%, oklch(0.95 0.05 90), transparent 60%);}/* 45% · 30% · 25%: each stop starts where the previous one ends */.pie {border-radius: 50%;background-image: conic-gradient(oklch(0.6 0.18 262) 0 45%,oklch(0.75 0.15 160) 45% 75%,oklch(0.85 0.15 90) 75% 100%);}
Which space they mix in
Between two stops the browser interpolates, and the result depends on the colour space. In srgb, blue and yellow meet in a dull grey. In oklab the middle keeps an even lightness. In oklch the hue travels round the colour wheel and passes through green. You pick it with in, right after the direction: linear-gradient(90deg in oklch, …).
Without in, legacy colours (hex, rgb(), hsl()) mix in srgb as they always did; once a modern one such as oklch() shows up, the spec says to mix in oklab. With oklch you can also choose the hue path: in oklch longer hue takes the long way round the wheel.
The in syntax has been Baseline since June 2024 (Chrome 111, Safari 16.2, Firefox 127). An older browser drops the whole declaration, so write a version without in first: a browser that can’t read the second one keeps the first.
Repeating gradients
repeating-linear-gradient(), repeating-radial-gradient() and repeating-conic-gradient() repeat their stops until the box is full. Positions are fixed lengths (or degrees), not percentages of the whole. Hard stops give stripes; soft ones give waves.
/* caution tape: 12px stripes at 45° */.tape {background-image: repeating-linear-gradient(45deg,oklch(0.85 0.17 90) 0 12px,oklch(0.25 0 0) 12px 24px);}
Several layers
background-image takes a comma-separated list. The first layer is on top and the last at the bottom, with background-color under them all. Every background property takes a list too, and value 1 goes with layer 1. A shorter list repeats.
- Size
background-sizeThe size of one tile.24px 24pxis a tile;coverandcontainscale an image to the box. - Position
background-positionWhere the tiling starts, such ascenterorright 8px bottom 8px. - Repeat
background-repeatrepeat,no-repeat,repeat-x, plusspaceandround, which adjust so no tile gets cut. - Attachment
background-attachmentWithscroll(the default) the background sticks to the box; withlocalit moves with the content scrolling inside; withfixedit sticks to the window.
The page below has no image at all: the lines are a gradient with a 1px hard stop, repeated by background-size, and the margin is another layer on top. Scroll the page with local and then with scroll: with local the text stays on its lines; with scroll the lines stay put and the text slides over them.
Croissants
500 g flour
250 g cold butter
2 eggs and a splash of milk
Syrup to glaze
Oven at 200°, 15 minutes
Roll out and cut into triangles.
Roll up from the base.
Let rise for an hour, covered.
Glaze as soon as they come out.
- margin
- lines
- paper color
.page {--paper: oklch(0.985 0.012 95);--rule: oklch(0.8 0.06 245);--margin: oklch(0.66 0.17 25);height: 232px;overflow-y: auto;padding: 24px 16px 0 52px;line-height: 24px;background-color: var(--paper);background-image:linear-gradient(to right, transparent 39px, var(--margin) 39px 40px, transparent 40px),linear-gradient(to bottom, transparent calc(100% - 1px), var(--rule) 0);background-size: auto, 100% 24px;background-repeat: no-repeat, repeat;background-attachment: local;}@media (prefers-color-scheme: dark) {.page {--paper: oklch(0.26 0.01 250);--rule: oklch(0.42 0.05 245);--margin: oklch(0.6 0.15 25);}}
<div class="[--paper:oklch(0.985_0.012_95)] [--rule:oklch(0.8_0.06_245)] [--margin:oklch(0.66_0.17_25)] dark:[--paper:oklch(0.26_0.01_250)] dark:[--rule:oklch(0.42_0.05_245)] dark:[--margin:oklch(0.6_0.15_25)] h-58 overflow-y-auto pt-[24px] pr-4 pl-13 leading-[24px] bg-(--paper) bg-[image:linear-gradient(to_right,transparent_39px,var(--margin)_39px_40px,transparent_40px),linear-gradient(to_bottom,transparent_calc(100%_-_1px),var(--rule)_0)] bg-size-[auto,100%_24px] bg-[repeat:no-repeat,repeat] bg-local">…</div>
The background shorthand writes one layer per comma, with the size after the position and a slash: background: url(paper.webp) center / cover no-repeat, oklch(0.98 0.01 95). Only the last layer can hold the colour. local works in the major browsers; fixed still doesn’t work properly in Safari on iOS.
How far the background reaches
Two similar properties that do different things. background-origin sets the box the background is positioned and sized from (padding-box by default). background-clip sets where it’s painted up to (border-box by default, so under the border too).
With background-clip: text the background is painted only inside the letters. To see it, the text colour has to be transparent. A browser that doesn’t understand the clip would then show invisible text, so color: transparent goes inside @supports, with a solid fallback colour outside. Try each background-clip value and change the origin: the orange line marks where the background stops.
The word Autumn on a gradient painted up to the border-box and measured from the padding-box.
.opener {--from: oklch(0.6 0.2 40);--to: oklch(0.42 0.2 300);padding: 16px;border: 12px dashed oklch(0.5 0 0 / 35%);border-radius: 8px;font-size: 56px;color: oklch(0.99 0 0);background-image: linear-gradient(135deg in oklch, var(--from), var(--to));background-origin: padding-box;background-clip: border-box;}@media (prefers-color-scheme: dark) {.opener {--from: oklch(0.82 0.14 65);--to: oklch(0.74 0.16 320);color: oklch(0.2 0 0);}}
<h2 class="p-4 border-12 border-dashed border-neutral-500/35 rounded-lg text-[56px] bg-linear-135/oklch from-[oklch(0.6_0.2_40)] to-[oklch(0.42_0.2_300)] dark:from-[oklch(0.82_0.14_65)] dark:to-[oklch(0.74_0.16_320)] bg-origin-padding bg-clip-border text-[oklch(0.99_0_0)] dark:text-[oklch(0.2_0_0)]">Autumn</h2>
Unprefixed text reached Chrome in version 120 and Safari in 14; before that only -webkit-background-clip: text worked, and many people still add it just in case. Firefox supports it with limits, so it isn’t Baseline: always keep a readable fallback colour.
In Tailwind
Tailwind builds a gradient from a direction class and the stops in from-*, via-* and to-*. The mixing space is a modifier after the slash; without one, Tailwind uses oklab. Repeating gradients and several layers have no class: they go in brackets, as in bg-[repeating-linear-gradient(45deg,…)].
| CSS | Tailwind |
|---|---|
| linear-gradient(135deg in oklch, …) | bg-linear-135/oklch |
| radial-gradient(at 30% 20%, …) | bg-radial-[at_30%_20%] |
| conic-gradient(from 90deg, …) | bg-conic-90 |
| hard-stop positions | from-50% to-50% |
| background-size · attachment | bg-size-[24px_24px] · bg-local |
| background-clip: text | bg-clip-text |
<!-- gradient text, with a fallback colour where it isn’t supported --><h2 class="bg-linear-135/oklchfrom-[oklch(0.6_0.2_40)] to-[oklch(0.42_0.2_300)]bg-clip-text text-[oklch(0.42_0.2_300)]supports-[background-clip:text]:text-transparent">Autumn</h2>

