Saltar al contenido

Qué propiedades SVG viven en CSS

El inventario real de propiedades de pintura, trazo, texto y geometría que se pueden escribir desde una hoja de estilos, y la trampa de transform-box en las transformaciones.

Pintura y trazo

Este es el bloque grande y el que se usa a diario. Todas son propiedades CSS de pleno derecho, todas se heredan salvo donde se indique, y todas admiten var(), transition y @media.

Propiedad Valores Nota
fill color, url(#id), none, currentColor Hereda
fill-opacity 0 a 1, porcentaje Hereda
fill-rule nonzero | evenodd Hereda
stroke igual que fill Hereda
stroke-width longitud, porcentaje Hereda
stroke-opacity 0 a 1 Hereda
stroke-linecap butt | round | square Hereda
stroke-linejoin miter | round | bevel Hereda
stroke-miterlimit número, mínimo 1 Hereda, inicial 4
stroke-dasharray lista de longitudes, none Hereda
stroke-dashoffset longitud Hereda
paint-order permutación de fill stroke markers Hereda
vector-effect none | non-scaling-stroke No hereda
marker-start url(#id) | none Hereda
marker-mid url(#id) | none Hereda
marker-end url(#id) | none Hereda
color-interpolation-filters sRGB | linearRGB Hereda, decisiva en filtros
shape-rendering auto | optimizeSpeed | crispEdges | geometricPrecision Hereda

Tres apuntes prácticos sobre esta tabla.

stroke-dasharray acepta una lista con espacios o comas, y si la longitud de la lista es impar se duplica: stroke-dasharray: 5 equivale a 5 5, y 5 3 2 equivale a 5 3 2 5 3 2. Es una regla heredada de PostScript que sorprende la primera vez.

vector-effect: non-scaling-stroke es la propiedad que hace posible una rejilla de gráfico que no engorde al escalar el viewBox. No se hereda, así que hay que ponerla en cada elemento o usar un selector.

color-interpolation-filters no parece de este bloque y es la propiedad más importante que existe para los filtros, porque su valor inicial es linearRGB y eso hace que todo filtro escrito sin pensar salga con un aspecto distinto del esperado. Se trata en el nivel 22.

Texto y disposición

Propiedad Nota
text-anchor start | middle | end, hereda
dominant-baseline La línea base a la que se alinea, hereda
alignment-baseline Sobre un tspan respecto a su padre
letter-spacing, word-spacing Las mismas de CSS, funcionan
font-* completo font-family, font-size, font-weight, etc.
writing-mode Vertical, con soporte desigual en SVG
direction, unicode-bidi Texto de derecha a izquierda

Y las de composición y efectos, que no heredan ninguna: opacity, clip-path, clip-rule (esta sí hereda), mask, filter, mix-blend-mode, isolation, display, visibility, pointer-events, cursor, overflow.

Las de gradientes y filtros: stop-color, stop-opacity, flood-color, flood-opacity, lighting-color. Todas son propiedades, lo que significa que puedes tematizar un gradiente desde CSS sin tocar el marcado, y eso es más útil de lo que parece.

CSS
:root { --acento: #89b4fa; }[data-tema="calido"] { --acento: #fab387; }#gradiente stop:first-child { stop-color: var(--acento); }#gradiente stop:last-child  { stop-color: transparent; }

Lo que nunca ha sido una propiedad

Esta lista es igual de importante y más corta:

  • viewBox, preserveAspectRatio
  • d (en los motores donde existe como propiedad, no está en los tres; no dependas de ello)
  • points
  • x1, y1, x2, y2 de un gradiente; cx, cy, r, fx, fy, fr de un radial
  • gradientUnits, gradientTransform, spreadMethod
  • patternUnits, patternContentUnits, patternTransform
  • clipPathUnits, maskUnits, maskContentUnits
  • filterUnits, primitiveUnits, y todos los atributos de las primitivas (stdDeviation, in, result, values…)
  • refX, refY, markerWidth, markerHeight, orient, markerUnits
  • offset de un stop
  • href, startOffset, textLength, lengthAdjust

Si tu tema necesita cambiar cualquiera de estos, la respuesta no es CSS: es generar marcado distinto o escribir el atributo desde JavaScript. Conviene saberlo antes de diseñar el sistema, no después.

Las propiedades de geometría

SVG 2 promovió a propiedades CSS los atributos geométricos de las formas: cx, cy, r, rx, ry, x, y, width, height. Con ellas puedes escribir esto:

CSS
.punto { r: 4; transition: r 150ms ease; }.punto:hover { r: 7; }

Es una mejora real: una transición de radio sin JavaScript, con el interpolador del navegador. Firefox fue el último motor en implementarlas y hoy están disponibles en los tres, pero conviene tenerlo presente si tu matriz de soporte incluye versiones antiguas; la degradación es benigna, porque el atributo sigue funcionando y solo se pierde la transición.

Dos límites que no son de soporte sino de diseño. El primero: solo se aplican a los elementos que tienen esos atributos. Un path no tiene width. El segundo: cuando el valor viene de datos, sigue haciendo falta escribir el atributo desde JavaScript, así que las propiedades de geometría son para estados de interacción, no para el dato en sí.

transform, y el origen que no está donde crees

transform es una propiedad CSS y funciona sobre elementos SVG. También lo son translate, rotate y scale como propiedades independientes. Y aquí está la trampa que cuesta más tiempo de todo el nivel.

En HTML, transform-origin: 50% 50% significa el centro del propio elemento, porque transform-box vale border-box para las cajas. En SVG, el valor inicial de transform-box es view-box, es decir, el sistema de coordenadas del viewport SVG. Un transform-origin: 50% 50% sobre un circle no es el centro del círculo: es el centro del lienzo entero.

HTML
<svg viewBox="0 0 200 100" width="400">  <rect class="mal"  x="20"  y="30" width="50" height="40" fill="#f38ba8" />  <rect class="bien" x="120" y="30" width="50" height="40" fill="#a6e3a1" /></svg>
CSS
.mal, .bien {  transform-origin: 50% 50%;  animation: girar 3s linear infinite;}/* La correccion: que el origen sea la caja del propio elemento */.bien { transform-box: fill-box; }@keyframes girar { to { transform: rotate(360deg); } }

El rojo describe una órbita alrededor del centro del lienzo. El verde gira sobre sí mismo. La única diferencia es transform-box: fill-box.