SVG 用于浏览器中带有 PNG 后备的图像

Posted

技术标签:

【中文标题】SVG 用于浏览器中带有 PNG 后备的图像【英文标题】:SVG for images in browsers with PNG fallback 【发布时间】:2011-07-29 04:51:53 【问题描述】:

我希望在网站上使用公司徽标的 SVG 版本。目前所有主流浏览器(IE、Safari、Chrome、Firefox、Opera)的当前版本都支持SVG,所以这看起来并不疯狂。但是,旧的浏览器仍然存在,所以我需要退回到 PNG 支持。

显而易见的解决方案是将 SVG 内容放在 object 标记中(请原谅内联样式...):

<object data='logo.svg' style='height:3em' >
    <img src='logo.png' style='height:3em' />
</object>

如果可能,理论上应该渲染object,否则渲染img。但是,Chrome 不喜欢这样,而是将 height 样式应用于对象本身而不是 SVG,因此我最终得到了一个带有滚动条的类似 iframe 的小框,显示了一个巨大的徽标。

另一个解决方案是使用 PNG 作为img 源,然后在渲染时将其与带有 javascript 的 SVG 源交换,如果我认为我在支持 SVG 的浏览器上运行。这并不理想,因为 PNG 仍然会被下载,而且我不相信我可以正确检测 SVG 支持。不幸的是,jQuery 似乎没有 SVG 检测功能。

最后,由于我的网站是使用 ASP.NET 部署的,我可以在提供页面之前检查用户代理字符串,并根据我认为它是否支持 SVG 来指定 img 源。但这也有一个潜在的问题,就是我不自信我可以做出正确的决定。

为图像制作 SVG 的首选方式是什么?

【问题讨论】:

你也可以只依赖 CSS 而使用不支持多背景的 【参考方案1】:

我不会将其称为首选方式,但如果您想追求第二种选择,这应该检测 SVG 支持(来自 Raphaël 1.5.2):

