如何在SVG精灵符号内引用内部渐变定义? [英] How can I refer to an internal gradient definition inside an SVG sprite symbol?

查看:80
本文介绍了如何在SVG精灵符号内引用内部渐变定义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

摘要: SVG精灵包含五个图标<symbol>块,其中一个通过ID引用了自己的渐变定义.它不再能够找到此渐变并正确渲染.

JSFIDDLE:: http://jsfiddle.net/Qtq24/1/


我正在将某些图形切换为SVG,并希望它们是图标(在本例中为社交网络配置文件),所以我想将它们保留在一个精灵中(就像我以前使用PNG一样).

我遵循了本CSS-技巧上的SVG精灵指南.com (以及此后续建议使用而不是<g> ).

我现在有一个SVG Sprite文件, social-sprite.svg ,您可以在完整的的原因),以便从HTML.

四个图标可以完美工作,而我遇到的唯一一个问题是YouTube图标,因为它使用了内部定义的渐变.这是SVG代码的YouTube部分:

<symbol id="youtube" viewBox="0 0 400 281.641">
    <path id="Triangle" fill="#FFFFFF" d="M159.845,191.73l106.152-54.999L159.845,81.348V191.73z"/>
    <path id="The_Sharpness" opacity="0.12" fill-rule="evenodd" clip-rule="evenodd" fill="#420000" d="M159.845,81.348l93.091,62.162
    l13.061-6.778L159.845,81.348z"/>
    <g id="Lozenge">
        <g>
            <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="200.4204" y1="2.6162" x2="200.4204" y2="278.9292">
                <stop  offset="0" style="stop-color:#E52D27"/>
                <stop  offset="1" style="stop-color:#BF171D"/>
            </linearGradient>
            <path fill="url(#SVGID_1_)" d="M392.928,62.226c0,0-3.839-27.073-15.617-38.995C362.371,7.583,345.626,7.506,337.947,6.59
            c-54.975-3.974-137.441-3.974-137.441-3.974h-0.171c0,0-82.464,0-137.44,3.974c-7.68,0.916-24.419,0.993-39.364,16.641
            C11.753,35.153,7.92,62.226,7.92,62.226s-3.929,31.792-3.929,63.583v29.805c0,31.791,3.929,63.582,3.929,63.582
            s3.833,27.073,15.611,38.995c14.945,15.646,34.575,15.152,43.318,16.792c31.43,3.015,133.571,3.946,133.571,3.946
            s82.552-0.124,137.526-4.099c7.679-0.915,24.424-0.993,39.363-16.64c11.778-11.922,15.617-38.995,15.617-38.995
            s3.923-31.791,3.923-63.582v-29.805C396.851,94.017,392.928,62.226,392.928,62.226z M159.863,191.73l-0.018-110.383
            l106.152,55.384L159.863,191.73z"/>
        </g>
    </g>
</symbol>

这在HTML中通过以下方式调用:

<svg width="30" height="21">
    <use xlink:href="#youtube" src="fallback.png" width="30" height="21" />
</svg>

开头的两个路径都可以正常工作,问题在于在这个新的合并的sprite SVG文件中,每个图标都以<symbol>分隔,"Lozenge" <path>无法找到#SVGID_1 _ <linearGradient>的引用.

在Firefox中,这将使菱形显示为白色(我认为,可能根本没有显示-并没有真正看到它):

Chrome将其呈现为黑色:

显然,两者都不可接受.目前,我唯一能做的就是删除路径上的fill="url(#SVGID_1_)",并用适合YouTube徽标的纯红色填充.不过,这不是一个适当的解决方案,甚至不打折扣,以这种方式伪装YouTube徽标将不会被其品牌准则接受.

我尝试过的事情(没有运气)

  • 删除两个围绕渐变和路径的<g>包装器,因此整个符号只是<path>-<path>-<linearGradient>-<path>
  • 将梯度定义包裹在<defs>容器中
  • 将其包装在<defs>中,然后还将其移至SVG文件的顶部,即,在YouTube特定的<symbol>
  • 的范围之外
  • 更改ID名称(您永远不会知道!)
  • 使用百分比而不是像素值重新定义渐变

那么我如何获取一个已经内部的<symbol>来引用一个也内部的<linearGradient>定义?


编辑:当整个<svg>块标记为style="display: none;"时,渐变失败.如果删除此样式,则渐变将正确呈现.但是提醒一下,添加了此样式,以便在导入SVG精灵时不会立即在页面上呈现它,而仅允许您根据需要引用id定义的符号.

visibility: hiddenopacity: 0都可以正确渲染渐变,显然,它们仍未提供适当的解决方案,尽管它们仍然划定了SVG如果可见将占据的空间.

发现所有这些内容之后,我非常确定拥有完全可见的<svg>并且没有添加任何样式的<svg>没问题. INSIDE 一个隐藏的容器<div>.但是,即使这样也会导致渐变无法渲染.我离解决这个问题还很近.

解决方案

首先,请注意对我的问题的编辑-然后,我发现使用display: none隐藏SVG符号直到我们需要它们才是问题./p>

我一直在摆弄并确定这个答案",虽然这个答案还不完美,但在任何这种情况下都应该是可靠的.

您需要做的就是将整个<svg>代码包装在<div>容器中,该容器必须显示但绝不会影响布局,因此我只是通过mega overkill CSS完成了此操作例如:

height: 0; width: 0; position: absolute; visibility: hidden;

这很好用.请参阅最后的小提琴: http://jsfiddle.net/Qtq24/5/

如果有人有更好的解决方案,我很想听听它,因为这听起来有点像是一种骇人听闻的方式,但我想除了必须使用display: none;之外,别无选择.

