跳到主要内容

变换

SVG 变换允许你移动、旋转、缩放和倾斜图形元素。变换可以应用于单个元素或一组元素,是创建复杂图形和动画的基础。

变换基础

使用 transform 属性对元素应用变换。变换会创建一个新的坐标系统,元素在这个新坐标系统中渲染。

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="50" height="50" fill="#bdc3c7"/>
<rect x="10" y="10" width="50" height="50" fill="#3498db" transform="translate(100, 20)"/>
</svg>

平移 - translate

translate(tx, ty) 将元素沿 x 和 y 轴移动指定距离。

<svg width="300" height="100" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="50" height="50" fill="#e74c3c"/>
<rect x="10" y="10" width="50" height="50" fill="#3498db" transform="translate(80, 0)"/>
<rect x="10" y="10" width="50" height="50" fill="#2ecc71" transform="translate(160, 20)"/>
</svg>

如果省略 ty,则默认为 0。

理解变换的本质:变换不是移动元素本身,而是移动元素的坐标系统。元素仍然在"原来的位置"绘制,只是坐标系统变了。

旋转 - rotate

rotate(angle, cx, cy) 将元素围绕指定点旋转指定角度。角度以度为单位,正值表示顺时针旋转。

围绕原点旋转

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="50" height="50" fill="#e74c3c" opacity="0.3"/>
<rect x="50" y="50" width="50" height="50" fill="#e74c3c" transform="rotate(30)"/>
</svg>

当只指定角度时,元素围绕 SVG 原点 (0, 0) 旋转。

围绕指定点旋转

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="50" height="50" fill="#3498db" opacity="0.3"/>
<rect x="50" y="50" width="50" height="50" fill="#3498db" transform="rotate(45, 75, 75)"/>
<circle cx="75" cy="75" r="3" fill="#e74c3c"/>
</svg>

rotate(45, 75, 75) 表示围绕点 (75, 75) 旋转 45 度。这个点通常是元素的中心。

旋转示例

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(75, 75)">
<rect x="-25" y="-25" width="50" height="50" fill="#9b59b6" transform="rotate(0)"/>
</g>
<g transform="translate(150, 75)">
<rect x="-25" y="-25" width="50" height="50" fill="#9b59b6" transform="rotate(15)"/>
</g>
<g transform="translate(225, 75)">
<rect x="-25" y="-25" width="50" height="50" fill="#9b59b6" transform="rotate(30)"/>
</g>
</svg>

通过将元素中心放在原点,旋转后再平移到目标位置,可以简化围绕中心旋转的操作。

缩放 - scale

scale(sx, sy) 将元素沿 x 和 y 轴缩放指定比例。

统一缩放

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="20" width="50" height="50" fill="#e74c3c"/>
<rect x="20" y="20" width="50" height="50" fill="#3498db" transform="scale(1.5)"/>
<rect x="20" y="20" width="50" height="50" fill="#2ecc71" transform="scale(2)"/>
</svg>

如果省略 sy,则 sy 等于 sx,实现等比例缩放。

非均匀缩放

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="75" r="30" fill="#e74c3c"/>
<ellipse cx="150" cy="75" rx="45" ry="30" fill="#3498db"/>
<ellipse cx="250" cy="75" rx="30" ry="60" fill="#2ecc71"/>
</svg>

缩放的原点问题

缩放以原点为中心进行,这可能导致元素位置偏移:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="50" height="50" fill="#e74c3c" opacity="0.3"/>
<rect x="50" y="50" width="50" height="50" fill="#e74c3c" transform="scale(1.5)"/>
</svg>

要围绕元素中心缩放,需要先平移到原点,缩放后再平移回来:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="50" height="50" fill="#3498db" opacity="0.3"/>
<rect x="50" y="50" width="50" height="50" fill="#3498db"
transform="translate(75, 75) scale(1.5) translate(-75, -75)"/>
</svg>

负值缩放

负值缩放会产生镜像效果:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<text x="20" y="60" font-size="24" fill="#e74c3c">正常文本</text>
<text x="280" y="60" font-size="24" fill="#3498db" transform="scale(-1, 1)">镜像文本</text>
</svg>

斜切 - skewX 和 skewY

skewX(angle) 沿 x 轴斜切,skewY(angle) 沿 y 轴斜切。

skewX

<svg width="300" height="100" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="20" width="50" height="50" fill="#e74c3c"/>
<rect x="100" y="20" width="50" height="50" fill="#3498db" transform="skewX(20)"/>
<rect x="180" y="20" width="50" height="50" fill="#2ecc71" transform="skewX(40)"/>
</svg>

skewY

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="20" width="50" height="50" fill="#e74c3c"/>
<rect x="100" y="20" width="50" height="50" fill="#3498db" transform="skewY(20)"/>
<rect x="180" y="20" width="50" height="50" fill="#2ecc71" transform="skewY(40)"/>
</svg>

组合斜切

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="100" y="50" width="60" height="60" fill="#9b59b6"
transform="skewX(15) skewY(15)"/>
</svg>

