前置知识: SVG

SVG 变换 transform

5 minIntermediate2026/7/18

translate、rotate、scale、skew、matrix 与 transform-origin 变换组合。

1. transform 属性

transform 对元素或分组应用几何变换,不影响后续元素的坐标系(除非在 <g> 上)。

<svg viewBox="0 0 200 200">
  <rect x="50" y="50" width="50" height="50" fill="#4f5bd5" />
  <rect x="50" y="50" width="50" height="50" fill="#d63031" transform="translate(60, 0)" />
</svg>

2. 基本变换函数

2.1 translate 平移

<rect transform="translate(50, 30)" />
<!-- 或单轴 -->
<rect transform="translate(50, 0)" />
参数说明
txX 方向偏移
tyY 方向偏移(可省略,默认 0)

2.2 rotate 旋转

<rect transform="rotate(45)" />
<!-- 围绕指定点旋转 -->
<rect transform="rotate(45 100 100)" />
参数说明
angle旋转角度(度)
cx, cy旋转中心(可省略,默认 0,0)

单参数 rotate(45) 围绕原点 (0,0) 旋转,通常不是想要的效果。常用 rotate(angle cx cy) 围绕元素中心旋转

2.3 scale 缩放

<rect transform="scale(1.5)" />
<!-- 双轴独立 -->
<rect transform="scale(1.5, 0.5)" />
参数说明
sxX 方向缩放比
syY 方向缩放比(可省略,默认等于 sx)

scale 会同时缩放 stroke-width。若需保持描边不变,使用 vector-effect="non-scaling-stroke"

2.4 skew 倾斜

<rect transform="skewX(30)" /> <rect transform="skewY(15)" />
函数说明
skewX(angle)沿 X 轴倾斜
skewY(angle)沐 Y 轴倾斜

3. matrix 矩阵

所有变换本质都是 2D 仿射矩阵: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

3.1 各变换对应的矩阵

变换matrix 参数
translate(tx, ty)matrix(1 0 0 1 tx ty)
rotate(θ)matrix(cosθ sinθ -sinθ cosθ 0 0)
scale(s)matrix(s 0 0 s 0 0)
skewX(θ)matrix(1 0 tanθ 1 0 0)

3.2 示例

<rect transform="matrix(1 0 0 1 50 30)" />
<!-- 等价于 translate(50, 30) -->

<rect transform="matrix(0.707 0.707 -0.707 0.707 0 0)" />
<!-- 等价于 rotate(45) -->

4. 变换组合

多个变换用空格分隔,从右到左应用(似 CSS transform)。

<!-- 先 translate 再 rotate(视觉上) -->
<rect transform="translate(100, 100) rotate(45)" />

<!-- 先 rotate 再 translate -->
<rect transform="rotate(45) translate(100, 0)" />

4.1 顺序影响结果

<svg viewBox="0 0 200 200">
  <!-- 原始矩形 -->
  <rect x="0" y="0" width="50" height="50" fill="#4f5bd5" />

  <!-- 先平移到 (100,100) 再绕原点旋转 45°:矩形被甩到远处 -->
  <rect
    x="0"
    y="0"
    width="50"
    height="50"
    fill="#d63031"
    transform="rotate(45) translate(100,100)"
  />

  <!-- 先绕原点旋转 45° 再平移到 (100,100):矩形在 (100,100) 处旋转 -->
  <rect
    x="0"
    y="0"
    width="50"
    height="50"
    fill="#00b894"
    transform="translate(100,100) rotate(45)"
  />
</svg>

建议:旋转用 rotate(angle cx cy) 形式,避免顺序歧义。

5. transform-origin

SVG 2 引入 transform-origin似 CSS 的同名属性。

<rect
  x="50"
  y="50"
  width="50"
  height="50"
  transform="rotate(45)"
  transform-origin="75px 75px"
  style="transform-box: fill-box"
/>

5.1 transform-box

含义
view-box以 SVG viewBox 为参考(默认)
fill-box以元素边界框为参考
<style>
  .spin {
    transform-box: fill-box;
    transform-origin: center;
    animation: spin 2s linear infinite;
  }
  @keyframes spin {
    to {
      transform: rotate(360deg);
    }
  }
</style>
<rect class="spin" x="50" y="50" width="100" height="100" fill="#4f5bd5" />

transform-box: fill-box + transform-origin: center 是 SVG 元素围绕自身中心旋转的标准模式。

6. CSS transform 与 SVG transform

