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.
: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,preserveAspectRatiod(en los motores donde existe como propiedad, no está en los tres; no dependas de ello)pointsx1,y1,x2,y2de un gradiente;cx,cy,r,fx,fy,frde un radialgradientUnits,gradientTransform,spreadMethodpatternUnits,patternContentUnits,patternTransformclipPathUnits,maskUnits,maskContentUnitsfilterUnits,primitiveUnits, y todos los atributos de las primitivas (stdDeviation,in,result,values…)refX,refY,markerWidth,markerHeight,orient,markerUnitsoffsetde unstophref,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:
.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.
<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>.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.