最近,我創建了一個磚牆圖案,作為我的#PetitePatterns 系列的一部分,這是一個挑戰,我需要在560 字節(或大約兩個推文的大小)內用SVG 創建看起來很自然的圖案或紋理。為了滿足這個限制,我經歷了一段旅程,這段旅程教會了我一些優化SVG 圖案的激進方法,以便它們包含盡可能少的代碼,而不會影響整體圖像質量。
我想帶你了解這個過程,並向你展示如何將一個最初為197 字節的SVG 圖案縮小到只有44 字節——驚人的77.7% 的減少!
這被稱為“連續粘結”磚圖案。這是最常見的磚圖案,你肯定以前見過:每一排磚塊都偏移半個磚塊的長度,形成重複的交錯圖案。這種排列非常簡單,使SVG 的<pattern></pattern>
元素非常適合在代碼中重現它。
SVG 的<pattern></pattern>
元素使用預定義的圖形對象,該對象可以在水平和垂直軸上以固定的間隔重複(或“平鋪”)。本質上,我們定義一個矩形平鋪圖案,它會重複以繪製填充區域。
首先,讓我們設置磚塊的尺寸以及每個磚塊之間的間隙。為簡單起見,讓我們使用清晰的整數:磚塊的寬度為100,高度為30,它們之間的水平和垂直間隙為10。
接下來,我們必須確定我們的“基本”圖塊。 “圖塊”指的是圖案圖塊,而不是物理圖塊,不要與磚塊混淆。讓我們使用上面圖像中突出顯示的部分作為我們的圖案圖塊:第一行中有兩個完整的磚塊,第二行中有一個完整的磚塊夾在兩個半個磚塊之間。注意間隙的位置和方式,因為這些需要包含在重複的圖案圖塊中。
使用<pattern></pattern>
時,我們必須定義圖案的寬度和高度,它們對應於基本圖塊的寬度和高度。要獲得尺寸,我們需要進行一些計算:
<code>图块宽度= 2(砖块宽度) 2(间隙)= 2(100) 2(10)= 220图块高度= 2(砖块高度) 2(间隙)= 2(30) 2(10)= 80</code>
好的,所以我們的圖案圖塊是220✕80。我們還必須設置patternUnits
屬性,其中userSpaceOnUse
值基本上表示像素。最後,添加圖案的id 是必要的,以便在用它繪製另一個元素時可以引用它。
<code><pattern height="80" patternunits="userSpaceOnUse" width="220"></pattern></code>
現在我們已經確定了圖塊的尺寸,挑戰是如何以盡可能少的字節數創建圖塊的代碼,從而呈現圖形。這就是我們最終希望達到的目標:
在我看來,重現此圖案最簡單、最明確的方法是繪製五個矩形。默認情況下,SVG 元素的填充為黑色,筆觸為透明。這對於優化SVG 圖案非常有效,因為我們不必在代碼中明確聲明它們。
下面代碼中的每一行都定義了一個矩形。寬度和高度始終設置,並且僅當矩形從0 位置偏移時才設置x 和y 位置。
<code><rect height="30" width="100"></rect><rect height="30" width="100" x="110"></rect><rect height="30" width="45" y="40"></rect><rect height="30" width="100" x="55" y="40"></rect><rect height="30" width="55" x="165" y="40"></rect></code>
圖塊頂行包含兩個全寬磚塊,第二個磚塊定位到x="110",在磚塊之前留有10 像素的間隙。同樣,之後也有10 像素的間隙,因為磚塊在水平軸上的結束位置為210 像素(110 100 = 210),即使<pattern></pattern>
寬度為220 像素。我們需要一點點額外的空間;否則,第二個磚塊將與相鄰圖塊中的第一個磚塊合併。
第二行(底部)中的磚塊是偏移的,因此該行包含兩個半個磚塊和一個完整的磚塊。在這種情況下,我們希望半個磚塊合併,因此開頭或結尾沒有間隙,允許它們與相鄰圖案圖塊中的磚塊無縫融合。偏移這些磚塊時,我們還必須包含半個間隙,因此x 值分別為55 和165。
如此明確地定義每個磚塊似乎效率低下。有沒有什麼方法可以通過重用形狀來優化SVG 圖案?
我認為SVG 的<use></use>
元素並不廣為人知。您可以使用它引用另一個元素,並在使用<use></use>
的任何位置呈現該引用的元素。這可以節省相當多的字節,因為我們可以省略指定每個磚塊的寬度和高度,除了第一個磚塊。
也就是說,<use></use>
確實需要付出一些代價。也就是說,我們必須為我們想要重用的元素添加一個id。
<code><rect height="30" width="100"></rect><use href="#b" x="110"></use><use href="#b" x="-55" y="40"></use><use href="#b" x="55" y="40"></use><use href="#b" x="165" y="40"></use></code>
可能的最小id 是一個字符,所以我為磚塊選擇了“b”。<use></use>
元素可以像<rect></rect>
一樣定位,x 和y 屬性作為偏移量。由於我們切換到<use></use>
後每個磚塊現在都是全寬(記住,我們在圖案圖塊的第二行中明確地將磚塊減半),我們必須在第二行中使用負x 值,然後確保最後一個磚塊從圖塊溢出,以便磚塊之間無縫連接。這些是可以的,因為圖案圖塊之外的任何內容都會自動被剪掉。
你能發現一些可以更有效地編寫的重複字符串嗎?接下來讓我們研究一下這些。
<path></path>
可能是SVG 中最強大的元素。您可以使用其d
屬性中的“命令”繪製幾乎任何形狀。共有20 個可用命令,但我們只需要最簡單的矩形命令。
這就是我最終得到的結果:
<code><path d="M0 0h100v30h-100z M110 0h100v30h-100 M0 40h45v30h-45z M55 40h100v30h-100z M165 40h55v30h-55z"></path></code>
我知道,超級奇怪的數字和字母!它們當然都有意義。以下是此特定情況下的情況:
此標記比之前的標記簡潔得多(換行符和縮進空格僅用於可讀性)。而且,嘿,我們已經設法減少了一半的初始大小,達到100 字節。儘管如此,有些事情讓我覺得這可以更小……
我們的圖案圖塊沒有重複的部分嗎?很明顯,第一行重複了一個完整的磚塊,但第二行呢?有點難以看出,但是如果我們將中間的磚塊切成兩半,就會很明顯。
好吧,中間的磚塊並沒有完全切成兩半。存在輕微偏移,因為我們還必須考慮間隙。無論如何,我們剛剛找到了一個更簡單的基本圖塊圖案,這意味著更少的字節!這也意味著我們必須將<pattern></pattern>
元素的寬度從220 減半到110。
<code><pattern height="80" patternunits="userSpaceOnUse" width="110"></pattern></code>
現在讓我們看看如何使用<path></path>
繪製簡化的圖塊:
<code><path d="M0 0h100v30h-100z M0 40h45v30h-45z M55 40h55v30h-55z"></path></code>
大小減少到62 字節,這已經不到原始大小的三分之一了!但是,為什麼在這裡停下來,當我們還可以做更多的事情時呢!
值得更深入地研究<path></path>
元素,因為它提供了更多優化SVG 圖案的提示。在使用<path></path>
時,我有一個誤解,關於填充屬性是如何工作的。在我的童年時代,我玩過很多MS Paint,我了解到任何我想用純色填充的形狀都必須是封閉的,即沒有開放點。否則,油漆會從形狀中洩漏並溢出到所有內容。
但是,在SVG 中,情況並非如此。讓我引用規範本身:
填充操作通過執行填充操作來填充開放子路徑,就好像向路徑添加了額外的“closepath”命令以將子路徑的最後一點與子路徑的第一點連接起來一樣。
這意味著我們可以省略閉合路徑命令(z),因為填充時會自動認為子路徑已關閉。
關於路徑命令的另一個有用之處是它們有大小寫變體。小寫字母表示使用相對坐標;大寫字母表示使用絕對坐標。
對於H 和V 命令來說,情況有點棘手,因為它們只包含一個坐標。以下是我的描述:
當我們繪製圖案圖塊中的第一個磚塊時,我們從(0,0) 坐標開始。然後我們繪製一條水平線到(100,0) 和一條垂直線到(100,30),最後,繪製一條水平線到(0,30)。我們在最後一行使用了h-100 命令,但它等效於H0,是五個字節而不是兩個字節。我們可以替換兩個類似的出現,並將<path></path>
的代碼減少到:
<code><path d="M0 0h100v30H0 M0 40h45v30H0 M55 40h55v30H55"></path></code>
又減少了9 個字節——我們還能減少多少?
阻礙我們完全優化SVG 圖案的最長命令是“移動到”命令,它們分別佔用4、5 和6 個字節。我們有一個限制是:
路徑數據段(如果存在)必須以“moveto”命令開頭。
但這沒關係。第一個是最短的。如果我們交換行,我們可以得到一個路徑定義,其中我們只需要在磚塊之間水平或垂直移動。如果我們可以在那裡使用h 和v 命令而不是M 會怎麼樣?
上圖顯示瞭如何使用單個路徑繪製三個形狀。請注意,我們正在利用填充操作會自動關閉(110,0) 和(0,0) 之間開放部分的事實。通過這種重新排列,我們還將間隙移動到第二行全寬磚塊的左側。以下是代碼的外觀,仍然分成每行一個磚塊:
<code><path d="M0 0v30h50V0 h10v30h50 v10H10v30h100V0"></path></code>
當然,我們現在已經找到了絕對最小的解決方案,因為我們已經減少到48 字節,對吧? !好吧……
如果您對尺寸有點靈活,那麼我們還可以優化SVG 圖案。我們一直在使用100 像素的磚塊寬度,但這需要三個字節。將其更改為90 表示每當我們需要編寫它時,都會減少一個字節。同樣,我們使用了10 像素的間隙——但是如果我們將其更改為8,則每次出現都會節省一個字節。
<code><path d="M0 0v30h45V0 h8v30h45 v8H8v30h90V0"></path></code>
當然,這也意味著我們必須相應地調整圖案尺寸。以下是最終優化的SVG 圖案代碼:
<code><pattern height="76" patternunits="userSpaceOnUse" width="98"><path d="M0 0v30h45V0h8v30h45v8H8v30h90V0"></path></pattern></code>
上面代碼片段中的第二行(不包括縮進)是44 字節。我們通過六次迭代從197 字節達到了這裡。這是一個巨大的77.7% 的尺寸縮減!
不過,我想知道……這真的是最小的尺寸嗎?我們是否已經查看了所有可能的優化SVG 圖案的方法?
我邀請您嘗試進一步縮小此代碼,甚至嘗試使用替代方法來優化SVG 圖案。我很想看看我們能否利用大眾的智慧找到真正的全局最小值!
如果您有興趣了解有關創建和優化SVG 圖案的更多信息,請閱讀我關於使用SVG 濾鏡創建圖案的文章。或者,如果您想查看60 多個圖案的畫廊,您可以查看PetitePatterns CodePen 集合。最後,歡迎您觀看我在YouTube 上的教程,以幫助您更深入地了解SVG 圖案。
以上是優化SVG圖案的最小尺寸的詳細內容。更多資訊請關注PHP中文網其他相關文章!