Chrome 在`data:` URIs中转义SVG的正确方法?

zvms9eto  于 2023-04-27  发布在  Go
关注(0)|答案(3)|浏览(176)

Chrome最近启动了blocking URLs with new line and < characters
我维护的应用程序严重依赖数据URI(data:image/svg+xml;utf8,<svg>......)中的SVG图像。使用data: URI而不是传统的图像或SVG标记的原因是SVG是在运行时从较大JSON文档中的SVG属性加载的。
在Chrome 60中进行此更改后,是否可以在data: URL中使用SVG?如果不可以,我的替代方案是什么?

**更新:**用户Álvaro González建议使用encodeURIComponent,这确实使弃用警告消失。

5cg8jx4n

5cg8jx4n1#

数据URI仍然是URI,所以encodeURIComponent()应该是正确的工具:
encodeURIComponent()函数**通过用一个、两个、三个或四个表示字符的UTF-8编码的转义序列(对于由两个“代理”字符组成的字符,将只有四个转义序列)替换特定字符的每个示例来编码统一资源标识符(URI)**组件。
不要忘记将其应用于图像数据,而不是整个URI。
如果URI是在CSS中使用的,这就是你所需要的。如果你想把它注入到HTML中,你还应该在上面应用HTML编码(这次是完整的URI)。

siv3szwd

siv3szwd2#

encodeURIComponent()完成了这项工作,但转义的次数超过了需要。下面是一篇博客文章,详细介绍了似乎最有效的方法,例如最小化转义序列和修复使用双引号的问题,而单引号会更有效:
https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
它包括一个工具来为CSS编码SVG,可以在本地或在线使用。这是另一个在线工具:
https://yoksel.github.io/url-encoder/

mfuanj7w

mfuanj7w3#

如果URL可以有空格和逗号(不包括srcset属性):

function encodeDataURIText(data) {
  return encodeURI(data).replace(/#|%20/g, s => s == '#' ? '%23' : ' ');
}
img.src = "data:image/svg+xml," + encodeDataURIText(textData);

这避免了容易出现在任何地方的转义字符,如空格``,svg字符如=',+&/,css字符如:;@以及$?。它转义#,所以它不会被解释为URL片段。
我不太确定?,但至少Firefox接受它没有问题。
此外,如果您想最大限度地减少过度转义,您可以确保:

  • svg使用单引号代替双引号:attr='value'(大小有很大差异)
  • 空格(特别是制表符和换行符)被折叠成一个``空格

但是这些依赖于上下文,所以不能只用一个简单的正则表达式来完成,因此,在编码之前,您必须手动完成,或者使用一些XML(或者最好是SVG)缩小库。

function encodeDataURIText(data) {
  return encodeURI(data).replace(/#|%20/g, s => s == '#' ? '%23' : ' ');
}

const textarea = document.querySelector('textarea');
const button = document.querySelector('button');
const url = document.querySelector('input');
const img = document.querySelector('img');

function input() {
  textarea.style.height = '';
  textarea.style.height = textarea.scrollHeight + 'px';
};
textarea.oninput = input;
input();

function load() {
  url.value = img.src = "data:image/svg+xml," + encodeDataURIText(textarea.value);
}
button.onclick = load;
load();
textarea { resize: none; }
textarea, img, input { width: 100%; }
img { border: 1px solid black; }
body { padding-right: 8px; }
<div><textarea>&lt;svg xmlns='http://www.w3.org/2000/svg' height='100'>
&lt;text style='dominant-baseline:text-before-edge'>lorem ipsum "&amp;amp;#$+,/:;=?@%{}[]()-_.!~*^`|\'&lt;/text>
&lt;/svg></textarea></div>
<div><button>Load</button> <input readonly/></div>
<hr/>
<div><img src="data:image/svg+xml," /></div>

相关问题