矩阵变换 - matrix

所有变换都可以用一个 3x3 变换矩阵表示。matrix(a, b, c, d, e, f) 直接指定变换矩阵:

| a c e |
| b d f |
| 0 0 1 |

变换公式:

x' = a*x + c*y + e
y' = b*x + d*y + f

基本变换对应的矩阵

变换矩阵参数
translate(tx, ty)matrix(1, 0, 0, 1, tx, ty)
scale(sx, sy)matrix(sx, 0, 0, sy, 0, 0)
rotate(a)matrix(cos(a), sin(a), -sin(a), cos(a), 0, 0)
skewX(a)matrix(1, 0, tan(a), 1, 0, 0)
skewY(a)matrix(1, tan(a), 0, 1, 0, 0)
<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="20" width="50" height="50" fill="#e74c3c"/>
<rect x="20" y="20" width="50" height="50" fill="#3498db"
transform="matrix(1, 0, 0, 1, 100, 30)"/>
</svg>

变换组合

多个变换可以组合使用,按从右到左的顺序执行:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="50" height="50" fill="#e74c3c" opacity="0.3"/>
<rect x="50" y="50" width="50" height="50" fill="#3498db"
transform="translate(100, 0) rotate(30)"/>
</svg>

这个例子中,先执行 rotate(30),再执行 translate(100, 0)

变换顺序的影响

变换顺序不同会产生不同结果:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="50" height="50" fill="#e74c3c" opacity="0.3"/>
<rect x="50" y="50" width="50" height="50" fill="#3498db"
transform="translate(100, 0) rotate(30)"/>
<rect x="50" y="50" width="50" height="50" fill="#2ecc71"
transform="rotate(30) translate(100, 0)"/>
</svg>

蓝色矩形先旋转后平移,绿色矩形先平移后旋转,结果完全不同。

围绕中心旋转的正确方法

要围绕元素中心旋转,正确的变换顺序是:平移到原点 → 旋转 → 平移回原位置:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="100" y="50" width="60" height="60" fill="#9b59b6" opacity="0.3"/>
<rect x="100" y="50" width="60" height="60" fill="#9b59b6"
transform="translate(130, 80) rotate(45) translate(-130, -80)"/>
</svg>

transform-origin 属性

CSS 的 transform-origin 属性可以简化围绕特定点变换的操作:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<style>
.rotate-center {
transform-origin: center;
transform: rotate(30deg);
}
</style>
<rect x="100" y="50" width="60" height="60" fill="#1abc9c" class="rotate-center"/>
</svg>

注意:使用 CSS transform 时,角度单位需要用 deg

嵌套坐标系统

<svg> 元素可以嵌套,内层 SVG 创建新的坐标系统:

<svg width="300" height="150" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="80" height="60" fill="#e74c3c"/>
<svg x="100" y="10" width="100" height="100" viewBox="0 0 50 50">
<rect x="5" y="5" width="40" height="40" fill="#3498db"/>
</svg>
</svg>

内层 SVG 的 viewBox="0 0 50 50" 定义了 50x50 的坐标系统,但显示区域是 100x100,所以内容被放大了两倍。

viewBox 与变换

viewBox 属性本质上是一种变换,它将用户坐标映射到视口坐标:

<svg width="200" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="80" height="80" fill="#f39c12"/>
</svg>

viewBox="0 0 100 100" 定义了 100x100 的用户坐标系统,显示在 200x100 的视口中,x 方向被放大 2 倍,y 方向保持不变。

实用示例

旋转的风车

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(100, 100)">
<polygon points="0,-80 20,-20 0,0 -20,-20" fill="#e74c3c" transform="rotate(0)"/>
<polygon points="0,-80 20,-20 0,0 -20,-20" fill="#3498db" transform="rotate(90)"/>
<polygon points="0,-80 20,-20 0,0 -20,-20" fill="#2ecc71" transform="rotate(180)"/>
<polygon points="0,-80 20,-20 0,0 -20,-20" fill="#f39c12" transform="rotate(270)"/>
<circle r="15" fill="#2c3e50"/>
</g>
</svg>

3D 立方体

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(100, 100)">
<polygon points="-40,-20 40,-20 40,60 -40,60" fill="#3498db"/>
<polygon points="-40,-20 0,-50 80,-50 40,-20" fill="#2980b9"/>
<polygon points="40,-20 80,-50 80,30 40,60" fill="#1a5276"/>
</g>
</svg>

阴影效果

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="100" cy="80" rx="60" ry="10" fill="#bdc3c7"/>
<rect x="60" y="20" width="80" height="60" rx="5" fill="#3498db"
transform="skewX(-10)"/>
</svg>

小结

变换是 SVG 中操作图形位置、大小和方向的核心工具。平移移动元素,旋转改变方向,缩放改变大小,斜切产生倾斜效果。变换可以组合使用,但顺序很重要。理解变换的本质是操作坐标系统,有助于正确应用变换实现预期效果。