if(window.SVGAngle || 
    document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") 
    // supports SVG
else 
    // no SVG

Raphaël 使用它来确定是否应该使用 VML (IE) 或 SVG(其他所有人)进行渲染。

出于好奇,为什么您的徽标使用 SVG?如果您已经有 PNG 版本,这似乎需要做很多工作。

【讨论】:

这似乎有助于特征检测,但仍然为时已晚,无法避免 PNG 下载。我对使用 SVG 很感兴趣,因为徽标非常适合矢量图形,SVG 的大小约为 PNG 的 1/3,并且将更好地支持页面缩放(例如在移动设备上)、打印、保证颜色奇偶校验CSS 样式、未来重新设计的便利性等……另外,由于知道我的网站没有位图,我有一种纯粹的感觉。我有什么理由不应该尽可能使用它吗? @Henry Jackson - 我很懒,所以我可能不是回答应该不应该的最佳人选。作为一个懒惰的人,我会选择无代码、非常简单的解决方案,除非替代方案的带宽和纯度优势很大,但这只是我。如果您对 JavaScript 解决方案感到满意,则可以测试 SVG 支持,然后将适当的元素(SVG 或 PNG)注入 DOM。这应该避免在不需要时自动下载 PNG。【参考方案2】:

试试svg-web,他们有多种显示 svg 图像的不同方式,包括具有自动后备功能的 flash。

【讨论】:

【参考方案3】:

要解决您在对象标签中调整 SVG 大小的问题:

将“preserveAspectRatio”和“viewBox”属性添加到 svg 标签。在文本编辑器中打开文件并找到标签。在该标签中,添加以下属性:

preserveAspectRatio="xMinYMin meet" viewBox="0 0 width height"

将 width 和 height 替换为 viewBox 的一些默认值。我使用 SVG 标签的“宽度”和“高度”属性中的值。保存 SVG,它现在应该可以按预期缩放。

见:How do I scale a stubborn SVG embedded with the <object> tag?

虽然对象标签中的 SVG 存在问题,但它们会吞噬点击。

SVG 作为带有 PNG 后备的背景图像:http://www.broken-links.com/2010/06/14/using-svg-in-backgrounds-with-png-fallback/

我最喜欢的是使用 img 标签和 onerror 处理程序将 src 标签更改为 PNG。

另一个好资源:http://www.schepers.cc/svg/blendups/embedding.html

【讨论】:

【参考方案4】:

这是一个老问题,但这里有另一个解决方案:

    下载 Modernizr 的一个版本,该版本被精简为仅测试 SVG(假设这是您需要的唯一测试)。

    运行测试。如果通过,则放入 SVG。如果失败,请放入位图。本质上:

    if (!Modernizr.svg)  
        $("#logo").css("background-image", "url(fallback.png)"); 
    
    

SVG 是Modernizr 的完美用例,因为没有简单的本地方式来提供回退。

注意:浏览器不会同时加载(png 和 svg)版本。

记录在案:如果您必须支持 IE 8 及更低版本或较旧的 android,那么这些天您需要回退 SVG 的唯一原因。

【讨论】:

没有js怎么处理? 如果没有 javascript,您将不得不设置您的 ASP 以根据检测到的浏览器提供不同的页面或 html sn-p。这会使您的模板复杂化,因此我同意并建议使用 Modernizr。 假设一个只需要 Modernizr 来进行 SVG 测试,那么最终用户需要下载多大的文件? @kleinfreund:如果您只需要 Modernizr 来测试 SVG 支持,那么您可以使用来自CSS Tricks的脚本之一【参考方案5】:

您唯一需要的就是 CSS。首先,您将备用图像声明为background-image。然后您可以使用多种背景来添加 SVG。

IE8及以下将忽略第二个background-image-声明,因为缺少对多背景的支持。

顺便说一句,我在这里使用img 元素,因为徽标是内容,而不是布局。在这种情况下使用背景图像可能看起来是错误的,但我不同意。你得到了世界上最好的:SVG 标志,后备

HTML:

<a href="/" class="site-logo">
    <!-- base64 encoded 1x1 px big transparent gif -->
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" >
</a>

CSS(使用多个背景图片):

caniuse: multiple backgrounds

PNG 用于 IE SVG 用于所有其他支持 SVG 的产品 Android 2.x 没有 PNG 或 SVG,因为这些版本实际上支持多个背景,但不支持 SVG 对于支持 SVG 的浏览器,只有一个 HTTP 请求
.site-logo > img 
    /* Dimensions of your image need to be set */
    width: 32px;
    height: 32px;

    /* Fallback for <IE9 */
    background-image: url(logo.png);

    /* multiple backgrounds are ignored by <IE9 */
    background-image: url(logo.svg), none;

CSS(使用线性渐变):

caniuse: CSS gradients

PNG for IE 所有其他支持 SVG 的 SVG(如果指定了供应商前缀) 忽略 webkit 的旧渐变语法使 Android 2.x 使用 PNG 后备
.site-logo > img 
    /* Dimensions of your image need to be set */
    width: 32px;
    height: 32px;

    background: transparent url(logo.png) center center no-repeat;
    background-image: -webkit-linear-gradient(transparent, transparent), url(logo.svg);
    background-image:         linear-gradient(transparent, transparent), url(logo.svg);

【讨论】:

使用线性渐变(透明,透明)而不是多个背景似乎是一种更好的方法,请参阅pauginer.tumblr.com/post/36614680636/… @PatrickFabrizius 为什么这种方法比使用多个背景更好?技术基本相同。 它为 Android 2.x 提供了一个后备方案,而单独的多个背景显然不能。 @PatrickFabrizius Android 2.x 也支持多种背景:browser support。线性渐变更糟糕,因为它们需要 -webkit- 供应商前缀。 您的方法的优点是它在 ios3-4、IE9 和 FF4-15 上显示 SVG 而不是 PNG,缺点是它在 Android 2 中显示空/损坏的图像。 x、IE6-7 和 FF3.6 或更低。我们的两种方法都在所有其他经过测试的设备/浏览器上显示 SVG(甚至 IOS5-7 与您的建议相反)。恕我直言,一种 100% 的时间提供图像的方法比在某些情况下显示空白背景的方法要好。【参考方案6】:

我发现将 SVG 作为 HTML 元素(带有后备)的最佳方法是:

<svg preserveAspectRatio="xMidYMid meet" viewBox="0 0 100 100" style="width: 100px; height: 100px; vertical-align: top;">
    <image xlink:href="image.svg" src="fallback.png"  />
</svg> 

优点:

在我测试过的每个设备/浏览器中提供后备功能(IE6-IE11、Android 2.0+、IOS3-7) 每个测试的浏览器只加载一张图片(IE9-IE11 除外) 外部加载的图片允许缓存图片

缺点:

无法在 IE9-IE11 中用作可缩放(响应)图像 (see this question) IE9-IE11 加载两个图像 IOS3-4 (Mobile Safari) 支持 SVG,但显示 PNG(因为它缺乏内联 SVG 支持) SVG 文件不能有高度/宽度属性(对此不确定,但在某处读过它,在我的测试中我的 SVG 没有它们) 不验证

请向 cmets 提供您能想到的其他优点/缺点。我知道一个 SVG 可能会在某些浏览器中出现像素化,但由于使用 browserstack 进行仿真,我无法测试放大。

来源:http://lynn.ru/examples/svg/en.html

【讨论】:

以上是关于SVG 用于浏览器中带有 PNG 后备的图像的主要内容,如果未能解决你的问题,请参考以下文章

html 具有PNG后备的SVG图像

SVG注入的后备,没有Javascript / SVG支持

在浏览器中将 SVG 转换为图像(JPEG、PNG 等)

在使用canvas api在浏览器中将svg转换为png时,svg中的嵌入图像在Safari中随机空白

scss 混合svg背景与png后备

CSS:使用 Mask 作为 Webkit-Mask-Image 的后备