svg 使用中的疑惑點

刨根發表於2020-07-16

svg,g ,defs,symbol 都是容器元素,使用起來給人許多疑惑

svg-spirite-loader在頁面生成的svg標籤有什麼特點?

svg標籤裡面的symbol有什麼用?

這些標籤能夠隨意相互包裹麼?

不能任意巢狀

經過實驗發現:

  1. svg>g>svg>g可以任意巢狀
  2. defs symbol巢狀不會展示,因為這兩個容器本來就不會展示
<svg xmlns="http://www.w3.org/2000/svg" style="fill: #cccccc" viewBox="0 0 8 8" width="16" height="16">
    <g id="user-icon">
        <g>
            <g>
                <svg>
                    <path id="user-icon_Rectangle-2" class="st0"
                          d="M4,0L4,0c2.21,0,4,1.79,4,4l0,0c0,2.21-1.79,4-4,4l0,0C1.79,8,0,6.21,0,4l0,0  C0,1.79,1.79,0,4,0z"></path>
                    <path id="user-icon_Combined-Shape-Copy" class="st1"
                          d="M4.23,2.94l0.52,1.59l1-0.85C5.7,3.61,5.67,3.52,5.67,3.43C5.67,3.19,5.85,3,6.08,3  C6.31,3,6.5,3.19,6.5,3.43c0,0.22-0.17,0.41-0.38,0.43L5.67,6H2.33L1.88,3.86C1.67,3.84,1.5,3.65,1.5,3.43C1.5,3.19,1.69,3,1.92,3  s0.42,0.19,0.42,0.43c0,0.09-0.03,0.18-0.08,0.25l1,0.85l0.52-1.59C3.62,2.86,3.51,2.69,3.51,2.5C3.51,2.22,3.73,2,4,2  s0.49,0.22,0.49,0.5C4.49,2.69,4.38,2.86,4.23,2.94z"
                          fill="#ffffff"></path>
                </svg>
            </g>
        </g>
    </g>
</svg>

可以用上面的例子測試

必須包裹在svg內部

g,defs,symbol use 外面必須包裹svg元素,否則這些元素是不起作用的;

// g元素外層沒有svg元素
<g id="g1">
    <rect id="rect1" width="1000" height="50" x="10" y="10" fill="#c00"/>
    <circle id="circle1" cx="30" cy="30" r="10" fill="#00c"/>
</g>
<svg>
    <use xlink:href="#g1" />
</svg>

單獨一個g元素不會渲染;也不能被use元素複用

// g元素外層有svg元素
<svg>
    <g id="g1">
        <rect id="rect1" width="1000" height="50" x="10" y="10" fill="#c00"/>
        <circle id="circle1" cx="30" cy="30" r="10" fill="#00c"/>
    </g>
</svg>
<svg>
    <use xlink:href="#g1" />
</svg>

上面的html能渲染出來兩組影像。

g元素

g是用來組合讀寫的容器,看名字像是group的縮寫,新增到g元素上的變換會應用到其所有的子元素上。

新增到g元素的屬性會被其所有的子元素繼承;比如fill會被子元素繼承。

此外,g元素也可以用來定義複雜的物件,之後可以通過use元素來引用它們。

<svg style="width: 1000px" viewBox="10 10 1000 50">
    <g id="aaa" fill="#ccc">
        <rect id="rect1" width="1000" height="50" x="10" y="10" />
        <circle id="circle1" cx="30" cy="30" r="10" fill="#00c"/>
    </g>
</svg>
<svg style="width: 1000px" viewBox="10 10 1000 50">
    <use xlink:href="#aaa" />
</svg>

use複用

use元素在SVG文件內取得目標節點,並在別的地方複製它們。它的效果等同於這些節點被深克隆到一個不可見的DOM中,然後將其貼上到use元素的位置。

克隆之後樣式可能會複製過去:

<style>
.special g{
    fill: #0b97c4;
}
.clone g{
    fill: red;
}
</style>
<div class="special">
    <svg style="width: 1000px" viewBox="10 10 1000 50">
        <g id="aaa"  >
            <rect id="rect1" width="1000" height="50" x="10" y="10" />
        </g>
    </svg>
