border-image y el corte en nueve trozos
Cómo se trocea una imagen en nueve piezas, qué unidades acepta el slice y por qué no llevan unidad, los cuatro modos de repetición, y el borde de degradado con su gran defecto.
border-image viene del nine-slice scaling de los motores de videojuegos: cortar una imagen en nueve trozos, estirar los del medio y dejar las esquinas intactas. Es la propiedad menos usada de la familia de fondos y la que resuelve un problema que ninguna otra resuelve, con un defecto tan visible que decide por sí solo cuándo puedes usarla.
- Explicar el corte en nueve y qué hace cada trozo.
- Escribir
border-image-slicecon sus unidades implícitas y la palabrafill. - Distinguir los cuatro modos de repetición y elegir el correcto.
- Reconocer el defecto del borde de degradado y sus dos alternativas.
El corte en nueve
La imagen de origen se corta con cuatro líneas —dos horizontales y dos verticales— en nueve regiones: cuatro esquinas, cuatro lados y un centro.
Las cuatro esquinas se colocan en las esquinas del área de borde y no se escalan nunca. Los cuatro lados se estiran o se repiten a lo largo de su borde. El centro se descarta salvo que pidas lo contrario.
Ese reparto es lo que permite que un marco decorativo funcione a cualquier tamaño sin que las esquinas se deformen, que es exactamente lo que un background-size no puede hacer.
Las propiedades son cinco:
| Propiedad | Qué controla |
|---|---|
border-image-source |
La imagen o el degradado |
border-image-slice |
Dónde van las cuatro líneas de corte |
border-image-width |
El grosor con el que se dibuja cada banda |
border-image-outset |
Cuánto sobresale respecto a la caja de borde |
border-image-repeat |
Cómo se rellenan los lados |
Y la abreviada las acepta todas:
.marco {
border: 24px solid transparent;
border-image: url(marco.png) 32 / 24px / 0 round;
}
Las dos barras separan slice / width / outset. El orden importa y las tres son opcionales.
El slice y sus unidades ausentes
border-image-slice es la propiedad más peculiar de CSS por una razón: sus números no llevan unidad y no son adimensionales.
border-image-slice: 32; /* 32 pixeles de la imagen de origen */
border-image-slice: 30%; /* 30% del tamano de la imagen de origen */
border-image-slice: 32 20; /* horizontal y vertical distintos */
border-image-slice: 32 fill; /* conserva el trozo central */
Un número suelto significa píxeles de la imagen de origen para un mapa de bits, o unidades del sistema de coordenadas para un SVG. No son píxeles CSS y no escalan con nada: describen dónde cortar el original, no dónde dibujar el resultado.
Los porcentajes se resuelven contra el tamaño de la imagen: horizontales contra su ancho, verticales contra su alto.
La palabra fill conserva el trozo central y lo pinta sobre el área de relleno, estirado o repetido como los lados. Sin fill, el centro se descarta y ahí se ve el fondo normal del elemento. Con marcos decorativos casi nunca lo quieres; con un globo de diálogo o una caja con textura sí.
border-image-width es independiente del slice y por defecto vale 1, que significa una vez el border-width. Los números sin unidad de esta propiedad son multiplicadores de border-width; también acepta longitudes, porcentajes y auto.
Y una condición que se olvida siempre: si border-style es none, border-width computa a cero y no hay área de borde donde dibujar. Por eso los ejemplos declaran border: 24px solid transparent: el color no se verá porque la imagen lo tapa, pero el estilo y el grosor son necesarios para que exista el área.
Los cuatro modos de repetición
border-image-repeat gobierna qué se hace con los lados cuando su longitud no es múltiplo del trozo:
| Valor | Comportamiento |
|---|---|
stretch |
Un solo trozo estirado a lo largo del lado. Es el inicial |
repeat |
Se repite el trozo y se corta el último |
round |
Se repite y se escala para que quepa un número entero |
space |
Se repite un número entero y se reparte el hueco entre las copias |
stretch deforma cualquier motivo que no sea liso. repeat corta el motivo por la mitad en los extremos, lo cual se ve mal casi siempre. round es el que quieres para un patrón reconocible, porque nunca corta y la deformación es pequeña. space es el más fiel al original y deja huecos regulares.
Acepta un valor por eje: border-image-repeat: round stretch redondea en horizontal y estira en vertical.
El borde de degradado y su defecto
El uso más popular de esta propiedad no tiene nada que ver con marcos: es pintar el borde con un degradado.
.borde-degradado {
border: 2px solid transparent;
border-image: linear-gradient(in oklch to right, #89b4fa, #f38ba8) 1;
}
El 1 es el slice, y con un degradado sin dimensiones intrínsecas significa “corta al 100%”, con lo que cada lado recibe la parte del degradado que le corresponde.
Y aquí está el defecto, que es grande: border-image no respeta border-radius. Se dibuja siempre sobre un rectángulo. Un botón redondeado con borde de degradado se ve con las esquinas cuadradas y el fondo redondeado, que es peor que no tener el borde.
Hay dos alternativas y las dos son mejores en cuanto hay esquinas redondeadas.
Fondo doble con recorte distinto, que aprovecha las dos cajas del fondo:
.borde-degradado-2 {
--grosor: 2px;
border: var(--grosor) solid transparent;
border-radius: 12px;
background:
linear-gradient(in oklab, #1e1e2e, #1e1e2e) padding-box,
linear-gradient(in oklch to right, #89b4fa, #f38ba8) border-box;
}
La primera capa, el fondo real, se recorta a la caja de relleno; la segunda, el degradado, llega hasta la caja de borde. Como el borde es transparente, se ve el degradado a través de él. Sigue el radio perfectamente y es la solución por defecto.
Máscara con mask-composite, cuando el borde tiene que ser semitransparente y el fondo también, caso en el que el truco anterior no vale porque las dos capas se superponen. Ahí se pinta el degradado en un pseudoelemento y se recorta un anillo con dos máscaras.
Con esquinas rectas y un motivo que no puede deformarse. Un marco de sello, una cinta con textura, un separador con un patrón que tiene que empezar y acabar bien. En esos casos el corte en nueve es insustituible: ninguna combinación de capas de fondo mantiene las esquinas sin escalar mientras estira los lados.
La confusión que hace que border-image parezca arbitraria se disuelve en cuanto ves que sus dos propiedades de tamaño hablan de espacios distintos. border-image-slice es una operación sobre la imagen de origen: dice dónde poner las tijeras en el archivo, y por eso sus números están en el sistema de coordenadas del archivo y no llevan unidad, porque una unidad CSS ahí no significaría nada. border-image-width es una operación sobre el destino: dice de qué grosor se dibuja cada banda en la página, y por eso sus números sin unidad son múltiplos de border-width, que es una medida de la página. Entre las dos hay un factor de escala implícito, y controlarlo es lo que la propiedad te ofrece de verdad. Si cortas a 32 y dibujas a 24 píxeles, las esquinas se ven al 75% de su tamaño original; si cortas a 32 y dibujas a 64, al 200% y se ven pixeladas. La forma de conseguir que un marco de mapa de bits se vea nítido es hacer que ese factor sea 1 o un entero, es decir cortar exactamente donde el diseño tiene sus esquinas y dibujar con ese mismo grosor, teniendo además en cuenta la densidad de la pantalla. Y de ese mismo desacoplamiento sale el uso avanzado que casi nadie conoce: border-image-width puede ser mayor que border-width, con lo que la imagen se dibuja más gruesa que el área de borde y se mete sobre el relleno sin desplazar el contenido; combinado con border-image-outset, que la saca hacia fuera de la caja, tienes un marco decorativo que ocupa espacio visual pero no ocupa espacio de layout. Eso no lo hace ninguna otra propiedad de CSS: un box-shadow tampoco ocupa layout, pero no puede llevar un motivo; un pseudoelemento posicionado sí puede, pero necesita marcado y un contexto de posicionamiento. Aquí está gratis.
- Coge una imagen con esquinas decoradas y ajusta el slice hasta que las esquinas queden completas.
- Compara los cuatro modos de repetición en un lado cuya longitud no sea múltiplo del trozo.
- Haz un borde de degradado con
border-imagey añádeleborder-radiuspara ver el defecto. - Reescríbelo con la técnica de fondo doble y comprueba que sigue el radio.
- Usa
border-image-outsetpara sacar un marco fuera de la caja sin mover el contenido.