我最近创建了一个砖墙图案作为我的一部分 #PetitePatterns 系列,这是一个挑战,我在 SVG 中创建 560 字节(或大约两条推文大小)的有机外观图案或纹理。 为了适应这个限制,我经历了一段旅程,教会了我一些优化 SVG 模式的激进方法,以便它们包含尽可能少的代码而不影响整体图像质量。
我想引导您完成整个过程,并向您展示我们如何将 SVG 模式从 197 字节开始一直缩减到仅 44 字节——减少了 77.7%!
SVG 模式
这就是所谓的“运行债券”砖模式。 这是最常见的砖图案,而且你肯定见过:每一排砖块的长度为砖块长度的一半,形成重复的交错图案。 安排很简单,制作 SVG 的 <pattern>
element 非常适合在代码中重现它。
SVG <pattern>
element 使用预定义的图形对象,可以沿水平和垂直轴以固定间隔复制(或“平铺”)。 本质上,我们定义了一个矩形瓷砖图案,并重复绘制填充区域。
首先,让我们设置一块砖的尺寸和每块砖之间的间隙。 为了简单起见,让我们使用干净的整数:宽度为 100
高度为 30
对于砖块,和 10
对于它们之间的水平和垂直间隙。
接下来,我们必须确定我们的“基础”图块。 我所说的“瓷砖”是指图案瓷砖而不是物理瓷砖,不要与砖混为一谈。 让我们使用上图中突出显示的部分作为我们的图案瓷砖:第一行有两块整块砖,第二排两块半砖夹在中间。 请注意包含间隙的方式和位置,因为这些间隙需要包含在重复的图案拼贴中。
使用时 <pattern>
,我们必须定义模式的 width
和 height
,它们对应于基础图块的宽度和高度。 为了得到尺寸,我们需要一点数学:
Tile Width = 2(Brick Width) + 2(Gap) = 2(100) + 2(10) = 220
Tile Height = 2(Bright Height) + 2(Gap) = 2(30) + 2(10) = 80
好的,所以我们的图案瓷砖是 220✕80
. 我们还必须设置 patternUnits
属性,其中的值 userSpaceOnUse
本质上是指像素。 最后,添加一个 id
图案是必要的,以便在我们用它绘制另一个元素时可以引用它。
<pattern id="p" width="220" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
既然我们已经确定了图块的尺寸,挑战就是以尽可能少的字节数呈现图形的方式为图块创建代码。 这就是我们希望最终得到的结果:
初始标记(197 字节)
我想到的重新创建这种模式的最简单和最具声明性的方法是绘制五个矩形。 默认情况下, fill
SVG 元素的 是黑色的,并且 stroke
是透明的。 这对于优化 SVG 模式非常有效,因为我们不必在代码中显式声明它们。
下面代码中的每一行都定义了一个矩形。 这 width
和 height
总是设置的,并且 x
和 y
仅当矩形从 0
位置。
<rect width="100" height="30"/>
<rect x="110" width="100" height="30"/>
<rect y="40" width="45" height="30"/>
<rect x="55" y="40" width="100" height="30"/>
<rect x="165" y="40" width="55" height="30"/>
瓷砖的顶行包含两块全宽砖,第二块砖位于 x="110"
允许 10
砖前间隙的像素。 同样有 10
之后的间隙像素,因为砖在 210
像素 (110 + 100 = 210
) 在水平轴上,即使 <pattern>
宽度为 220
像素。 我们需要一点额外的空间; 否则第二块砖将与相邻瓷砖中的第一块砖合并。
第二行(底部)的砖是偏移的,因此该行包含两个半砖和一个整砖。 在这种情况下,我们希望半宽砖合并,因此在开始或结束时没有间隙,允许它们与相邻图案瓷砖中的砖无缝流动。 在抵消这些砖块时,我们还必须包括半间隙,因此 x
价值观是 55
和 165
。
元素重用,(-43B,总共 154B)
如此明确地定义每块砖似乎效率低下。 难道没有办法通过重用形状来优化 SVG 模式吗?
我不认为 SVG 有一个广为人知的 <use>
元素。 您可以使用它引用另一个元素并在任何地方渲染该引用的元素 <use>
用来。 这节省了相当多的字节,因为我们可以省略指定每个砖块的宽度和高度,除了第一个。
也就是说, <use>
确实要付出一点代价。 也就是说,我们必须添加一个 id
对于我们想要重用的元素。
<rect id="b" width="100" height="30"/>
<use href="#b" x="110"/>
<use href="#b" x="-55" y="40"/>
<use href="#b" x="55" y="40"/>
<use href="#b" x="165" y="40"/>
最短的 id
可能是一个字符,所以我选择“b”代表砖。 这 <use>
元素的定位类似于 <rect>
,与 x
和 y
属性作为偏移量。 由于现在我们已经切换到每个砖块都是全宽的 <use>
(请记住,我们明确地将图案瓷砖第二排的砖块减半),我们必须使用负数 x
第二行中的值,然后确保最后一块砖从砖中溢出,以实现砖之间的无缝连接。 不过,这些都可以,因为任何落在图案拼贴之外的东西都会被自动切断。
你能发现一些可以更有效地编写的重复字符串吗? 让我们接下来研究这些。
重写到路径(-54B,总共 100B)
<path>
可能是 SVG 中最强大的元素。 您可以在其中使用“命令”绘制几乎任何形状 d
属性。 有 20 个可用命令,但我们只需要最简单的用于矩形的命令。
这是我登陆的地方:
<path d="M0 0h100v30h-100z M110 0h100v30h-100 M0 40h45v30h-45z M55 40h100v30h-100z M165 40h55v30h-55z"/>
我知道,超级奇怪的数字和字母! 他们都有意义, 当然。 以下是在这种特定情况下发生的情况:
M{x} {y}
: 根据坐标移动到一个点。z
: 关闭当前段。h{x}
: 从当前点画一条水平线,长度为x
在符号定义的方向上x
. 小写x
表示相对坐标。v{y}
: 从当前点画一条垂直线,长度为y
在符号定义的方向上y
. 小写y
表示相对坐标。
这个标记比前一个更简洁(换行和缩进空白只是为了可读性)。 而且,嘿,我们已经设法削减了一半的初始大小,达到 100 字节。 不过,有些东西让我觉得这可能会更小……
平铺修订(-38B,总共 62B)
我们的图案瓷砖没有重复的部分吗? 很明显,在第一行重复了整块砖,但是第二行呢? 这有点难看,但如果我们把中间的砖切成两半,就很明显了。
好吧,中间的砖并没有完全切成两半。 有轻微的抵消,因为我们还必须考虑到差距。 无论如何,我们刚刚找到了一个更简单的基本平铺模式,这意味着更少的字节! 这也意味着我们必须减半 width
我们 <pattern>
元素从 220 到 110。
<pattern id="p" width="110" height="80" patternUnits="userSpaceOnUse"> <!-- pattern content here -->
</pattern>
现在让我们看看简化的瓷砖是如何绘制的 <path>
:
<path d="M0 0h100v30h-100z M0 40h45v30h-45z M55 40h55v30h-55z"/>
大小减少到 62 字节,已经不到原来大小的三分之一! 但是,当我们可以做的更多时,为什么要停在这里!
缩短路径命令(-9B,总共 53B)
值得深入一点 <path>
元素,因为它为优化 SVG 模式提供了更多提示。 我在工作时遇到的一个误解 <path>
是关于如何 fill
属性有效。 在我的童年玩了很多 MS Paint 之后,我了解到我想用纯色填充的任何形状都必须是封闭的,即没有开放点。 否则,油漆会漏出形状并溢出所有东西。
然而,在 SVG 中,情况并非如此。 让我引用 规范 本身:
填充操作通过执行填充操作来填充打开的子路径,就好像在路径中添加了一个额外的“closepath”命令以连接子路径的最后一个点和子路径的第一个点。
这意味着我们可以省略关闭路径命令(z
),因为子路径在填充时被视为自动关闭。
关于路径命令的另一件有用的事情是它们有大写和小写的变体。 小写字母表示使用相对坐标; 大写字母表示使用绝对坐标。
这比使用 H
和 V
命令,因为它们只包含一个坐标。 以下是我将如何描述这两个命令:
H{x}
: 从当前点画一条水平线到坐标x
.V{y}
: 从当前点画一条垂直线到坐标y
.
当我们在图案瓷砖中绘制第一块砖时,我们从 (0,0)
坐标。 然后我们画一条水平线 (100,0)
和一条垂直线 (100,30)
, 最后画一条水平线 (0,30)
. 我们使用了 h-100
命令在最后一行,但它相当于 H0
,这是两个字节而不是五个。 我们可以替换两个类似的事件并削减我们的代码 <path>
归根结底:
<path d="M0 0h100v30H0 M0 40h45v30H0 M55 40h55v30H55"/>
又减少了 9 个字节——我们可以减少多少?
桥接(-5B,总共 48B)
阻碍我们完全优化的 SVG 模式的最长命令是“移动到”命令,它们分别占用 4、5 和 6 个字节。 我们的一个限制是:
路径数据段(如果有的话)必须以“moveto”命令开始。
但没关系。 反正第一个是最短的。 如果我们交换行,我们可以提出一个路径定义,我们只需要在砖块之间水平或垂直移动。 如果我们可以使用 h
和 v
那里的命令而不是 M
?
上图显示了如何使用单个路径绘制三个形状。 请注意,我们正在利用以下事实: fill
操作自动关闭之间的开放部分 (110,0)
和 (0,0)
. 通过这种重新排列,我们还将间隙移到了第二行全宽砖的左侧。 下面是代码的样子,仍然每行分成一个砖块:
<path d="M0 0v30h50V0 h10v30h50 v10H10v30h100V0"/>
当然,我们已经找到了绝对最小的解决方案,因为我们已经减少到 48 个字节,对吧?! 好吧…
数字修整(-4B,总共 44B)
如果您可以对尺寸灵活一点,我们还有另一种优化 SVG 模式的小方法。 我们一直在使用宽度为 100
像素,但这是三个字节。 将其更改为 90
意味着每当我们需要写它时少一个字节。 同样,我们使用了一个间隙 10
像素 - 但如果我们将其更改为 8
相反,我们在每次出现时保存一个字节。
<path d="M0 0v30h45V0 h8v30h45 v8H8v30h90V0"/>
当然,这也意味着我们必须相应地调整图案尺寸。 这是最终优化的 SVG 模式代码:
<pattern id="p" width="98" height="76" patternUnits="userSpaceOnUse"> <path d="M0 0v30h45V0h8v30h45v8H8v30h90V0"/>
</pattern>
上面代码片段中的第二行——不包括缩进——是 44字节. 我们在六次迭代中从 197 个字节到达这里。 这是一个厚实的 尺寸减少 77.7%!
不过我想知道……这真的是最小的尺寸吗? 我们是否研究过所有可能的优化 SVG 模式的方法?
我邀请您尝试进一步缩小此代码,甚至尝试使用其他方法来优化 SVG 模式。 我很想看看我们是否能凭借大众的智慧找到真正的全球最小值!
更多关于创建和优化 SVG 模式
如果您有兴趣了解有关创建和优化 SVG 模式的更多信息,请阅读我的文章 使用 SVG 过滤器创建模式. 或者,如果您想查看 60 多种模式的图库,您可以查看 PetitePatterns CodePen 集合. 最后欢迎大家观看 我在 YouTube 上的教程 帮助您更深入地了解 SVG 模式。
将 SVG 模式优化为最小尺寸 最初发表于 CSS技巧。 你应该 获取时事通讯.
- "
- 10
- 100
- 77
- 9
- 98
- 关于
- 绝对
- 账号管理
- 额外
- 所有类型
- 允许
- 已经
- 另一个
- 的途径
- 国家 / 地区
- 刊文
- 属性
- 可使用
- 轴
- 位
- 黑色
- 挑战
- 更改
- 关闭
- 码
- 相当常见
- 地都
- 包含
- 内容
- 协调
- 可以
- 创造
- 电流
- data
- 更深
- 向下
- 结束
- 成熟
- 一切
- 例子
- 除
- 实验
- 终于
- 姓氏:
- 适合
- 流
- 发现
- 进一步
- 差距
- 越来越
- 全球
- 有
- 高度
- 帮助
- 此处
- 突出
- 创新中心
- HTTPS
- 鉴定
- 图片
- 包括
- 包括
- IT
- 本身
- 已知
- 泄漏
- 学习用品
- 知道
- 借力
- Line
- 小
- 看着
- 爱
- 制作
- 制作
- 管理
- 数学
- 介意
- 更多
- 最先进的
- 移动
- MS
- 数
- 数字
- 抵消
- 好
- 打开
- 优化
- 除此以外
- 模式
- 的
- 点
- 定位的
- 可能
- 强大
- 漂亮
- 车资
- 过程
- 提供
- 质量
- 圆
- 运行
- 说
- 无缝的
- 系列
- 集
- 形状
- 类似
- 简易
- SIX
- 尺寸
- So
- 方案,
- 东西
- 太空
- Spot
- 开始
- 启动
- 支持
- 说
- 通过
- 最佳
- 透明
- 教程
- 使用
- 折扣值
- 查看
- W3
- 了解
- 欢迎进入
- 什么是
- 中
- 也完全不需要
- 工作
- 加工
- 合作
- 价值
- YouTube的