CSS transform 也可作用于 SVG 元素,但需注意坐标系差异。

6.1 CSS 方式

.logo {
  transform: rotate(45deg);
  transform-origin: 50% 50%;
  transform-box: fill-box;
}
<svg viewBox="0 0 200 200">
  <rect class="logo" x="50" y="50" width="100" height="100" fill="#4f5bd5" />
</svg>

6.2 两者区别

维度SVG transform 属性CSS transform
语法rotate(45 100 100)rotate(45deg) + transform-origin
单位无单位(默认度/像素)degpx
动画SMIL <animateTransform>CSS @keyframes
性能略优(直接矩阵)现代浏览器已优化
浏览器支持全部SVG 2 后完整支持

7. animateTransform 变换动画

SMIL 提供 <animateTransform> 专门用于变换动画。

<svg viewBox="0 0 200 200">
  <rect x="75" y="75" width="50" height="50" fill="#4f5bd5">
    <animateTransform
      attributeName="transform"
      type="rotate"
      from="0 100 100"
      to="360 100 100"
      dur="4s"
      repeatCount="indefinite"
    />
  </rect>
</svg>

7.1 多变换叠加 additive

<g>
  <animateTransform
    attributeName="transform"
    type="translate"
    values="0 0; 100 0; 0 0"
    dur="4s"
    repeatCount="indefinite"
  />
  <animateTransform
    attributeName="transform"
    type="rotate"
    values="0; 360"
    dur="2s"
    repeatCount="indefinite"
    additive="sum"
  />
  <rect x="-25" y="-25" width="50" height="50" fill="#4f5bd5" />
</g>

additive="sum" 让多个 animateTransform 叠加,否则后一个会覆盖前一个。

8. 嵌套变换

<g> 上的 transform 会作用于所有子元素,形成坐标系嵌套。

<svg viewBox="0 0 400 200">
  <g transform="translate(100, 100)">
    <!-- 子坐标系原点平移到 (100,100) -->
    <g transform="rotate(45)">
      <!-- 再旋转 45° -->
      <rect x="-25" y="-25" width="50" height="50" fill="#4f5bd5" />
    </g>
    <circle cx="0" cy="0" r="5" fill="#d63031" />
  </g>
</svg>

嵌套变换矩阵会相乘,最终变换是父子变换的复合。

9. 实战:地球绕太阳

<svg viewBox="0 0 400 400">
  <!-- 太阳 -->
  <circle cx="200" cy="200" r="40" fill="#f9a825" />
  <!-- 地球轨道 -->
  <circle cx="200" cy="200" r="120" fill="none" stroke="#ccc" stroke-dasharray="4 4" />
  <!-- 地球绕太阳公转 -->
  <g>
    <animateTransform
      attributeName="transform"
      type="rotate"
      from="0 200 200"
      to="360 200 200"
      dur="8s"
      repeatCount="indefinite"
    />
    <!-- 地球自转 -->
    <g transform="translate(320, 200)">
      <circle cx="0" cy="0" r="15" fill="#4f5bd5">
        <animateTransform
          attributeName="transform"
          type="rotate"
          from="0"
          to="360"
          dur="2s"
          repeatCount="indefinite"
        />
      </circle>
    </g>
  </g>
</svg>

结构

  • 外层 <g> 绕太阳中心旋转 → 实现公转
  • 内层 <g> translate 到轨道位置 → 地球位置
  • 地球 circle 自身 animateTransform → 自转

10. 常见陷阱

10.1 rotate 默认绕原点

<!-- 错误:矩形被甩到画布外 -->
<rect x="50" y="50" width="100" height="100" transform="rotate(45)" />

<!-- 正确:围绕矩形中心旋转 -->
<rect x="50" y="50" width="100" height="100" transform="rotate(45 100 100)" />

10.2 scale 缩放描边

<!-- 描边被放大到 6px -->
<rect stroke-width="2" transform="scale(3)" />

<!-- 保持描边不变 -->
<rect stroke-width="2" transform="scale(3)" vector-effect="non-scaling-stroke" />

10.3 transform 与 viewBox 重复缩放

<!-- viewBox 已缩放 2 倍,transform scale(2) 会再缩 2 倍 -->
<svg viewBox="0 0 100 100" width="200" height="200">
  <rect width="50" height="50" transform="scale(2)" />
  <!-- 实际显示 200×200 -->
</svg>

下一篇介绍滤镜,构建阴影、模糊、光照等高级视觉效果。