wandres.dev
FONDOS Y BORDES · Capas, repetición y radios

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.

⏱ 17 min

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.

🎯 Al terminar esta lección sabrás
  • Explicar el corte en nueve y qué hace cada trozo.
  • Escribir border-image-slice con sus unidades implícitas y la palabra fill.
  • 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.

💡
Cuándo sigue mereciendo la pena border-image

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.

El slice describe el origen y el width describe el destino, y ese desacoplamiento es todo el diseño de la propiedad

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.

⚔️ Corta en nueve
  1. Coge una imagen con esquinas decoradas y ajusta el slice hasta que las esquinas queden completas.
  2. Compara los cuatro modos de repetición en un lado cuya longitud no sea múltiplo del trozo.
  3. Haz un borde de degradado con border-image y añádele border-radius para ver el defecto.
  4. Reescríbelo con la técnica de fondo doble y comprueba que sigue el radio.
  5. Usa border-image-outset para sacar un marco fuera de la caja sin mover el contenido.