SUMMARY: An SVG sprite contains five icon <symbol> blocks, one of which references its own gradient definition by ID. It is no longer able to find this gradient and render properly.

JSFIDDLE: http://jsfiddle.net/Qtq24/1/


I am switching some graphics to SVG, and being that they are icons (in this case for social networking profiles) I'd like to keep them in a sprite (as I had with PNG before).

I've followed this guide to SVG sprites on CSS-tricks.com (along with this follow-up which advises using <symbol> instead of <g>).

I now have an SVG sprite file, social-sprite.svg, which you can view in full here.

This is one complete <svg> block containing five different <symbol> blocks, each with an id and with a viewBox attribute. In each case I got the SVG code for each symbol by preparing official icons in Adobe Illustrator and retaining the relevant parts of the processed code.

The .svg file is included via PHP as soon as the <body> tag opens (and this is why the main <svg> container inside it is marked with style="display: none;") so that the references to each symbol work from the HTML.

Four icons work perfectly, and the only one I am having trouble with is the YouTube icon, because it uses an internally-defined gradient. Here is the YouTube part of the SVG code:

<symbol id="youtube" viewBox="0 0 400 281.641">
    <path id="Triangle" fill="#FFFFFF" d="M159.845,191.73l106.152-54.999L159.845,81.348V191.73z"/>
    <path id="The_Sharpness" opacity="0.12" fill-rule="evenodd" clip-rule="evenodd" fill="#420000" d="M159.845,81.348l93.091,62.162
    l13.061-6.778L159.845,81.348z"/>
    <g id="Lozenge">
        <g>
            <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="200.4204" y1="2.6162" x2="200.4204" y2="278.9292">
                <stop  offset="0" style="stop-color:#E52D27"/>
                <stop  offset="1" style="stop-color:#BF171D"/>
            </linearGradient>
            <path fill="url(#SVGID_1_)" d="M392.928,62.226c0,0-3.839-27.073-15.617-38.995C362.371,7.583,345.626,7.506,337.947,6.59
            c-54.975-3.974-137.441-3.974-137.441-3.974h-0.171c0,0-82.464,0-137.44,3.974c-7.68,0.916-24.419,0.993-39.364,16.641
            C11.753,35.153,7.92,62.226,7.92,62.226s-3.929,31.792-3.929,63.583v29.805c0,31.791,3.929,63.582,3.929,63.582
            s3.833,27.073,15.611,38.995c14.945,15.646,34.575,15.152,43.318,16.792c31.43,3.015,133.571,3.946,133.571,3.946
            s82.552-0.124,137.526-4.099c7.679-0.915,24.424-0.993,39.363-16.64c11.778-11.922,15.617-38.995,15.617-38.995
            s3.923-31.791,3.923-63.582v-29.805C396.851,94.017,392.928,62.226,392.928,62.226z M159.863,191.73l-0.018-110.383
            l106.152,55.384L159.863,191.73z"/>
        </g>
    </g>
</symbol>

And this is called in the HTML with:

<svg width="30" height="21">
    <use xlink:href="#youtube" src="fallback.png" width="30" height="21" />
</svg>

The opening two paths work fine, the problem is that in this new combined sprite SVG file, with each icon separated as a <symbol>, the "Lozenge" <path> is unable to find the #SVGID_1_ reference to the <linearGradient>.

In Firefox this causes the lozenge to display as white (I assume, perhaps it is not displaying at all - not really looked into it):

whilst Chrome renders it in black:

Obviously neither is acceptable. The only thing I can do at the moment is remove fill="url(#SVGID_1_)" on the path and just fill with a flat colour red appropriate to the YouTube logo. This is not a proper solution though, even discounting the fact that bastardising the YouTube logo in this way would not be accepted under their brand guidelines.

Things I've tried (and had no luck with):

  • removing the two <g> wrappers that surround the gradient and the path, so the whole of the symbol is just <path>-<path>-<linearGradient>-<path>
  • wrapping the gradient definition inside a <defs> container
  • wrapping it in a <defs> and also moving it to the top of the SVG file, i.e. outside the bounds of the YouTube-specific <symbol>
  • changing ID name (you never know!)
  • redefining the gradient with percentages rather than pixel values

So how do I get an already-internal <symbol> to reference an also-internal <linearGradient> definition?


EDIT: It turns out the gradient fails when the whole <svg> block is marked with style="display: none;". If this style is removed, the gradient renders properly. But as a reminder, this styling is added so that when you import the SVG sprite it is not rendered instantly on the page, and just allows you to make references to the id-defined symbols as required.

visibility: hidden or opacity: 0 both allow the gradient to render properly, obviously they don't offer proper solutions though as they still demarcate the space that the SVG would have taken up if visible.

After discovering all this, I was pretty sure it would be no problem to have the fully visible <svg> with no stylings added INSIDE a container <div> which is hidden. However, even this causes the gradient not to render. I'm no closer to solving the issue.

解决方案

Firstly please note the edit to my question - whereupon I discover that the use of display: none to hide the SVG symbols until we need them was the problem.

I kept fiddling and settled upon this "answer", which is far from perfect, but should still be reliable for any such situation.

All you need to do is wrap the entire <svg> code in a <div> container which must be displayed but will never affect layout, so I've just done this via mega overkill CSS such as:

height: 0; width: 0; position: absolute; visibility: hidden;

And this works great. See the final fiddle: http://jsfiddle.net/Qtq24/5/

If anyone has a better solution, I'd love to hear it as this feels like a bit of a hacky way of doing it but I guess no more hacky than having to use display: none; anyway.

这篇关于如何在SVG精灵符号内引用内部渐变定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