</div>

<svg style="width: 1000px" viewBox="10 10 1000 50">
    <use xlink:href="#aaa" />
</svg>

克隆導致上面渲染出來兩個長方形顏色一致。

use出來的svg的顏色沒有變成紅色說明css選擇器在此處不再起作用了。

此時如何去更改顏色呢,看調整svg顏色

defs

def -->define 定義以後需要重複使用的圖形元素。

建議把所有需要再次使用的引用元素定義在defs元素裡面。這樣做可以增加SVG內容的易讀性和可訪問性。

在defs元素中定義的圖形元素不會直接呈現。

你可以在你的視口的任意地方利用 元素呈現這些元素。

<div class="special">
    <svg style="width: 1000px" viewBox="10 10 1000 50">
        <defs>
            <g id="aaa"  >
                <rect id="rect1" width="1000" height="50" x="10" y="10" />
            </g>
        </defs>
    </svg>
</div>

<svg style="width: 1000px" viewBox="10 10 1000 50">
    <use xlink:href="#aaa" />
</svg>

使用defs之後只能看到一個長方塊。

symbol元素

symbol元素用來定義一個圖形模板物件,它可以用一個元素例項化。

symbol元素對圖形的作用是在同一文件中多次使用,新增結構和語義,和g,defs類似。

symbol元素本身是不呈現的。只有symbol元素的例項(亦即,一個引用了symbol的 元素)能呈現,類似於defs。

symbol 和svg 一樣也可以使用viewBox。

vue中使用svg-sprite-loader之後就會在頁面的body下面渲染一個下面結構的html程式碼

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     style="position: absolute; width: 0; height: 0" aria-hidden="true" id="__SVG_SPRITE_NODE__">
    <symbol xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-7 1 24 24"
            id="Sync">
        <style type="text/css">
            #Sync .st0 {
                fill: none;
            }
        </style>

        <desc>Created with Sketch.</desc>
        <rect id="Sync_Rectangle-111" x="-7" y="1" class="st0" width="24" height="24"></rect>
        <g>
            <path d="M5,19.5c-2.9,0-5.3-1.9-6.2-4.5H1v-1h-2.4H-2h-0.4H-3v4h1v-2.3c1.1,2.8,3.8,4.8,7,4.8c3.8,0,6.9-2.8,7.4-6.5h-1   C10.9,17.1,8.2,19.5,5,19.5z"></path>
            <path d="M12,8v2.3c-1.1-2.8-3.8-4.8-7-4.8c-3.8,0-6.9,2.8-7.4,6.5h1C-0.9,8.9,1.8,6.5,5,6.5c2.9,0,5.3,1.9,6.2,4.5H9v1h2.4H12h0.4   H13V8H12z"></path>
        </g>
    </symbol>
</svg>

調整svg大小

<svg>
    <g id="g1">
        <rect id="rect1" width="1000" height="50" x="10" y="10" fill="#c00"/>
    </g>
</svg>

對上面的svg設定width="100" height="5" 或者 style="width:100px;height:5px"之後,影像直接消失了。

消失的原因在於影像的位置在偏離左上角10px,10px的位置,設定svg的展示區域是從0,0偏離到width,height;而此處height只有5px,導致不能看到影像。

所以一般需要viewBox這個屬性,值為:x y width height,功能類似於擷取svg影像;如果影像的尺寸/偏移和viewBox一致,放大縮小的操作作用域整個影像;如果viewBox和影像原始尺寸/偏移不一致,會導致只能展示一部分的影像。

<svg viewbox="0 0 1000 50"> // 設定原始值之後,然後設定屬性或者樣式就能完美生效了。

調整svg顏色

一般的svg有背景和圖案組成,背景色透明,由頁面背景決定;圖案的顏色根據svg元素的繼承特點使用fill設定。

方法一:

svg{
	fill:red;
}  // 需要特意設定fill

方法二:

svg{
	fill:currentColor;
	color:red;
} // 只需要設定color 

特殊情況:

如果預先在內部設定了背景色或者圖案色,

