<g>元素通过transform属性实现整体变换,支持translate、rotate、scale等操作,且变换顺序影响结果;可统一设置fill、stroke、opacity等样式并继承给子元素;嵌套<g>能构建局部坐标系,便于复用与动画;对含<text>的组做scale需谨慎以防文字变形。

直接在 <g> 上写 transform 就能整体移动、旋转、缩放
SVG 的 <g> 本身不渲染图形,但它会把所有子元素(<circle>、<rect>、嵌套的 <g> 等)纳入同一个变换上下文。只要给 <g> 加上 transform 属性,整个组就按规则动起来。
常见写法:
-
transform="translate(80, 60)":整组向右移 80px、向下移 60px(注意顺序:x 在前,y 在后) -
transform="rotate(25 100 100)":绕坐标 (100, 100) 顺时针转 25 度(中心点必须显式给出,否则默认绕原点) -
transform="scale(0.75) translate(-20, -10)":先等比缩小到 75%,再平移——注意变换顺序影响结果,先写的先执行
别在子元素上重复写 transform,除非你明确需要局部覆盖;否则优先集中控制在 <g> 层。
用 <g> 统一设 fill、stroke、opacity 省得每个子元素都写
<g> 支持样式继承,填色、描边、透明度这些属性写在组上,子元素自动生效(除非子元素自己又写了同名属性,会覆盖)。
立即学习“前端免费学习笔记(深入)”;
例如:
<g fill="steelblue" stroke="#333" stroke-width="1.5"> <circle cx="20" cy="20" r="12"/> <rect x="40" y="10" width="30" height="20"/> <path d="M10,50 L30,50 L20,70 Z"/> </g>
三个形状都会是钢蓝色填充、深灰描边、1.5px 粗细——不用分别加 fill。
但要注意:text 元素对 fill 继承正常,但若组里有 stroke,文字不会描边(<text> 默认不响应 stroke,需显式加)。
嵌套 <g> 构建局部坐标系,避免手动调每个 x/y
外层 <g transform="translate(100, 80)"> 定义新原点,内层所有子元素的坐标都相对于这个新原点算——相当于“把画布挪过去再画”,而不是每个 <circle cx="10" cy="10"> 都改成 cx="110" cy="90"。
典型场景:
- 画齿轮:外层
<g transform="rotate(45)">控制整体朝向,内层多个<g transform="rotate(30)">分布齿形 - 做图标系统:一个
<g id="icon-home">内部用 (0,0) 为中心设计,复用时只需改外层transform定位 - 动画联动:JS 修改外层
<g>的transform,内部结构完全不动,逻辑解耦
嵌套层级越深,坐标系叠加越明显;调试时可用 console.log(group.getCTM()) 查当前变换矩阵。
对含 <text> 的 <g> 做 scale() 要小心文字变形
transform="scale(2)" 会让组内所有内容等比放大,包括文字尺寸和描边粗细——这通常不是想要的效果,文字可能糊掉或比例失调。
更稳妥的做法:
- 去掉
<g>上的scale(),改用<svg viewBox="0 0 100 100">+ CSSwidth/height控制整体缩放(文字保持可读) - 保留
scale()但给<text>单独加transform="scale(0.5)"抵消(不推荐,维护成本高) - 用 CSS 控制文字:
<text style="font-size: 14px">,再配合vector-effect="non-scaling-stroke"让描边不随缩放变粗
真正容易被忽略的是:<g> 的变换不影响其自身尺寸计算(比如 getBBox() 返回的是变换后的包围盒),但 JS 动态修改时,若依赖原始坐标做计算,得先用 getScreenCTM().inverse() 反向映射。



















