SVG 基础
SVG 文档结构
SVG 是基于 XML 的矢量图形。viewBox 属性定义坐标系。所有形状都可用 CSS 或 fill、stroke 等属性来设置样式。
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
width="200" height="200"
viewBox="0 0 200 200">
<!-- SVG content goes here -->
<rect x="0" y="0" width="200" height="200" fill="#eee"/>
</svg>viewBox 与坐标系
viewBox 建立独立于像素尺寸的内部坐标系。形状使用 viewBox 坐标;渲染器把它们缩放以适配 width/height。这把几何与显示尺寸解耦。
<!-- 1. Inline (best for styling and scripting) -->
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red"/>
</svg>
<!-- 2. As an image (no CSS/JS interaction) -->
<img src="icon.svg" alt="Icon" width="100" height="100">
<!-- 3. As a background (limited styling) -->
<div style="background: url('icon.svg') no-repeat;"></div>
<!-- 4. Via object/embed (allows scripting) -->
<object data="icon.svg" type="image/svg+xml"></object>width/height 与 viewBox
width/height 设置渲染后的像素尺寸;viewBox 设置绘图空间。响应式 SVG 应省略 width/height 并用 CSS 控制尺寸。两者都设置时,内容会缩放以适配(在没有 preserveAspectRatio 时可能变形)。
<svg width="200" height="100" viewBox="0 0 200 100">
<!-- Origin (0,0) is top-left, like Canvas -->
<!-- X increases rightward, Y increases downward -->
<!-- A point at (50, 25) -->
<circle cx="50" cy="25" r="3" fill="black"/>
<!-- The viewBox stretches content to fill width/height -->
<!-- viewBox="minX minY width height" -->
</svg>
<!-- viewBox 0 0 100 100 in a 200x200 element = 2x zoom -->
<svg width="200" height="200" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="50" fill="blue"/>
</svg>preserveAspectRatio
preserveAspectRatio 控制 viewBox 内容在宽高比不一致时如何适配。'meet' 完整放入(默认),'slice' 覆盖并裁剪,'none' 拉伸。xMidYMid 部分设置对齐方式(xMin/xMid/xMax、YMin/YMid/YMax)。
<svg width="200" height="100">
<!-- Default unit is the user unit (px equivalent) -->
</svg>
<!-- Common units: px, em, %, pt, cm, mm, in -->
<svg width="50%" height="auto" viewBox="0 0 100 100">
<!-- % is relative to the parent element -->
</svg>
<!-- No width/height + viewBox = fully responsive -->
<svg viewBox="0 0 100 100" style="width:100%;height:auto;">
<!-- Scales to container, preserves aspect ratio -->
</svg>xmlns 与命名空间
xmlns 声明 SVG 命名空间,在独立文件中必需。在 HTML5 中内联 SVG 可省略它。直接用 href(SVG 2)替代 xlink:href。foreignObject 可在 SVG 内嵌入 HTML/XML。
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Modern SVG 2: use href directly -->
<use href="#icon"/>
<!-- Legacy SVG 1.1: use xlink:href -->
<use xlink:href="#icon"/>
</svg>
<!-- In HTML5 inline SVG, the xmlns is optional -->
<!-- But xlink namespace is needed if you use xlink:href -->注释与 CDATA
SVG 支持 XML 注释(<!-- -->)。当 <style> 和 <script> 内容包含会被解析为 XML 标记的 < 或 & 字符时,使用 CDATA 段。现代解析器通常无需 CDATA 也能处理,但对内嵌 CSS/JS 最安全。
<svg width="100" height="100" viewBox="0 0 100 100">
<!-- This is an XML comment (same as HTML) -->
<!-- Metadata is hidden from rendering -->
<metadata>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<dc:title xmlns:dc="http://purl.org/dc/elements/1.1/">My Icon</dc:title>
</rdf:RDF>
</metadata>
<!-- title and desc for accessibility -->
<title>Shopping Cart Icon</title>
<desc>A red shopping cart with 3 items</desc>
<circle cx="50" cy="50" r="40" fill="red"/>
</svg>矩形
基本矩形
<rect> 绘制矩形。x/y 定位左上角;width/height 设置尺寸。默认 fill 为黑色;默认 stroke 为 none。
<svg width="200" height="100" viewBox="0 0 200 100">
<!-- Basic rectangle -->
<rect x="10" y="10" width="80" height="50" fill="steelblue"/>
<!-- Rounded corners -->
<rect x="110" y="10" width="80" height="50"
rx="10" ry="10" fill="tomato"/>
<!-- Stroked, no fill -->
<rect x="10" y="70" width="80" height="20"
fill="none" stroke="black" stroke-width="2"/>
</svg>圆角(rx/ry)
rx 和 ry 创建圆角。只指定 rx 时,ry 默认取相同值。当半径超过尺寸一半时会产生药丸/跑道形。
<svg width="200" height="120" viewBox="0 0 200 120">
<!-- circle: cx, cy (center), r (radius) -->
<circle cx="50" cy="60" r="40" fill="gold"/>
<!-- ellipse: cx, cy, rx (x radius), ry (y radius) -->
<ellipse cx="150" cy="60" rx="50" ry="30" fill="mediumpurple"/>
<!-- Circle as an ellipse (rx == ry) -->
<ellipse cx="100" cy="20" rx="15" ry="15" fill="black"/>
</svg>描边与填充
fill 设置内部颜色;stroke 设置轮廓。stroke-width 居中于路径(一半在几何内部、一半在外部)。fill-opacity 和 stroke-opacity 可与整体 opacity 属性不同。
<svg width="200" height="100" viewBox="0 0 200 100">
<!-- line: x1,y1 (start) to x2,y2 (end) -->
<line x1="10" y1="10" x2="190" y2="10" stroke="black" stroke-width="2"/>
<!-- Diagonal line -->
<line x1="10" y1="90" x2="190" y2="10" stroke="red" stroke-width="3"/>
<!-- Dashed line -->
<line x1="10" y1="50" x2="190" y2="50"
stroke="blue" stroke-width="2" stroke-dasharray="10,5"/>
</svg>描边虚线
stroke-dasharray 用一组虚线/间隙长度定义重复的虚线模式。stroke-dashoffset 偏移模式的起点——对其做动画可产生蚂蚁线效果。
<svg width="200" height="120" viewBox="0 0 200 120">
<!-- polyline: open shape (no auto-close) -->
<polyline points="10,10 50,90 100,10 150,90 190,10"
fill="none" stroke="green" stroke-width="2"/>
<!-- polygon: closed shape (auto-connects last to first) -->
<polygon points="100,10 190,110 10,110"
fill="lime" stroke="black" stroke-width="1"/>
<!-- Star (polygon with 10 points) -->
<polygon points="50,5 61,38 95,38 67,58 78,90 50,70 22,90 33,58 5,38 39,38"
fill="gold" stroke="orange"/>
</svg>rect 上的变换
transform 属性对元素应用 translate、rotate、scale、skew 或 matrix 操作。变换从右向左组合。transform-origin(CSS)设置枢轴点。
<svg width="200" height="100" viewBox="0 0 200 100">
<rect x="10" y="10" width="80" height="80"
fill="#3498db"
fill-opacity="0.5"
stroke="#2c3e50"
stroke-width="3"
stroke-opacity="0.8"
stroke-dasharray="5,3"
stroke-linecap="round"
stroke-linejoin="round"
opacity="0.9"/>
<!-- opacity affects the whole element -->
<!-- fill-opacity/stroke-opacity affect parts independently -->
</svg>Fill Rules (evenodd)
fill-rule determines how overlapping regions of a shape are filled. 'nonzero' (default) fills based on winding direction. 'evenodd' fills regions that are enclosed an odd number of times — this creates the classic 'donut hole' effect for self-intersecting paths and concentric polygons.
<svg width="200" height="100" viewBox="0 0 200 100">
<!-- Default fill-rule: nonzero -->
<polygon points="50,10 90,90 10,90 50,30 80,80 20,80"
fill="red" fill-rule="nonzero"/>
<!-- fill-rule: evenodd creates holes in overlapping shapes -->
<polygon points="150,10 190,90 110,90 150,30 180,80 120,80"
fill="blue" fill-rule="evenodd"/>
</svg>圆与椭圆
圆(cx/cy/r)
<circle> 用 cx/cy 表示圆心、r 表示半径。默认值为 cx=0、cy=0、r=0。负的 r 会被忽略。
<svg width="200" height="100" viewBox="0 0 200 100">
<!-- The d attribute contains all path commands -->
<path d="M 10 10 L 190 10 L 100 90 Z" fill="none" stroke="black"/>
<!-- Uppercase = absolute, lowercase = relative -->
<!-- M = moveto (lift pen, move) -->
<!-- L = lineto (draw straight line) -->
<!-- H = horizontal lineto, V = vertical lineto -->
<!-- C = cubic bezier, S = smooth cubic -->
<!-- Q = quadratic bezier, T = smooth quadratic -->
<!-- A = arc, Z = closepath -->
</svg>椭圆(cx/cy/rx/ry)
<ellipse> 接受独立的 rx(水平)和 ry(垂直)半径,允许非圆形椭圆。设 rx=ry 可模拟圆。
<svg width="200" height="120" viewBox="0 0 200 120">
<!-- M = moveto, L = lineto, Z = close path -->
<path d="M 10 10 L 190 10 L 190 110 L 10 110 Z"
fill="none" stroke="black"/>
<!-- H = horizontal line, V = vertical line (one coord each) -->
<path d="M 10 60 H 190" stroke="red"/>
<!-- Relative commands (lowercase): coords are offsets -->
<path d="M 10 80 l 30 -20 l 30 20 l 30 -20 l 30 20"
fill="none" stroke="blue"/>
<!-- Multiple M's create subpaths (disconnected segments) -->
<path d="M 10 100 L 50 100 M 100 100 L 150 100" stroke="green"/>
</svg>带描边的圆
在圆上,描边绘制在半径线的中心——一半向内、一半向外。r=40 的圆加 10px 描边覆盖从 r=35 到 r=45 的像素。
<svg width="240" height="120" viewBox="0 0 240 120">
<!-- C = cubic bezier: two control points + endpoint -->
<!-- C x1 y1, x2 y2, x y -->
<path d="M 10 60 C 60 10, 180 110, 230 60"
fill="none" stroke="red" stroke-width="2"/>
<!-- S = smooth cubic: control point mirrors the previous -->
<!-- S x2 y2, x y (first control point is auto-mirrored) -->
<path d="M 10 100 C 60 50, 100 50, 120 100 S 200 150, 230 100"
fill="none" stroke="blue" stroke-width="2"/>
<!-- Multiple cubics in one path -->
<path d="M 10 20 C 40 0, 70 40, 100 20 C 130 0, 160 40, 190 20"
fill="none" stroke="green"/>
</svg>带透明度的填充圆
opacity 应用于整个元素(填充+描边一起)。fill-opacity 和 stroke-opacity 相互独立。重叠的半透明形状通过 alpha 合成混合。
<svg width="200" height="120" viewBox="0 0 200 120">
<!-- Q = quadratic bezier: one control point + endpoint -->
<!-- Q x1 y1, x y -->
<path d="M 10 100 Q 100 0, 190 100"
fill="none" stroke="purple" stroke-width="2"/>
<!-- T = smooth quadratic: control point auto-mirrored -->
<path d="M 10 60 Q 50 20, 90 60 T 170 60"
fill="none" stroke="orange" stroke-width="2"/>
<!-- Q is simpler than C but less precise — good for curves -->
<!-- with a single bend, like basic arcs and waves -->
</svg>用描边做圆环
设 fill=none 加粗描边即可轻松做出圆环/甜甜圈。要画弧线,用 stroke-dasharray 配合周长计算(2*pi*r)。画圆的 25%:dash = 0.25 * 周长。
<svg width="200" height="150" viewBox="0 0 200 150">
<!-- A rx ry, x-rotation, large-arc-flag, sweep-flag, x y -->
<path d="M 10 75 A 60 60, 0, 0, 1, 130 75"
fill="none" stroke="red" stroke-width="2"/>
<!-- large-arc-flag: 0 = small arc, 1 = large arc -->
<!-- sweep-flag: 0 = counterclockwise, 1 = clockwise -->
<!-- Large arc (the long way around) -->
<path d="M 10 75 A 60 60, 0, 1, 1, 130 75"
fill="none" stroke="blue" stroke-width="2"/>
<!-- Elliptical arc (rx != ry) -->
<path d="M 10 120 A 80 30, 0, 0, 0, 170 120"
fill="none" stroke="green" stroke-width="2"/>
</svg>Practical Path Examples
Real-world icons combine M, L, C, and Z to trace shapes. The heart uses cubic beziers for smooth curves. The checkmark is just three points with round line caps. The speech bubble mixes H/V lines for the rectangle and L commands for the tail. Start simple, then refine control points.
<svg width="200" height="120" viewBox="0 0 200 120">
<!-- Heart shape -->
<path d="M 100 30
C 70 0, 20 20, 20 60
C 20 90, 60 110, 100 120
C 140 110, 180 90, 180 60
C 180 20, 130 0, 100 30 Z"
fill="red"/>
<!-- Checkmark -->
<path d="M 20 60 L 50 90 L 100 20"
fill="none" stroke="green" stroke-width="6"
stroke-linecap="round" stroke-linejoin="round"/>
<!-- Speech bubble (combines lines and curves) -->
<path d="M 20 20 H 180 V 80 H 60 L 40 100 L 45 80 H 20 Z"
fill="lightblue" stroke="navy"/>
</svg>线、折线与多边形
直线(x1/y1/x2/y2)
<line> 在两点间画直线段。它没有填充(线无法填充)。stroke-width、stroke-dasharray、stroke-linecap 都适用。
<svg width="200" height="100" viewBox="0 0 200 100">
<text x="10" y="50" font-family="Arial" font-size="24"
fill="black">Hello SVG!</text>
<!-- x, y sets the baseline position (y is the text baseline) -->
<!-- Use dominant-baseline to change the vertical anchor -->
<text x="100" y="50" font-size="20" fill="blue"
text-anchor="middle" dominant-baseline="middle">Centered</text>
</svg>折线
<polyline> 用直线连接一组点。它不会自动闭合,所以填充会隐式绘制一条闭合边。折线图请设 fill=none。
<svg width="300" height="120" viewBox="0 0 300 120">
<text x="10" y="30"
font-family="Georgia, serif"
font-size="28"
font-weight="bold"
font-style="italic"
fill="darkblue"
stroke="navy"
stroke-width="0.5"
text-decoration="underline"
letter-spacing="2">Styled Text</text>
<!-- font-family uses CSS font stacks -->
<!-- font-weight: normal, bold, 100-900 -->
<!-- font-style: normal, italic, oblique -->
</svg>多边形
<polygon> 类似 polyline,但会自动从最后一个点画回第一个点闭合形状。闭合边会被描边。
<svg width="300" height="100" viewBox="0 0 300 100">
<text x="10" y="50" font-size="20" fill="black">
<tspan font-weight="bold" fill="red">Bold red</tspan>
<tspan dx="10" font-style="italic">italic</tspan>
<tspan x="10" dy="30">New line via dy</tspan>
<tspan dx="10" font-size="14">smaller</tspan>
</text>
<!-- dx/dy: relative offset from previous position -->
<!-- x/y: absolute position (useful for line breaks) -->
</svg>描边端帽
stroke-linecap 控制开放路径的端点。'butt' 在端点平切,'round' 加半圆,'square' 延伸半个描边宽度的矩形。默认是 'butt'。
<svg width="300" height="150" viewBox="0 0 300 150">
<!-- Define a path (can be invisible) -->
<defs>
<path id="curve" d="M 20 100 Q 150 0, 280 100" fill="none"/>
</defs>
<!-- Text follows the path via xlink:href / href -->
<text font-size="20" fill="purple">
<textPath href="#curve">Text along a curved path!</textPath>
</text>
<!-- startOffset shifts where the text begins on the path -->
<text font-size="14" fill="gray">
<textPath href="#curve" startOffset="50%" text-anchor="middle">
Centered on path
</textPath>
</text>
</svg>描边连接
stroke-linejoin 控制线段间拐角的渲染。'miter' 形成尖角(被 stroke-miterlimit 裁剪),'round' 圆滑,'bevel' 削平拐角。默认是 'miter'。
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- Vertical text (top-to-bottom) -->
<text x="50" y="20" writing-mode="tb" font-size="20">Vertical</text>
<!-- Right-to-left text -->
<text x="190" y="100" direction="rtl" font-size="20"
text-anchor="end">RTL text</text>
<!-- Rotated text (via transform) -->
<text x="100" y="100" font-size="20"
transform="rotate(45, 100, 100)">Rotated 45°</text>
</svg>线上的标记
<marker> 定义可复用的箭头或端点,通过 marker-start/marker-mid/marker-end 引用。refX/refY 定位标记;orient='auto' 让它沿路径方向旋转。
<svg width="200" height="80" viewBox="0 0 200 80">
<title>Error Icon</title>
<desc>A red circle with a white exclamation mark</desc>
<!-- role and aria-label for screen readers -->
<text role="img" aria-label="Error: 3 items need attention"
x="100" y="45" text-anchor="middle"
font-size="24" fill="red">! Error</text>
</svg>路径
M / L / H / V 命令
<path> 的 d 属性使用命令:M(移到,抬笔)、L(连线)、H/V(水平/垂直线)、Z(闭合)。大写=绝对坐标;小写=相对当前点。
<svg width="200" height="100" viewBox="0 0 200 100">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="red"/>
<stop offset="50%" stop-color="yellow"/>
<stop offset="100%" stop-color="green"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="180" height="80" fill="url(#grad1)"/>
</svg>C / S 三次贝塞尔
C 用两个控制点画三次贝塞尔;S 通过反射上一个控制点平滑续接。控制点把曲线拉向自己,但曲线不经过控制点。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<radialGradient id="grad2" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0%" stop-color="white"/>
<stop offset="50%" stop-color="orange"/>
<stop offset="100%" stop-color="darkred"/>
</radialGradient>
</defs>
<circle cx="100" cy="100" r="90" fill="url(#grad2)"/>
</svg>Q / T 二次贝塞尔
Q 用单个控制点画二次贝塞尔;T 平滑续接。二次比三次更简单(一个控制点),适合弧线、波浪和圆角。
<svg width="300" height="100" viewBox="0 0 300 100">
<defs>
<!-- objectBoundingBox (default): coords are 0-1 relative to the shape -->
<linearGradient id="g1" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="blue"/>
<stop offset="1" stop-color="cyan"/>
</linearGradient>
<!-- userSpaceOnUse: coords are in the SVG's user units -->
<linearGradient id="g2" x1="0" y1="0" x2="200" y2="0"
gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="red"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
<!-- spreadMethod: pad (default), reflect, repeat -->
<linearGradient id="g3" x1="0" y1="0" x2="0.3" y2="0"
spreadMethod="repeat">
<stop offset="0" stop-color="green"/>
<stop offset="1" stop-color="lime"/>
</linearGradient>
</defs>
<rect width="100" height="100" x="0" fill="url(#g1)"/>
<rect width="100" height="100" x="100" fill="url(#g2)"/>
<rect width="100" height="100" x="200" fill="url(#g3)"/>
</svg>A 弧线命令
A 命令画椭圆弧。rx/ry 是半径,x-axis-rotation 倾斜椭圆,large-arc-flag 选择优/劣弧(0/1),sweep-flag 选择顺时针(1)或逆时针(0)。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<linearGradient id="sunset" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="deepskyblue" stop-opacity="0"/>
<stop offset="40%" stop-color="orange" stop-opacity="0.8"/>
<stop offset="70%" stop-color="orangered"/>
<stop offset="100%" stop-color="darkred"/>
</linearGradient>
</defs>
<rect width="200" height="200" fill="url(#sunset)"/>
</svg>Z 闭合路径
Z 画线回到当前子路径的起点(最近的 M)。需要它来描边闭合边。填充无论是否有 Z 都会把路径当作闭合处理。
<svg width="300" height="100" viewBox="0 0 300 100">
<defs>
<!-- A reusable gradient -->
<linearGradient id="metal" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#eee"/>
<stop offset="50%" stop-color="#999"/>
<stop offset="100%" stop-color="#333"/>
</linearGradient>
<!-- Gradient referencing another via href -->
<linearGradient id="metal-horizontal" href="#metal"
x1="0" y1="0" x2="1" y2="0"/>
</defs>
<!-- Same gradient on multiple shapes -->
<rect x="10" y="10" width="80" height="80" fill="url(#metal)"/>
<circle cx="150" cy="50" r="40" fill="url(#metal)"/>
<rect x="210" y="10" width="80" height="80" fill="url(#metal-horizontal)"/>
</svg>文本
基本文本
<text> 把文本放在 x/y(默认是基线)。字体通过 font-family、font-size、font-weight、font-style 设置——与 CSS 属性相同。fill 设置文本颜色。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<pattern id="dots" x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="3" fill="steelblue"/>
</pattern>
</defs>
<rect width="200" height="200" fill="url(#dots)"/>
</svg>text-anchor 与 dominant-baseline
text-anchor 相对 x 水平对齐文本:'start'(默认,左)、'middle'(中)、'end'(右)。dominant-baseline 垂直对齐:'middle'、'hanging'、'alphabetic'(默认)、'central'。
<svg width="300" height="100" viewBox="0 0 300 100">
<defs>
<!-- objectBoundingBox (default): tile size is relative to shape -->
<!-- 0.1 = 10% of the shape's width/height -->
<pattern id="p1" width="0.1" height="0.1">
<rect width="10" height="10" fill="red" opacity="0.5"/>
</pattern>
<!-- userSpaceOnUse: tile size is in SVG units -->
<pattern id="p2" width="20" height="20"
patternUnits="userSpaceOnUse">
<rect width="10" height="10" fill="blue" opacity="0.5"/>
</pattern>
</defs>
<rect width="150" height="100" fill="url(#p1)"/>
<rect x="150" width="150" height="100" fill="url(#p2)"/>
</svg>tspan
<tspan> 给文本的不同部分设置不同样式(类似 HTML 的 <span>)。可覆盖字体、颜色、字重。用 dx/dy 相对前一字形位移,可做下标/上标。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- Diagonal stripes -->
<pattern id="stripes" width="20" height="20"
patternUnits="userSpaceOnUse"
patternTransform="rotate(45)">
<rect width="20" height="10" fill="gold"/>
<rect y="10" width="20" height="10" fill="black"/>
</pattern>
<!-- Checkerboard -->
<pattern id="checker" width="40" height="40"
patternUnits="userSpaceOnUse">
<rect width="40" height="40" fill="white"/>
<rect width="20" height="20" fill="black"/>
<rect x="20" y="20" width="20" height="20" fill="black"/>
</pattern>
</defs>
<rect width="100" height="200" fill="url(#stripes)"/>
<rect x="100" width="100" height="200" fill="url(#checker)"/>
</svg>textPath
<textPath> 沿 <path> 的轮廓渲染文本。通过 href 引用路径。startOffset 沿路径定位文本(长度或百分比)。text-anchor 也适用于 textPath。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- patternContentUnits: how the pattern's children are measured -->
<!-- userSpaceOnUse (default): children use SVG units -->
<!-- objectBoundingBox: children are relative to the shape -->
<pattern id="pb" width="0.25" height="0.25"
patternContentUnits="objectBoundingBox">
<circle cx="0.125" cy="0.125" r="0.05" fill="green"/>
</pattern>
</defs>
<!-- The dots scale with each shape's bounding box -->
<rect width="100" height="100" fill="url(#pb)"/>
<rect x="100" width="100" height="200" fill="url(#pb)"/>
</svg>字体属性
SVG 文本支持标准 CSS 字体属性:font-family、font-size、font-weight、font-style、font-stretch,以及 letter-spacing 和 word-spacing。务必提供通用回退字体族。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- A pattern can reference another pattern or gradient -->
<pattern id="grid" width="40" height="40"
patternUnits="userSpaceOnUse">
<rect width="40" height="40" fill="url(#cellGrad)"/>
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#ccc"/>
</pattern>
<linearGradient id="cellGrad">
<stop offset="0" stop-color="#f0f8ff"/>
<stop offset="1" stop-color="#e0e0ff"/>
</linearGradient>
</defs>
<rect width="200" height="200" fill="url(#grid)"/>
</svg>渐变
线性渐变
<linearGradient> 沿 (x1,y1) 到 (x2,y2) 的直线混合颜色。坐标默认为 objectBoundingBox(0..1),其中 0,0 是左上、1,0 是右上。通过 fill=url(#id) 引用。
<svg width="200" height="100" viewBox="0 0 200 100">
<!-- Original -->
<rect x="10" y="10" width="40" height="40" fill="red"/>
<!-- Translated 80px right -->
<rect x="10" y="10" width="40" height="40" fill="blue"
transform="translate(80, 0)"/>
<!-- translate with one arg moves only horizontally -->
<rect x="10" y="10" width="40" height="40" fill="green"
transform="translate(0, 50)"/>
<!-- Equivalent in CSS (for inline SVG in HTML) -->
<rect x="10" y="10" width="40" height="40" fill="orange"
style="transform: translate(150px, 0);"/>
</svg>径向渐变
<radialGradient> 从中心点 (cx,cy) 向外辐射到半径 r。fx/fy 偏移焦点以产生不对称高光。适合球体、辉光和暗角。
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="50" y="50" width="100" height="20" fill="red"/>
<!-- rotate(angle) around origin (0,0) -->
<rect x="50" y="50" width="100" height="20" fill="blue"
transform="rotate(45)"/>
<!-- rotate(angle, cx, cy) around point (cx, cy) -->
<rect x="50" y="50" width="100" height="20" fill="green"
transform="rotate(45, 100, 60)"/>
<!-- Negative angles rotate counterclockwise -->
<rect x="50" y="50" width="100" height="20" fill="orange"
transform="rotate(-30, 100, 60)"/>
</svg>渐变停止点与透明度
每个 <stop> 有 offset(0..100%)、stop-color 和 stop-opacity。多个停止点产生多色混合。stop-opacity 让渐变淡出到透明——适合叠加和毛玻璃效果。
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- Original square -->
<rect x="10" y="10" width="50" height="50" fill="red"/>
<!-- scale(2): 2x in both dimensions -->
<rect x="10" y="10" width="50" height="50" fill="blue"
transform="scale(2)"/>
<!-- scale(sx, sy): different x and y scaling -->
<rect x="10" y="10" width="50" height="50" fill="green"
transform="scale(1, 2)"/>
<!-- skewX / skewY: shear the shape -->
<rect x="10" y="10" width="50" height="50" fill="orange"
transform="skewX(30)"/>
</svg>spreadMethod
spreadMethod 控制超出渐变边界时的行为:'pad'(默认)延伸末端颜色,'reflect' 来回镜像渐变,'repeat' 平铺它。适合条纹或重复图案。
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- transform="matrix(a, b, c, d, e, f)" -->
<!-- Represents: [a c e] [b d f] [0 0 1] -->
<!-- New x = a*x + c*y + e -->
<!-- New y = b*x + d*y + f -->
<!-- Identity (no change) -->
<rect width="50" height="50" fill="red" transform="matrix(1,0,0,1,0,0)"/>
<!-- Translate (100, 50) -->
<rect width="50" height="50" fill="blue" transform="matrix(1,0,0,1,100,50)"/>
<!-- Scale 2x and translate -->
<rect width="50" height="50" fill="green" transform="matrix(2,0,0,2,50,0)"/>
</svg>gradientUnits
gradientUnits='objectBoundingBox'(默认)把渐变坐标映射到每个形状的 0..1,所以渐变按元素缩放。'userSpaceOnUse' 用绝对 SVG 坐标,所以渐变在多个形状间保持固定——便于一致光照。
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- Multiple transforms apply right-to-left -->
<rect x="0" y="0" width="40" height="40" fill="red"
transform="translate(100, 100) rotate(45) scale(2)"/>
<!-- This means: scale, then rotate, then translate -->
<!-- Order matters! rotate then translate != translate then rotate -->
<!-- transform-origin via CSS (for inline SVG) -->
<rect x="80" y="80" width="40" height="40" fill="blue"
style="transform: rotate(45deg); transform-origin: center;"/>
<!-- transform-origin: center, 50% 50%, or explicit coords -->
</svg>复用渐变
在 <defs> 中定义一次渐变,即可在任意数量元素上用 fill=url(#id) 或 stroke=url(#id) 引用。使用 objectBoundingBox 单位时,同一渐变会自动适配每个形状的边界框。
<svg width="200" height="200" viewBox="0 0 200 200">
<style>
.gear {
transform-origin: 100px 100px; /* SVG user units */
transform-box: fill-box; /* or view-box */
animation: spin 4s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
<circle class="gear" cx="100" cy="100" r="50" fill="orange"/>
<circle cx="100" cy="100" r="10" fill="black"/>
</svg>图案
基本图案
<pattern> 平铺一块 SVG 内容来填充形状。width/height 设置瓦片尺寸。通过 fill=url(#id) 引用。瓦片内容绘制一次并在形状中重复。
<svg width="200" height="200" viewBox="0 0 200 200">
<g fill="steelblue" stroke="navy" stroke-width="2">
<!-- Children inherit the group's attributes -->
<circle cx="60" cy="60" r="30"/>
<rect x="100" y="30" width="60" height="60" rx="5"/>
<path d="M 30 150 L 100 110 L 170 150 Z"/>
</g>
<!-- Without g, you'd repeat fill/stroke on each element -->
</svg>patternUnits
patternUnits='objectBoundingBox'(默认)把瓦片尺寸作为形状的比例——图案随形状缩放。'userSpaceOnUse' 用绝对用户单位——瓦片保持固定像素尺寸,与形状大小无关。
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- A transform on a group applies to all children -->
<g transform="translate(100, 100) rotate(45)">
<rect x="-30" y="-30" width="60" height="60" fill="red"/>
<circle cx="0" cy="0" r="15" fill="white"/>
</g>
<!-- The group defines its own coordinate system -->
<!-- Children use coords relative to the group's origin -->
<g transform="translate(50, 150)">
<text x="0" y="0">Origin here</text>
<circle cx="0" cy="-20" r="5"/>
</g>
</svg>带形状的图案
图案瓦片可包含任何 SVG 元素:线、路径、圆,甚至嵌套图案。网格、条纹、棋盘和交叉线很常见。让瓦片部分透明可让底层填充透出。
<svg width="200" height="200" viewBox="0 0 200 200">
<g transform="translate(100, 100)"> <!-- outer group -->
<g transform="scale(0.5)"> <!-- inner group -->
<circle r="80" fill="blue"/>
<g transform="translate(40, 0)"> <!-- innermost -->
<circle r="20" fill="white"/>
</g>
</g>
</g>
<!-- Transforms compound: the innermost circle is -->
<!-- translated, scaled, and translated again -->
</svg>patternTransform
patternTransform 对整个图案平铺应用 translate、rotate、scale 或 skew。可把条纹旋转 45° 做斜线,或缩放图案使瓦片变大而无需修改其定义。
<svg width="200" height="100" viewBox="0 0 200 100">
<defs>
<g id="star">
<polygon points="50,5 61,38 95,38 67,58 78,90 50,70 22,90 33,58 5,38 39,38"
fill="gold" stroke="orange"/>
</g>
</defs>
<!-- Reference the group with <use> -->
<use href="#star" transform="translate(0, 0) scale(0.5)"/>
<use href="#star" transform="translate(100, 0) scale(0.5)"/>
<use href="#star" transform="translate(0, 50) scale(0.3)"/>
</svg>嵌套图案
图案可以引用其他图案,允许分层或嵌套平铺。这里一个小圆点图案填充较大网格图案的瓦片,用简单部件产生复杂纹理背景。
<svg width="200" height="100" viewBox="0 0 200 100">
<!-- <g> can have ids for CSS targeting and JS selection -->
<g id="button" class="interactive" data-action="save">
<rect width="80" height="30" rx="5" fill="steelblue"/>
<text x="40" y="20" text-anchor="middle" fill="white">Save</text>
</g>
<style>
#button:hover rect { fill: royalblue; }
#button { cursor: pointer; }
</style>
<script>
document.getElementById("button").addEventListener("click", save);
</script>
</svg>Group vs Symbol
<symbol> is purpose-built for reusable icons: it's never rendered directly and has its own viewBox, so <use> can size it independently. <g> in <defs> also works but lacks the viewBox feature. For icon systems, prefer <symbol> — it handles scaling and aspect ratio automatically.
<svg width="0" height="0" viewBox="0 0 0 0">
<!-- <g> in <defs>: original is hidden, use can instantiate -->
<defs>
<g id="icon-g">
<rect width="20" height="20" fill="red"/>
</g>
</defs>
<!-- <symbol> is like <g> but supports viewBox and is never rendered -->
<symbol id="icon-s" viewBox="0 0 20 20">
<rect width="20" height="20" fill="blue"/>
</symbol>
<!-- Use with explicit size (symbol scales to fit) -->
<use href="#icon-g" x="0" y="0"/>
<use href="#icon-s" x="40" y="0" width="40" height="40"/>
</svg>裁剪与遮罩
clipPath 基础
<clipPath> 定义一个裁剪内容的形状。带 clip-path=url(#id) 的元素只在裁剪区域内渲染。裁剪是二值的——像素要么完全可见,要么完全隐藏。
<svg width="200" height="100" viewBox="0 0 200 100">
<defs>
<!-- Anything in defs is defined but NOT rendered -->
<linearGradient id="myGrad">
<stop offset="0" stop-color="red"/>
<stop offset="1" stop-color="blue"/>
</linearGradient>
<pattern id="myPattern" width="20" height="20">
<circle cx="10" cy="10" r="5" fill="url(#myGrad)"/>
</pattern>
<g id="myShape">
<rect width="40" height="40" rx="5"/>
</g>
</defs>
<!-- Reference and render them -->
<rect width="100" height="100" fill="url(#myPattern)"/>
<use href="#myShape" x="120" y="30" fill="green"/>
</svg>用文本裁剪
在 clipPath 内使用文本会创建一个文本形状的窗口——适合图片填充的标题。文本本身不渲染,只用作裁剪区域。结合渐变或图片可产生惊艳效果。
<svg width="300" height="100" viewBox="0 0 300 100">
<defs>
<g id="cloud">
<circle cx="30" cy="50" r="20" fill="white"/>
<circle cx="50" cy="45" r="25" fill="white"/>
<circle cx="75" cy="50" r="20" fill="white"/>
</g>
</defs>
<!-- Basic use -->
<use href="#cloud"/>
<!-- Positioned and styled -->
<use href="#cloud" x="120" y="0" fill="lightgray"/>
<use href="#cloud" x="200" y="10" transform="scale(0.5)" fill="silver"/>
</svg>遮罩(亮度)
遮罩默认使用亮度:白色区域完全可见,黑色完全隐藏,灰色部分可见。这能实现平滑淡入和柔边——clipPath 做不到。mask-type 可切换为 alpha。
<!-- In a hidden sprite file or <defs> -->
<svg width="0" height="0" style="position:absolute">
<symbol id="heart" viewBox="0 0 32 32">
<path d="M16 28 C 4 18, 4 8, 12 8 C 14 8, 16 10, 16 12
C 16 10, 18 8, 20 8 C 28 8, 28 18, 16 28 Z"
fill="currentColor"/>
</symbol>
<symbol id="star" viewBox="0 0 32 32">
<polygon points="16,2 20,12 31,12 22,19 25,30 16,23 7,30 10,19 1,12 12,12"
fill="currentColor"/>
</symbol>
</svg>
<!-- Usage: size with width/height, color with CSS -->
<svg width="24" height="24"><use href="#heart"/></svg>
<svg width="48" height="48"><use href="#star" style="color: gold"/></svg>遮罩(Alpha)
用 mask-type='alpha' 时,遮罩使用 alpha 通道而非亮度——完全不透明区域可见,透明区域隐藏。这与 PNG/WebP 的 alpha 遮罩行为一致,通常更直观。
<!-- Reference a symbol in an external .svg file -->
<svg width="24" height="24">
<use href="icons.svg#heart"/>
</svg>
<!-- The external file (icons.svg) would contain: -->
<!-- <svg xmlns="http://www.w3.org/2000/svg" style="display:none"> -->
<!-- <symbol id="heart" viewBox="0 0 32 32">...</symbol> -->
<!-- </svg> -->
<!-- Note: external references have limited browser support -->
<!-- and don't work with file:// protocol. Inline is more reliable. -->
<!-- For production, inline the sprite at the top of your HTML body. -->clip-rule
clip-rule(设在 clipPath 内的形状上)控制重叠子路径的处理方式——'evenodd' 创建孔洞,'nonzero'(默认)按绕向填充。可构建带透明中心的相框式裁剪。
<svg width="300" height="100" viewBox="0 0 300 100">
<defs>
<!-- Shape without explicit fill — inherits from use -->
<circle id="ball" cx="20" cy="20" r="15"/>
</defs>
<!-- Each use can set its own fill -->
<use href="#ball" fill="red"/>
<use href="#ball" x="50" fill="green"/>
<use href="#ball" x="100" fill="blue" stroke="black" stroke-width="2"/>
</svg>多个裁剪路径
SVG 不直接支持在一个元素上组合多个 clip-path,但可以嵌套分组:每个 <g> 应用自己的 clip-path,相交所有裁剪。这产生韦恩图式的相交区域。
<!-- A complete inline SVG sprite system -->
<svg style="display:none" aria-hidden="true">
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M12 3 L2 12 H5 V21 H10 V14 H14 V21 H19 V12 H22 Z"/>
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
<line x1="16" y1="16" x2="21" y2="21" stroke="currentColor" stroke-width="2"/>
</symbol>
</svg>
<!-- Reference anywhere in HTML -->
<svg class="icon"><use href="#icon-home"/></svg>
<svg class="icon"><use href="#icon-search"/></svg>
<style>
.icon { width: 24px; height: 24px; fill: currentColor; }
</style>滤镜
高斯模糊
<feGaussianBlur> 柔化图像。stdDeviation 控制模糊半径(越大越模糊)。滤镜区域(x/y/width/height)必须扩展到默认 -10%..110% 之外,否则边缘的模糊会被裁剪。
<svg width="200" height="120" viewBox="0 0 200 120">
<defs>
<filter id="blur1">
<!-- feGaussianBlur: stdDeviation is the blur radius -->
<feGaussianBlur in="SourceGraphic" stdDeviation="3"/>
</filter>
</defs>
<!-- Without filter -->
<text x="10" y="30" font-size="24" fill="red">Sharp</text>
<!-- With filter -->
<text x="10" y="70" font-size="24" fill="red"
filter="url(#blur1)">Blurred</text>
</svg>投影
投影由原语构建:模糊 alpha(对 SourceAlpha 做 feGaussianBlur)、偏移(feOffset)、上色(feFlood + feComposite)、再合并到原图下方(feMerge)。这是 CSS filter: drop-shadow() 的手动版本。
<svg width="200" height="120" viewBox="0 0 200 120">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<!-- Offset the source -->
<feOffset in="SourceAlpha" dx="4" dy="4" result="offset"/>
<!-- Blur the offset copy -->
<feGaussianBlur in="offset" stdDeviation="3" result="blur"/>
<!-- Color the shadow -->
<feFlood flood-color="black" flood-opacity="0.5" result="color"/>
<feComposite in="color" in2="blur" operator="in" result="shadow"/>
<!-- Put shadow under the original -->
<feMerge>
<feMergeNode in="shadow"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<rect x="20" y="20" width="80" height="60" fill="white"
filter="url(#shadow)"/>
</svg>feColorMatrix
<feColorMatrix> 应用一个 5x4 矩阵变换 RGBA 通道。type='matrix' 用自定义值;type='saturate' 和 type='hueRotate' 是便捷快捷方式。这是棕褐、灰度和调色效果的基础构件。
<!-- Modern browsers: use CSS filter instead of SVG filter -->
<svg width="200" height="100" viewBox="0 0 200 100">
<rect x="50" y="20" width="100" height="60" fill="white"
style="filter: drop-shadow(4px 4px 4px rgba(0,0,0,0.5));"/>
</svg>
<!-- In CSS -->
<style>
.shadowed { filter: drop-shadow(0 0 10px rgba(0,0,0,0.3)); }
</style>
<!-- CSS drop-shadow follows the shape's alpha, unlike box-shadow -->
<!-- which only shadows the bounding box -->feMerge 与 feOffset
<feMerge> 把滤镜结果叠放在一起(后节点渲染在上)。命名结果(result='blur')在原语间传递数据。重复模糊节点增强辉光。结合亮色文本可产生霓虹效果。
<svg width="200" height="100" viewBox="0 0 200 100">
<defs>
<!-- Convert to grayscale -->
<filter id="grayscale">
<feColorMatrix type="matrix"
values="0.33 0.33 0.33 0 0
0.33 0.33 0.33 0 0
0.33 0.33 0.33 0 0
0 0 0 1 0"/>
</filter>
<!-- Built-in saturation -->
<filter id="desaturate">
<feColorMatrix type="saturate" values="0"/>
</filter>
</defs>
<image href="photo.jpg" width="100" height="100" filter="url(#grayscale)"/>
<image href="photo.jpg" x="100" width="100" height="100" filter="url(#desaturate)"/>
</svg>feOffset
<feOffset> 只是按 dx/dy 偏移输入。单独使用产生重影;结合模糊和合并形成阴影。它常是阴影滤镜链中的第一个原语。
<svg width="200" height="120" viewBox="0 0 200 120">
<defs>
<filter id="emboss">
<!-- Create a height map from the alpha -->
<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/>
<!-- Lighting from upper-left -->
<feSpecularLighting in="blur" surfaceScale="5"
specularConstant="0.8" specularExponent="20"
lighting-color="white" result="spec">
<fePointLight x="-50" y="-50" z="200"/>
</feSpecularLighting>
<feComposite in="spec" in2="SourceGraphic"
operator="in" result="lit"/>
<feComposite in="SourceGraphic" in2="lit" operator="arithmetic"
k1="0" k2="1" k3="1" k4="0"/>
</filter>
</defs>
<text x="10" y="70" font-size="48" font-weight="bold"
fill="gray" filter="url(#emboss)">3D</text>
</svg>滤镜组合
逼真效果链接多个原语:模糊 alpha、偏移、通过 feFlood+feComposite 上色、再把结果合并到原图下方。每个原语的结果通过 result/in 属性喂给下一个。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- feTurbulence generates Perlin noise -->
<filter id="noise" x="0" y="0" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.65"
numOctaves="3" stitchTiles="stitch"/>
<feColorMatrix type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
</filter>
</defs>
<rect width="200" height="200" fill="steelblue"/>
<rect width="200" height="200" filter="url(#noise)"/>
<!-- type: "fractalNoise" or "turbulence" -->
<!-- baseFrequency: lower = larger blobs, higher = finer grain -->
<!-- numOctaves: more = more detail (slower) -->
</svg>变换
translate
translate(tx, ty) 按 (tx, ty) 移动元素。y 参数默认为 0。这是最简单的变换,常用于定位 defs 中的可复用形状。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- A clip path: only the inside is visible -->
<clipPath id="circleClip">
<circle cx="100" cy="100" r="80"/>
</clipPath>
</defs>
<!-- The image is clipped to the circle -->
<rect width="200" height="200" fill="steelblue"
clip-path="url(#circleClip)"/>
<!-- Any shape can be a clip path -->
<clipPath id="textClip">
<text x="100" y="120" font-size="80" text-anchor="middle"
font-weight="bold">SVG</text>
</clipPath>
<rect width="200" height="200" fill="gold" clip-path="url(#textClip)"/>
</svg>rotate
rotate(angle, cx, cy) 绕 (cx, cy) 顺时针旋转 angle 度。不带 cx/cy 时绕原点 (0,0) 旋转——通常不是你想要的,所以总要用用户单位指定中心点。
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<!-- A mask: white = visible, black = hidden, gray = partial -->
<mask id="fadeMask">
<linearGradient id="fadeGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="white"/>
<stop offset="1" stop-color="black"/>
</linearGradient>
<rect width="200" height="200" fill="url(#fadeGrad)"/>
</mask>
</defs>
<!-- The image fades from top to bottom -->
<rect width="200" height="200" fill="red" mask="url(#fadeMask)"/>
</svg>scale
scale(sx, sy) 缩放元素。sy 默认等于 sx(等比缩放)。>1 放大,0 到 1 之间缩小,负值翻转(镜像)。缩放绕原点 (0,0) 进行,需要时先平移。
<svg width="300" height="100" viewBox="0 0 300 100">
<defs>
<!-- userSpaceOnUse (default): clip coords in SVG units -->
<clipPath id="clip1" clipPathUnits="userSpaceOnUse">
<rect x="10" y="10" width="50" height="50"/>
</clipPath>
<!-- objectBoundingBox: coords are 0-1 relative to the element -->
<clipPath id="clip2" clipPathUnits="objectBoundingBox">
<rect x="0.1" y="0.1" width="0.8" height="0.8"/>
</clipPath>
</defs>
<rect width="100" height="100" fill="red" clip-path="url(#clip1)"/>
<rect x="100" width="100" height="80" fill="blue" clip-path="url(#clip2)"/>
<rect x="200" width="100" height="60" fill="green" clip-path="url(#clip2)"/>
</svg>skewX 与 skewY
skewX(angle) 沿 x 轴倾斜(竖线倾斜),skewY(angle) 沿 y 轴倾斜。结合 translate 可创建仿 3D 和等距效果。角度单位为度。
<style>
/* CSS clip-path works on SVG and HTML elements */
.circle {
clip-path: circle(50% at 50% 50%);
}
.triangle {
clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
}
/* Reference an SVG clipPath */
.svg-clip {
clip-path: url(#myClip);
}
</style>
<svg width="200" height="100">
<defs>
<clipPath id="myClip">
<circle cx="50" cy="50" r="40"/>
</clipPath>
</defs>
<rect class="svg-clip" width="200" height="100" fill="purple"/>
</svg>matrix
matrix(a b c d e f) 是原始 2D 仿射变换。translate/scale/rotate/skew 都是编译为矩阵的便捷写法。当你外部计算了变换或需要精确控制全部六个值时使用 matrix。
<svg width="400" height="120" viewBox="0 0 400 120">
<defs>
<clipPath id="textShape">
<text x="200" y="90" font-size="80" font-weight="900"
text-anchor="middle" font-family="Arial">SUMMER</text>
</clipPath>
</defs>
<!-- Background (visible only through the text) -->
<rect width="400" height="120" fill="black"/>
<!-- Image clipped to the text shape -->
<rect width="400" height="120" fill="url(#sunsetGrad)"
clip-path="url(#textShape)"/>
<linearGradient id="sunsetGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#ff6b6b"/>
<stop offset="0.5" stop-color="#feca57"/>
<stop offset="1" stop-color="#ff9ff3"/>
</linearGradient>
</svg>动画
SMIL animate
<animate> 随时间动画化一个属性。设置 attributeName、from/to(或 values 列表)、dur 和 repeatCount。SMIL 是声明式的,除 IE/旧 Edge 外所有浏览器都支持。现代 Chrome/Firefox/Safari 完全支持。
<svg width="200" height="100" viewBox="0 0 200 100">
<rect x="0" y="40" width="20" height="20" fill="red">
<animate attributeName="x"
from="0" to="180"
dur="2s"
repeatCount="indefinite"/>
</rect>
<!-- The rect moves from x=0 to x=180 over 2 seconds, forever -->
</svg>animateTransform
<animateTransform> 动画化 transform 属性。type 选择 translate/rotate/scale/skewX/skewY。用 additive='sum' 叠加多个变换动画——否则每个都会替换前一个。
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="80" y="80" width="40" height="40" fill="blue">
<animateTransform attributeName="transform"
type="rotate"
from="0 100 100" to="360 100 100"
dur="3s"
repeatCount="indefinite"/>
</rect>
<!-- type can be: rotate, scale, translate, skewX, skewY -->
<!-- For rotate, the values are "angle cx cy" -->
</svg>animateMotion
<animateMotion> 让元素沿 <mpath> 引用的 <path> 移动。非常适合沿曲线路径运动的对象。animateMotion 上设 rotate='auto' 还会让元素朝运动方向定向。
<svg width="200" height="150" viewBox="0 0 200 150">
<defs>
<path id="motionPath" d="M 10 75 Q 100 0, 190 75" fill="none"/>
</defs>
<!-- A circle follows the path -->
<circle r="10" fill="red">
<animateMotion dur="3s" repeatCount="indefinite">
<mpath href="#motionPath"/>
</animateMotion>
</circle>
<!-- Show the path for reference -->
<use href="#motionPath" stroke="gray" stroke-width="1"/>
<!-- rotate="auto" makes the element face the direction of motion -->
<circle r="5" fill="blue">
<animateMotion dur="3s" repeatCount="indefinite" rotate="auto">
<mpath href="#motionPath"/>
</animateMotion>
</circle>
</svg>CSS 动画
标准 CSS 动画和过渡适用于 SVG 元素。用用户单位设置 transform-origin 让旋转/缩放枢轴正确。CSS 动画比 SMIL 更熟悉,并与其余样式集成。
<svg width="200" height="100" viewBox="0 0 200 100">
<rect x="0" y="40" width="20" height="20" fill="green">
<animate attributeName="x"
values="0; 80; 180; 80; 0"
keyTimes="0; 0.25; 0.5; 0.75; 1"
keySplines="0.5 0 0.5 1; 0 0 1 1; 0.5 0 0.5 1; 0 0 1 1"
calcMode="spline"
dur="4s"
repeatCount="indefinite"/>
</rect>
<!-- values: the animated values at each keyTime -->
<!-- keyTimes: 0-1 fractions of dur (semicolon-separated) -->
<!-- keySplines: cubic-bezier easing between each pair -->
<!-- calcMode: "discrete", "linear", "paced", or "spline" -->
</svg>CSS 过渡
CSS 过渡在 :hover 等状态变化时动画化 SVG 属性。常见可动画属性:fill、stroke、opacity、transform、r、cx、cy。在文本标签上设 pointer-events='none' 以免阻挡下方形状的悬停。
<svg width="200" height="100" viewBox="0 0 200 100">
<!-- begin: when to start (time or event) -->
<rect x="10" y="10" width="30" height="30" fill="red">
<animate attributeName="width" from="30" to="100"
dur="1s" begin="2s" fill="freeze"/>
</rect>
<!-- begin on a click event -->
<rect x="10" y="60" width="30" height="30" fill="blue" id="trigger">
<animate attributeName="x" from="10" to="150"
dur="1s" begin="click" fill="freeze"/>
</rect>
<!-- begin when another animation ends -->
<rect x="10" y="80" width="30" height="10" fill="green">
<animate attributeName="x" from="10" to="150"
dur="1s" begin="trigger.click+1s" fill="freeze"/>
</rect>
</svg>begin 与 end 事件
begin 和 end 可以是时间('2s')、事件('elemId.click'、'elemId.mouseenter')或 syncbase 值('otherAnim.end')。fill='freeze' 保持最终值而非弹回。这让 SMIL 无需 JavaScript 即可相当交互。
<svg width="200" height="100" viewBox="0 0 200 100">
<style>
.pulse {
animation: pulse 1.5s ease-in-out infinite;
transform-origin: center;
transform-box: fill-box;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.2); opacity: 0.7; }
}
</style>
<circle class="pulse" cx="100" cy="50" r="20" fill="red"/>
</svg>
<!-- CSS animations are more maintainable for web pages -->
<!-- SMIL is better for standalone .svg files -->符号与复用
defs
<defs> 存放可复用元素(渐变、图案、形状、符号),它们在被 <use> 或 url(#id) 引用前不渲染。它相当于 SVG 的 CSS 变量/模板片段。
<svg width="200" height="100" viewBox="0 0 200 100">
<rect id="box" x="10" y="10" width="80" height="80" fill="steelblue"/>
<script>
var box = document.getElementById("box");
box.addEventListener("click", function (e) {
alert("Clicked at " + e.clientX + "," + e.clientY);
});
box.addEventListener("mouseenter", function () {
this.setAttribute("fill", "tomato");
});
box.addEventListener("mouseleave", function () {
this.setAttribute("fill", "steelblue");
});
</script>
</svg>symbol
<symbol> 类似 <g>,但有自己的 viewBox 且从不直接渲染。<use> 把符号缩放到 use 的 width/height——非常适合一处定义、任意尺寸渲染的图标系统。
<svg width="200" height="200" viewBox="0 0 200 200">
<circle id="touch" cx="100" cy="100" r="30" fill="purple"/>
<script>
var circle = document.getElementById("touch");
circle.addEventListener("touchstart", function (e) {
e.preventDefault(); // prevent scrolling
this.setAttribute("fill", "orange");
});
circle.addEventListener("touchend", function () {
this.setAttribute("fill", "purple");
});
// touchmove for dragging
circle.addEventListener("touchmove", function (e) {
var touch = e.touches[0];
var pt = svg.createSVGPoint();
pt.x = touch.clientX; pt.y = touch.clientY;
var svgP = pt.matrixTransform(svg.getScreenCTM().inverse());
this.setAttribute("cx", svgP.x);
this.setAttribute("cy", svgP.y);
});
</script>
</svg>use
<use> 通过引用克隆任何元素(<g>、<rect>、<symbol>)。克隆继承你在 <use> 上设置的属性(x、y、transform、opacity)。一处源头、多处实例——改原版所有克隆都更新。
<svg width="500" height="300" viewBox="0 0 1000 600" id="mysvg">
<rect width="1000" height="600" fill="lightblue"/>
<script>
var svg = document.getElementById("mysvg");
svg.addEventListener("click", function (e) {
// Convert screen (clientX/Y) to SVG user coordinates
var pt = svg.createSVGPoint();
pt.x = e.clientX;
pt.y = e.clientY;
// getScreenCTM maps SVG coords to screen; inverse maps back
var svgPoint = pt.matrixTransform(
svg.getScreenCTM().inverse()
);
console.log("SVG coords:", svgPoint.x, svgPoint.y);
// This accounts for viewBox scaling and CSS sizing
});
</script>
</svg>use 与 href
直接用 href(SVG 2)替代已弃用的 xlink:href。<use> 克隆可在原版用 fill='currentColor' 时重新着色——在 <use> 上设置 CSS color 属性即可为每个实例单独配色。
<svg width="300" height="100" viewBox="0 0 300 100">
<g id="shapes">
<circle cx="50" cy="50" r="30" fill="red" data-name="circle1"/>
<rect x="100" y="20" width="60" height="60" fill="blue" data-name="rect1"/>
<polygon points="220,20 280,20 250,80" fill="green" data-name="tri1"/>
</g>
<script>
// One listener on the parent group handles all children
document.getElementById("shapes").addEventListener("click", function (e) {
var target = e.target;
var name = target.getAttribute("data-name");
console.log("Clicked:", name, target.tagName);
// e.target is the actual shape; e.currentTarget is the group
});
</script>
</svg>嵌套 svg
<svg> 可嵌套在另一个 <svg> 内。每个嵌套 svg 通过 x/y/width/height 和自己的 viewBox 创建自己的视口与坐标系。适合并排放置自包含场景。
<svg width="400" height="300" viewBox="0 0 400 300" id="canvas">
<circle id="draggable" cx="200" cy="150" r="30" fill="orange" cursor="grab"/>
<script>
var circle = document.getElementById("draggable");
var svg = document.getElementById("canvas");
var dragging = false;
function getSVGPoint(e) {
var pt = svg.createSVGPoint();
pt.x = e.clientX; pt.y = e.clientY;
return pt.matrixTransform(svg.getScreenCTM().inverse());
}
circle.addEventListener("mousedown", function () {
dragging = true;
this.setAttribute("cursor", "grabbing");
});
svg.addEventListener("mousemove", function (e) {
if (!dragging) return;
var p = getSVGPoint(e);
circle.setAttribute("cx", p.x);
circle.setAttribute("cy", p.y);
});
svg.addEventListener("mouseup", function () {
dragging = false;
circle.setAttribute("cursor", "grab");
});
</script>
</svg>HTML 中的 SVG
内联 SVG
内联 SVG 把标记直接嵌入 HTML。SVG 是 DOM 的一部分,所以 CSS 和 JavaScript 可针对其各部分。最适合图标和交互图形;静态图建议用 <img> 保持 HTML 简洁。
<svg id="canvas" width="200" height="200" viewBox="0 0 200 200">
<script>
var svg = document.getElementById("canvas");
var NS = "http://www.w3.org/2000/svg";
// createElementNS is required for SVG elements
var circle = document.createElementNS(NS, "circle");
circle.setAttribute("cx", "100");
circle.setAttribute("cy", "100");
circle.setAttribute("r", "50");
circle.setAttribute("fill", "red");
svg.appendChild(circle);
// Create a path
var path = document.createElementNS(NS, "path");
path.setAttribute("d", "M 10 10 L 100 100");
path.setAttribute("stroke", "black");
svg.appendChild(path);
</script>
</svg>object 标签
<object> 把外部 SVG 作为独立文档加载。SVG 保留自己的脚本并可缓存。<object> 内的回退(img 或文本)在不支持 SVG 时显示。是内联与 img 之间的良好折中。
<svg width="200" height="100" viewBox="0 0 200 100">
<rect id="r" x="10" y="10" width="50" height="50" fill="blue"/>
<script>
var r = document.getElementById("r");
// Change attributes
r.setAttribute("fill", "red");
r.setAttribute("width", "80");
// Get attribute values
var w = r.getAttribute("width"); // "80"
// Remove attributes
r.removeAttribute("fill");
// Class manipulation (use classList, not className for SVG in some browsers)
r.classList.add("highlight");
r.classList.toggle("active");
// Style (use setAttribute for presentation attributes)
r.style.fill = "green"; // works via CSS
</script>
</svg>img 标签
<img> 是嵌入 SVG 最简单的方式。它会被缓存并尊重 width/height,但 SVG 被沙箱化:无外部 CSS、无 JavaScript、无内部交互。用于自包含的静态图形如徽标。
<svg width="200" height="100" viewBox="0 0 200 100">
<rect id="r" x="10" y="10" width="80" height="50" fill="blue"/>
<script>
var r = document.getElementById("r");
// Get bounding box in SVG user units
var bbox = r.getBBox();
console.log(bbox.x, bbox.y, bbox.width, bbox.height);
// Get bounding box in screen coordinates (after transforms)
var cbox = r.getBoundingClientRect();
console.log(cbox.left, cbox.top, cbox.width, cbox.height);
// Total length of a path or line
var path = document.querySelector("path");
var len = path.getTotalLength();
var point = path.getPointAtLength(len / 2); // midpoint
</script>
</svg>embed 与 iframe
<embed> 和 <iframe> 都加载外部 SVG。<iframe> 创建独立文档上下文(便于隔离,但多实例开销大)。<embed> 更短但已过时。新代码优先用 <object> 或 <img>。
<svg width="200" height="100" viewBox="0 0 200 100">
<circle cx="50" cy="50" r="20" fill="red"
data-id="123" data-label="node"/>
<script>
var circle = document.querySelector("circle");
// dataset reads data-* attributes
console.log(circle.dataset.id); // "123"
console.log(circle.dataset.label); // "node"
// Set data attributes
circle.dataset.selected = "true"; // adds data-selected="true"
// Use for storing state
circle.dataset.visits = "0";
circle.dataset.visits = String(+circle.dataset.visits + 1);
</script>
</svg>data URI
SVG 可作为 data URI 嵌入 <img>、CSS 背景等。URL 编码(用 %3C 等)比 base64 更紧凑。data URI 要小——过大会使 CSS 臃肿且难维护。
<svg width="300" height="150" viewBox="0 0 300 150" id="chart">
<script>
var NS = "http://www.w3.org/2000/svg";
var svg = document.getElementById("chart");
var data = [10, 50, 30, 80, 45, 90, 25];
// Build a path string from data points
var d = "M 0 " + (150 - data[0]);
for (var i = 1; i < data.length; i++) {
d += " L " + (i * 40) + " " + (150 - data[i]);
}
var path = document.createElementNS(NS, "path");
path.setAttribute("d", d);
path.setAttribute("fill", "none");
path.setAttribute("stroke", "steelblue");
path.setAttribute("stroke-width", "2");
svg.appendChild(path);
// Add dots at each point
data.forEach(function (val, i) {
var c = document.createElementNS(NS, "circle");
c.setAttribute("cx", i * 40);
c.setAttribute("cy", 150 - val);
c.setAttribute("r", 3);
c.setAttribute("fill", "red");
svg.appendChild(c);
});
</script>
</svg>background-image(CSS)
SVG 可用于 CSS background-image,由 background-size 控制缩放。非常适合装饰图案和徽标。CSS 中的内联 data-URI SVG 对不值得单独文件的小形状很方便。
<script>
// Batch DOM operations with document fragments
var fragment = document.createDocumentFragment();
for (var i = 0; i < 1000; i++) {
var c = document.createElementNS(NS, "circle");
c.setAttribute("cx", i);
c.setAttribute("cy", 50);
c.setAttribute("r", 2);
fragment.appendChild(c);
}
svg.appendChild(fragment); // one reflow, not 1000
// Use requestAnimationFrame for animations
function animate() {
element.setAttribute("cx", +element.getAttribute("cx") + 1);
requestAnimationFrame(animate);
}
animate();
// For many elements, consider <canvas> instead (faster)
// SVG slows down with thousands of nodes due to DOM overhead
</script>响应式 SVG
viewBox 响应式
响应式 SVG 应省略 width/height 属性,让 CSS 控制元素尺寸。viewBox 保持内部坐标系稳定,使绘图流畅缩放。display:block 防止内联空白间隙。
<!-- viewBox="minX minY width height" -->
<svg viewBox="0 0 100 100" width="200" height="200">
<!-- A circle at center of a 100x100 coordinate system -->
<circle cx="50" cy="50" r="50" fill="blue"/>
</svg>
<!-- viewBox shifts the visible area -->
<svg viewBox="50 50 50 50" width="200" height="200">
<!-- Now showing only the bottom-right quadrant -->
<!-- The same circle, but zoomed in 2x on that corner -->
<circle cx="50" cy="50" r="50" fill="blue"/>
</svg>width 100%
width:100%; height:auto 让 SVG 填满容器宽度同时保持宽高比。preserveAspectRatio='xMidYMid meet'(默认)保持绘图居中且不变形,需要时会有信箱边。
<!-- Default: preserve aspect ratio, center, letterbox -->
<svg viewBox="0 0 100 50" width="200" height="200"
preserveAspectRatio="xMidYMid meet">
<rect width="100" height="50" fill="blue"/>
</svg>
<!-- "slice": fill entirely, crop overflow -->
<svg viewBox="0 0 100 50" width="200" height="200"
preserveAspectRatio="xMidYMid slice">
<rect width="100" height="50" fill="red"/>
</svg>
<!-- "none": stretch to fill (distorts) -->
<svg viewBox="0 0 100 50" width="200" height="200"
preserveAspectRatio="none">
<rect width="100" height="50" fill="green"/>
</svg>meet 与 slice
'meet' 把整个 viewBox 放入视口,宽高比不一致时留空边。'slice' 完全覆盖视口并裁剪溢出。要展示完整绘图选 meet;要填充主图选 slice。
<!-- Omit width/height, set viewBox, use CSS to size -->
<svg viewBox="0 0 100 100" style="width: 100%; height: auto; display: block;">
<circle cx="50" cy="50" r="50" fill="orange"/>
</svg>
<!-- In a container with max-width -->
<div style="max-width: 500px; margin: auto;">
<svg viewBox="0 0 400 300" style="width: 100%; height: auto;">
<rect width="400" height="300" fill="steelblue"/>
</svg>
</div>CSS aspect-ratio
CSS aspect-ratio 锁定 SVG 容器的形状,无论宽度如何,使 SVG 填满其框而不变形。结合 viewBox 可在任何尺寸清晰缩放。这是 padding-bottom hack 的现代替代。
<svg width="300" height="200" viewBox="0 0 300 200">
<!-- Nested SVG creates a new viewport -->
<svg x="10" y="10" width="100" height="100" viewBox="0 0 50 50">
<circle cx="25" cy="25" r="25" fill="red"/>
</svg>
<!-- overflow="hidden" (default) clips content outside -->
<svg x="120" y="10" width="100" height="100" viewBox="0 0 50 50"
overflow="visible">
<circle cx="25" cy="25" r="30" fill="blue"/>
</svg>
<!-- Each nested svg can have its own preserveAspectRatio -->
<svg x="230" y="10" width="60" height="100" viewBox="0 0 50 50"
preserveAspectRatio="xMidYMid slice">
<circle cx="25" cy="25" r="25" fill="green"/>
</svg>
</svg>媒体查询适配
SVG 内的 CSS 响应媒体查询——但它们针对 SVG 自身视口尺寸(内联在 HTML 中时为页面视口)。可用于小屏隐藏标签、简化描边,或尊重 prefers-reduced-motion。
<svg viewBox="0 0 400 100" style="width:100%;height:auto;">
<style>
/* Use viewBox units for font-size — scales with the SVG */
text { font-size: 20px; }
/* Note: 'px' here means SVG user units, not CSS px */
</style>
<text x="200" y="50" text-anchor="middle">Scales with SVG</text>
</svg>
<!-- For truly responsive text relative to viewport, use CSS: -->
<svg viewBox="0 0 400 100" style="width:100%;height:auto;">
<text x="200" y="50" text-anchor="middle"
style="font-size: 5vw;">5% of viewport width</text>
</svg>
<!-- Or use container queries / media queries on the SVG element -->Aspect Ratio Control
Combine CSS aspect-ratio on the container with width/height 100% on the SVG for predictable responsive behavior. This prevents layout shift (CLS) by reserving space before the SVG loads. The viewBox matches the aspect ratio so content isn't distorted. This is the modern best practice for responsive SVG embeds.
<!-- Use CSS aspect-ratio for consistent sizing -->
<div style="width: 100%; max-width: 600px; aspect-ratio: 16/9;">
<svg viewBox="0 0 1600 900" style="width:100%;height:100%;">
<rect width="1600" height="900" fill="black"/>
<text x="800" y="450" text-anchor="middle" dominant-baseline="middle"
fill="white" font-size="48">16:9 Container</text>
</svg>
</div>
<!-- aspect-ratio ensures the container keeps proportions -->
<!-- even before the SVG loads, preventing layout shift -->SVG 与 CSS
通过 CSS 设置填充与描边
fill、stroke、stroke-width 等都是 CSS 属性——可像 HTML 一样用 class 定位 SVG 元素。这比重复属性更干净,并可在多个 SVG 间共享设计系统调色板。
<!-- SVG: retained mode (DOM-based) -->
<svg width="200" height="100">
<circle cx="50" cy="50" r="30" fill="red"/>
<!-- Each element is a DOM node, accessible via JS -->
</svg>
<!-- Canvas: immediate mode (pixel-based) -->
<canvas id="c" width="200" height="100"></canvas>
<script>
var ctx = document.getElementById("c").getContext("2d");
ctx.beginPath();
ctx.arc(50, 50, 30, 0, Math.PI * 2);
ctx.fillStyle = "red";
ctx.fill();
// Pixels are drawn; the circle isn't an object anymore
</script>currentColor
currentColor 让 SVG 元素继承周围文本颜色。在 SVG(或父元素)上设置 CSS color 属性即可一次性给所有 currentColor 填充/描边配色。这是单色图标配色的基础。
<!-- SVG is ideal for:
- Icons and logos (crisp at any size)
- Charts with few elements (D3.js)
- Interactive diagrams (clickable shapes)
- Illustrations with editable layers
- Accessibility-required graphics
-->
<svg viewBox="0 0 24 24" width="48" height="48">
<path d="M12 2 L2 22 H22 Z" fill="triangle"/>
</svg>
<!-- Stays sharp whether displayed at 16px or 1024px -->
<!-- Each part can have its own click handler -->
<!-- Screen readers can access <title> and <desc> -->CSS 变量
CSS 自定义属性(--var)在 SVG 中有效。带回退定义它们(var(--badge-bg, #3b82f6)),可从层叠任意位置覆盖——甚至从父 HTML 元素。无需改动 SVG 标记即可运行时换肤。
<!-- Canvas is ideal for:
- Games (hundreds of sprites per frame)
- Particle systems
- Real-time image processing
- Heatmaps with thousands of cells
- Physics simulations
-->
<canvas id="particles" width="800" height="600"></canvas>
<script>
var ctx = document.getElementById("particles").getContext("2d");
var particles = [];
for (var i = 0; i < 5000; i++) {
particles.push({ x: Math.random()*800, y: Math.random()*600 });
}
function draw() {
ctx.clearRect(0, 0, 800, 600);
particles.forEach(function (p) {
ctx.fillRect(p.x, p.y, 2, 2);
});
requestAnimationFrame(draw);
}
draw();
</script>:hover 效果
:hover、:focus、:active 适用于 SVG 元素。结合 CSS 过渡可实现平滑反馈。兄弟选择器(+、~)可在相关形状悬停时为标签设置样式。
<!-- SVG DOM overhead grows with element count -->
<!-- 100 circles: SVG ~0.1ms, Canvas ~0.1ms (both fine) -->
<!-- 1000 circles: SVG ~10ms, Canvas ~1ms (Canvas pulls ahead) -->
<!-- 10000 circles: SVG ~500ms+, Canvas ~10ms (SVG struggles) -->
<!-- SVG advantages:
- No redraw needed for CSS changes (browser handles it)
- Hardware-accelerated transforms
- Only changed elements re-render (incremental)
-->
<!-- Canvas advantages:
- Constant redraw cost regardless of history
- No DOM memory overhead per shape
- Direct pixel access (getImageData, putImageData)
-->外部样式表
独立 .svg 文件可用 <?xml-stylesheet?> 链接外部样式表。这把表现移出标记,但仅在 SVG 直接加载时有效(通过 <img> 加载会被沙箱化)。
<!-- SVG for UI chrome, Canvas for dense content -->
<div style="position:relative; width:800px; height:600px;">
<!-- Canvas renders the heatmap (fast for thousands of cells) -->
<canvas width="800" height="600" style="position:absolute; top:0; left:0;">
</canvas>
<!-- SVG overlay for interactive tooltips and selection -->
<svg width="800" height="600" viewBox="0 0 800 600"
style="position:absolute; top:0; left:0;">
<g id="overlay"></g>
</svg>
</div>
<script>
// Draw heatmap on canvas (performant)
// Add hover tooltips as SVG elements (accessible, styled)
</script>内联 <style> 作用域
当 SVG 内联在 HTML 中时,其 <style> 规则加入全局样式表,可能泄漏到其他 SVG。用包装类(如 .my-chart .bar)限定规则以保持隔离。独立 .svg 文件本身已隔离。
<!-- SVG: screen readers traverse the DOM -->
<svg role="img" aria-label="Sales chart showing 20% growth">
<title>Sales Chart</title>
<desc>Bar chart with 5 quarters, Q3 highest at $2M</desc>
<rect .../> <!-- each bar is a DOM element -->
</svg>
<!-- Text in SVG is selectable and searchable -->
<!-- Canvas: just pixels to a screen reader -->
<canvas role="img" aria-label="Sales chart showing 20% growth">
<!-- Must provide text fallback inside the canvas tag -->
Sales chart: Q1 $1M, Q2 $1.3M, Q3 $2M, Q4 $1.8M
</canvas>
<!-- No DOM, no selectable text, harder to make accessible -->SVG 与 JavaScript
createElementNS
SVG 元素必须用 document.createElementNS 和 SVG 命名空间创建。用 HTML 的 createElement 会返回渲染器忽略的未知元素。把命名空间 URI 放在常量里避免拼写错误。
<!-- Place this hidden SVG at the top of your HTML body -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M12 3 L2 12 H5 V21 H10 V14 H14 V21 H19 V12 H22 Z"/>
</symbol>
<symbol id="icon-user" viewBox="0 0 24 24">
<circle cx="12" cy="8" r="4"/>
<path d="M4 21 C 4 16, 8 14, 12 14 C 16 14, 20 16, 20 21 Z"/>
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
<line x1="16" y1="16" x2="21" y2="21" stroke="currentColor" stroke-width="2"/>
</symbol>
</svg>setAttribute
setAttribute 对所有 SVG 属性接受字符串值。数值属性在内部转为字符串。有些(x、y、width、height)也通过 .baseVal.value 暴露 IDL 属性,但 setAttribute 更简单且普遍支持。
<!-- Reference any icon with <use> -->
<svg class="icon"><use href="#icon-home"/></svg>
<svg class="icon"><use href="#icon-user"/></svg>
<svg class="icon icon-large"><use href="#icon-search"/></svg>
<style>
.icon {
width: 24px;
height: 24px;
fill: currentColor; /* inherits text color */
display: inline-block;
vertical-align: middle;
}
.icon-large { width: 48px; height: 48px; }
</style>
<!-- Color via CSS color (because fill="currentColor") -->
<button style="color: red;">
<svg class="icon"><use href="#icon-home"/></svg> Home
</button>事件监听器
SVG 元素支持标准鼠标/触摸/键盘事件。要把鼠标坐标从屏幕像素转换到 SVG 用户坐标系,用 createSVGPoint + getScreenCTM().inverse()——这会考虑所有变换和 viewBox 缩放。
<!-- icons.svg (a separate file) -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-home" viewBox="0 0 24 24">...</symbol>
</svg>
<!-- Reference external symbols (limited browser support) -->
<svg class="icon"><use href="icons.svg#icon-home"/></svg>
<!-- More reliable: fetch and inject the sprite -->
<script>
fetch("icons.svg")
.then(r => r.text())
.then(text => {
var div = document.createElement("div");
div.style.display = "none";
div.innerHTML = text;
document.body.insertBefore(div, document.body.firstChild);
});
</script>getElementById 与 querySelector
内联 SVG 是 HTML DOM 的一部分,所以 getElementById 和 querySelector 正常工作。通过 <object> 加载的 SVG,先用 objectElement.contentDocument 访问内部文档再查询。data-* 属性与 HTML 一样。
<!-- Using svg-sprite-loader (webpack) -->
// import all icons in a folder
const req = require.context("./icons", true, /\.svg$/);
req.keys().forEach(req);
// In your component:
<svg class="icon"><use href="#icon-home"/></svg>
<!-- Using gulp-svg-sprite -->
// gulpfile.js
const svgSprite = require("gulp-svg-sprite");
gulp.task("sprite", () =>
gulp.src("icons/*.svg")
.pipe(svgSprite({ mode: { symbol: { dest: "." } } }))
.pipe(gulp.dest("dist"))
);
// Outputs dist/symbol/svg/sprite.symbol.svg用 JS 做动画
requestAnimationFrame 是从 JavaScript 驱动 SVG 动画的正确方式。在 rAF 循环内设置属性(r、cx、transform)。对 transform,优先用 setAttribute 以避免 SVG 上 CSS transform-origin 的怪异行为。
<!-- Decorative icon (hidden from screen readers) -->
<svg class="icon" aria-hidden="true">
<use href="#icon-decoration"/>
</svg>
<!-- Meaningful icon (with label) -->
<svg class="icon" role="img" aria-label="Home">
<use href="#icon-home"/>
</svg>
<!-- Icon button with visible text (icon is decorative) -->
<button>
<svg class="icon" aria-hidden="true"><use href="#icon-home"/></svg>
<span>Home</span>
</button>
<!-- Icon-only button (needs aria-label on the button) -->
<button aria-label="Search">
<svg class="icon" aria-hidden="true"><use href="#icon-search"/></svg>
</button>用模板字面量生成 SVG
模板字面量便于从数据生成 SVG 标记。结果字符串可通过 innerHTML 注入。注意:这样做时要转义任何用户控制的文本以防止 SVG 注入(标签用 textContent,或转义 <、>、&)。
<svg style="display:none">
<!-- Icon with two fill regions -->
<symbol id="icon-mail" viewBox="0 0 24 24">
<rect x="2" y="4" width="20" height="16" rx="2" fill="currentColor"/>
<path d="M2 6 L12 13 L22 6" fill="white"/>
</symbol>
</svg>
<!-- Override individual parts via CSS (limited: works if the
symbol uses currentColor and CSS variables) -->
<svg class="icon" style="color: steelblue;">
<use href="#icon-mail"/>
</svg>
<!-- For full multi-color control, use CSS custom properties -->
<symbol id="icon-alert" viewBox="0 0 24 24">
<path fill="var(--icon-bg, currentColor)" d="M12 2 L2 22 H22 Z"/>
<text x="12" y="18" text-anchor="middle" fill="var(--icon-fg, white)">!</text>
</symbol>
<svg class="icon" style="--icon-bg: red; --icon-fg: yellow;">
<use href="#icon-alert"/>
</svg>图标系统
Symbol 雪碧图
把每个图标定义为带自身 viewBox 的 <symbol>,放在一个隐藏 SVG 中,即构建出图标雪碧图。每个 symbol 的 viewBox 让它独立缩放。在页面顶部加载一次雪碧图,然后随处通过 <use> 引用图标。
# Install SVGO globally
npm install -g svgo
# Optimize a single file (overwrites)
svgo icon.svg
# Optimize to a new file
svgo icon.svg -o icon.min.svg
# Optimize a folder
svgo -f icons/ -o icons/min/
# Show available plugins
svgo --show-plugins
# Use a specific config
svgo --config=svgo.config.js icon.svguse 引用
<use href='#id'> 把图标从雪碧图克隆到布局中。外部雪碧图(href='file.svg#id')会被缓存,但跨文件 CSS 样式在各浏览器中不一致。内联雪碧图样式最可靠。
<!-- Before optimization (from Illustrator) -->
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0 -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
width="100px" height="100px" viewBox="0 0 100 100"
enable-background="new 0 0 100 100" xml:space="preserve">
<metadata>...</metadata>
<path d="..." fill="#FF0000" fill-rule="nonzero"/>
</svg>
<!-- After SVGO -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path d="..." fill="red"/>
</svg>currentColor 图标
用 fill='currentColor' 或 stroke='currentColor' 设计图标。它们随后继承所处位置的 CSS color,所以同一图标可在链接中是蓝色、危险按钮中是红色、页脚中是灰色——无需重复定义。
<!-- SVGO can merge and simplify paths -->
<!-- Before: multiple paths with redundant points -->
<g>
<path d="M 10 10 L 20 10 L 20 20 L 10 20 Z" fill="red"/>
<path d="M 10 10 L 20 10 L 20 20 L 10 20 Z" fill="none" stroke="black"/>
</g>
<!-- After: merged into one path with combined commands -->
<path d="M10 10h10v10H10z" fill="red" stroke="black"/>
<!-- Path command shortcuts:
L 20 10 -> h 10 (relative horizontal)
L 10 20 -> v 10 (relative vertical)
Z closes the path
-->图标尺寸
用 width:1em; height:1em 设置图标尺寸,使其随 font-size 缩放并与文本对齐。vertical-align:-0.125em 让它略微下沉以落在文本基线上。固定像素尺寸适合 UI 装饰中的独立图标。
<!-- Before: repeated attributes on each element -->
<svg viewBox="0 0 100 100">
<rect x="10" y="10" width="20" height="20" fill="red" stroke="black" stroke-width="2"/>
<rect x="40" y="10" width="20" height="20" fill="red" stroke="black" stroke-width="2"/>
<rect x="70" y="10" width="20" height="20" fill="red" stroke="black" stroke-width="2"/>
</svg>
<!-- After: group with shared attributes -->
<svg viewBox="0 0 100 100">
<g fill="red" stroke="black" stroke-width="2">
<rect x="10" y="10" width="20" height="20"/>
<rect x="40" y="10" width="20" height="20"/>
<rect x="70" y="10" width="20" height="20"/>
</g>
</svg>无障碍
装饰性图标应有 aria-hidden='true' 和 focusable='false',让屏幕阅读器跳过。有意义的图标需要 role='img' 和一个 <title>,其唯一 id 由 aria-labelledby 引用。纯图标按钮必须有 aria-label。
<!-- SVG is text, so it gzips very well (70-90% reduction) -->
<!-- Ensure your server sends SVG with gzip/brotli compression: -->
<!-- Apache .htaccess -->
AddType image/svg+xml .svg
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE image/svg+xml
</IfModule>
<!-- Nginx -->
# gzip_types image/svg+xml;
<!-- HTML: use the right loading strategy -->
<img src="hero.svg" loading="lazy" decoding="async">
<!-- For above-the-fold critical SVG, inline it to avoid a request -->
<!-- For below-the-fold, use <img loading="lazy"> to defer -->多色图标
多色符号把调色板固化在定义中。运行时换肤时,把硬编码颜色替换为 var(--icon-primary),并在每个 <use> 或其父元素上覆盖变量——一处定义、多套配色。
// svgo.config.js (SVGO 2+)
module.exports = {
multipass: true, // run multiple passes for best result
js2svg: {
indent: 2,
pretty: true, // readable output (false for minified)
},
plugins: [
{ name: "preset-default" }, // sensible defaults
{ name: "removeDimensions", active: true }, // remove width/height (use viewBox)
{ name: "removeViewBox", active: false }, // KEEP viewBox (opposite of default)
{ name: "removeXMLNS", active: false }, // keep xmlns for standalone files
{ name: "cleanupIDs", active: true }, // minify id names
{ name: "mergePaths", active: true },
],
};数据可视化基础
柱状图
柱状图把值映射为 rect 高度。用用户单位把每个柱的 y 算作(基线 - 值)、高度算作值。把坐标轴、网格线、柱和标签放在各自 <g> 中,便于独立设置样式和更新。
<!-- 1. Always include <title> and <desc> for meaningful SVGs -->
<svg role="img" aria-labelledby="title-id desc-id">
<title id="title-id">Annual Revenue Chart</title>
<desc id="desc-id">A bar chart showing revenue from 2019 to 2023,
rising from $1M to $5M.</desc>
<!-- chart content -->
</svg>
<!-- 2. Decorative SVG: hide from screen readers -->
<svg aria-hidden="true" focusable="false">
<!-- purely visual flourish -->
</svg>
<!-- 3. focusable="false" prevents IE/Edge from making SVG focusable -->
<!-- 4. Use role="img" so screen readers treat SVG as a single image -->折线图
折线图是穿过数据点的 <polyline>。把数据值映射到 (x, y) 坐标,然后在 points 属性中列出。在每个点加 <circle> 标记以强调。要平滑曲线则改用带 C 或 Q 命令的 <path>。
<!-- GOOD: viewBox makes the SVG scalable -->
<svg viewBox="0 0 24 24" style="width: 24px; height: 24px;">
<path d="..."/>
</svg>
<!-- BAD: fixed width/height limits scalability -->
<svg width="24" height="24">
<path d="..."/>
</svg>
<!-- For responsive: omit width/height, size with CSS -->
<svg viewBox="0 0 100 100" style="width:100%;height:auto;">
<circle cx="50" cy="50" r="50"/>
</svg>饼图
饼图扇区是路径:M 到圆心,L 到扇区在圆上的起点,A 弧线到扇区终点,Z 闭合。大于 180° 的扇区 large-arc-flag 为 1。环形图用相同路径加一个白色圆盖在上面。
<!-- GOOD: use currentColor so the icon inherits text color -->
<symbol id="icon" viewBox="0 0 24 24">
<path fill="currentColor" d="..."/>
</symbol>
<!-- Usage: color via CSS -->
<button style="color: tomato;">
<svg class="icon"><use href="#icon"/></svg> Themed
</button>
<button style="color: steelblue;">
<svg class="icon"><use href="#icon"/></svg> Also themed
</button>
<!-- BAD: hardcoded colors can't be themed -->
<symbol id="icon">
<path fill="#333333" d="..."/> <!-- always gray -->
</symbol>坐标轴与刻度
坐标轴只是 <line> 元素,刻度是 <line> + <text> 对。刻度标签用 text-anchor='end'(Y 轴)或 'middle'(X 轴),dominant-baseline='middle' 垂直居中。可通过 JS 刻度渲染函数复用。
<svg viewBox="0 0 200 200">
<!-- Group by logical component, not just by shape type -->
<g id="background">
<rect width="200" height="200" fill="#f0f0f0"/>
</g>
<g id="chart-axis">
<line x1="20" y1="180" x2="180" y2="180" stroke="black"/>
<line x1="20" y1="20" x2="20" y2="180" stroke="black"/>
</g>
<g id="chart-data" fill="steelblue">
<rect x="30" y="100" width="20" height="80"/>
<rect x="60" y="60" width="20" height="120"/>
<rect x="90" y="80" width="20" height="100"/>
</g>
<g id="labels" font-size="10" fill="black">
<text x="40" y="195" text-anchor="middle">Q1</text>
<text x="70" y="195" text-anchor="middle">Q2</text>
</g>
</svg>网格线
网格线是数据后方细而低对比度的 <line> 元素。保持它们低调(浅灰、1px),以引导视线而不与数据争夺。在数据之前的 <g> 中绘制,使其位于下层。
<!-- BAD: layered shapes that cover each other (overdraw) -->
<g>
<rect width="100" height="100" fill="red"/>
<rect width="100" height="100" fill="blue"/> <!-- covers red -->
<rect width="100" height="100" fill="green"/> <!-- covers blue -->
</g>
<!-- The red and blue are never visible but still rendered -->
<!-- GOOD: only draw what's visible -->
<rect width="100" height="100" fill="green"/>
<!-- BAD: path with 10,000 points for a simple shape -->
<path d="..."/> <!-- over-tessellated -->
<!-- GOOD: simplify paths; use curves instead of many line segments -->
<path d="M 10 50 Q 50 10, 90 50"/> <!-- one curve vs 100 lines -->标签与图例
标题用顶部醒目的 <text>;图例把一个小色块 <rect> 与标签 <text> 配对。用一致间距对齐图例条目,并用 text-anchor / dominant-baseline 使其整齐。保持文本在图表最小渲染尺寸下仍清晰可读。
<!-- 1. Validate SVG XML -->
<!-- Use the W3C validator: https://validator.w3.org/ -->
<!-- 2. Test in multiple browsers -->
<!-- Chrome, Firefox, Safari, Edge, (IE if required) -->
<!-- 3. Test at different sizes -->
<div style="width: 16px;"><svg>...</svg></div> <!-- icon -->
<div style="width: 500px;"><svg>...</svg></div> <!-- hero -->
<!-- 4. Test with screen readers (VoiceOver, NVDA) -->
<!-- 5. Check file size after optimization -->
ls -la icon.svg # should be under 2KB for simple icons
<!-- 6. Verify currentColor theming works -->
<!-- 7. Ensure no hardcoded dimensions block responsiveness -->相关 SVG 代码片段
Copy-paste ready code for common tasks.
Basic Shapes
Rect, circle, ellipse, line, polygon, polyline.
Paths
Draw arbitrary curves via the d attribute.
Gradients
Linear and radial color blends.
Transforms
Translate, rotate, scale, and skew groups.
Text
Styled text and tspans.
Filters
Blur, shadow, and other effects.
Animation
SMIL animate, transform, and opacity.
Patterns
Tileable fills defined in defs.
这篇内容对您有帮助吗?