<svg xmlns="http://www.w3.org/2000/svg" class="special icon-user-icon icon-s-normal-tny" style="fill: #cccccc"  viewBox="0 0 8 8" width="16" height="16">
    <g  id="user-icon">
        <style type="text/css">
            #user-icon .st1 {
                fill: #ffffff;
            }
        </style>
        <path id="user-icon_Rectangle-2" class="st0"
              d="M4,0L4,0c2.21,0,4,1.79,4,4l0,0c0,2.21-1.79,4-4,4l0,0C1.79,8,0,6.21,0,4l0,0  C0,1.79,1.79,0,4,0z"></path>
        <path id="user-icon_Combined-Shape-Copy" class="st1"
              d="M4.23,2.94l0.52,1.59l1-0.85C5.7,3.61,5.67,3.52,5.67,3.43C5.67,3.19,5.85,3,6.08,3  C6.31,3,6.5,3.19,6.5,3.43c0,0.22-0.17,0.41-0.38,0.43L5.67,6H2.33L1.88,3.86C1.67,3.84,1.5,3.65,1.5,3.43C1.5,3.19,1.69,3,1.92,3  s0.42,0.19,0.42,0.43c0,0.09-0.03,0.18-0.08,0.25l1,0.85l0.52-1.59C3.62,2.86,3.51,2.69,3.51,2.5C3.51,2.22,3.73,2,4,2  s0.49,0.22,0.49,0.5C4.49,2.69,4.38,2.86,4.23,2.94z"
              fill="#ffffff"></path>
    </g>
</svg>

<svg class="sdsdsd" style="width: 16px;fill:red" viewBox="0 0 8 8">
    <use xlink:href="#user-icon"/>
</svg>
<style>
.special .st1{
    fill: blue!important;
} 
body .sdsdsd .st1{
    fill: orange!important;
}
</style>

比如上面的svg內部定義了一個style,直接設定了樣式。外部使用style又設定了樣式。非use使用(.special )可以改變內部path的fill;使用use情況(.sdsdsd)無法改變內部path的fill,css選擇器在此處失效了,無法覆蓋舊有樣式。

如果必須要控制樣式怎麼辦呢?

這時候可以使用css變數來定義內部的樣式,通過改變css變數的值來修改顏色。

<svg xmlns="http://www.w3.org/2000/svg" class="special icon-user-icon icon-s-normal-tny" style="fill: #cccccc"  viewBox="0 0 8 8" width="16" height="16">
    <g  id="user-icon">
        <style type="text/css">
            #user-icon .st1 {
                fill: var(--color);
            }
        </style>
        <path id="user-icon_Rectangle-2" class="st0"
              d="M4,0L4,0c2.21,0,4,1.79,4,4l0,0c0,2.21-1.79,4-4,4l0,0C1.79,8,0,6.21,0,4l0,0  C0,1.79,1.79,0,4,0z"></path>
        <path id="user-icon_Combined-Shape-Copy" class="st1"
              d="M4.23,2.94l0.52,1.59l1-0.85C5.7,3.61,5.67,3.52,5.67,3.43C5.67,3.19,5.85,3,6.08,3  C6.31,3,6.5,3.19,6.5,3.43c0,0.22-0.17,0.41-0.38,0.43L5.67,6H2.33L1.88,3.86C1.67,3.84,1.5,3.65,1.5,3.43C1.5,3.19,1.69,3,1.92,3  s0.42,0.19,0.42,0.43c0,0.09-0.03,0.18-0.08,0.25l1,0.85l0.52-1.59C3.62,2.86,3.51,2.69,3.51,2.5C3.51,2.22,3.73,2,4,2  s0.49,0.22,0.49,0.5C4.49,2.69,4.38,2.86,4.23,2.94z"
              fill="#ffffff"></path>
    </g>
</svg>

<svg class="sdsdsd" style="width: 16px;fill:red" viewBox="0 0 8 8">
    <use xlink:href="#user-icon"/>
</svg>

<style>
    .special {
        --color: blue!important;
    }
    body  .sdsdsd {
        --color: orange!important;
    }
</style>

成功改變了顏色,但是此處又讓人疑惑:使用css變數之後 css選擇器好像又生效了......

相關文章