翻译了一篇关于SVG编程注意事项的文章, 对比以前的代码,发现犯了很多错误,只能在以后的代码中注意了。现在贴出来,希望对使用SVG的朋友有所帮助。中英文对照,以便存在翻译错误时修改。
There are a lot of mistakes in the SVG documents currently found on the Web. Because Adobe's SVG Viewer ignores many of these errors, the maintainers of these documents usually don't realise when they're doing something wrong. Unfortunately, the result is that far too often SVG on the Web doesn't work in Mozilla, Batik or one of the other SVG implementations. It is important that these problems are addressed as soon as possible to prevent them from propagating into authoring tools and the SVG documents that people will write in the future.
现在在网上可以看到很多存在缺陷的
SVG
文档。因为
Adobe SVG Viewer
忽略了很多这样的错误,文档维护人员通常没有意识到它们的存在。不幸的是,这些错误很可能导致文档在其它
SVG
实现中,例如
Mozilla, Batik
等,不能正常工作。目前重要的是尽快澄清这些错误,让相关人员以后在创作
SVG
发布工具和文档时,能够避免重复这些错误。
This document highlights some of the most common mistakes made in SVG content, and explains what SVG maintainers can do to fix them. The hope is that the SVG community will read this document, and that individual members of the community will do what they can to make sure that SVG on the Web is as portable as possible. Please spread the word. If you see others making any of the mistakes described here, please let them know so that they can correct them. Even more important,
if you know of SVG authoring tools that make these mistakes please contact the vendor and let me know
. Feel free to link to this document, and please send me your feedback. My email address is jwatt@jwatt.org.
本文指出
SVG
中一些最常见的错误,并且指导
SVG
文档维护人员如何解决这些问题。希望
SVG
社区能够了解本文的内容,而且社区成员能够尽其所能,确保网上的
SVG
文档尽可能的具有移植性。请宣传这些内容。如果你看到其它人正在犯本文中描述的错误,请指出以便他们修改。更重要的是,如果你知道某些
SVG
发布工具存在这些问题,请通知供应商并通知笔者本人。本文可以自由链接,欢迎你的回复。笔者的邮件地址是
jwatt@jwatt.org.
Contents
内容
·
为
SVG
配置你的服务器
·
不要包含
DOCTYPE
声明
·
绑定必要的名字空间
·
尽可能避免使用
style
属性
·
为属性值分配长度时指定单位
·
使用名字空间敏感的
DOM
方法
·
不要使用
Adobe
的
getter
和
setter
扩展
Configure your server for SVG
This isn't really an issue with SVG content itself, but nevertheless, server misconfiguration is a very common reason for SVG failing to load. For security and correctness reasons, some browsers decides how to handle files by looking at the HTTP headers the server sends with them. If your server isn't configured to send the correct headers with the SVG files it serves, then a browser like Mozilla won't treat those files as SVG. Instead it will most likely show the markup of the files as text or encoded garbage, or even ask the viewer to choose an application to open them. For normal SVG files, servers should send the HTTP header:
Content-Type: image/svg+xml
For gzipped SVG files, servers should send the HTTP headers:
Content-Type: image/svg+xml
Content-Encoding: gzip
Content-Encoding: gzip
You can check that your server is sending the correct HTTP headers with your SVG files by using a site such as web-sniffer.net. Submit the URL of one of your SVG files and look at the HTTP
response
headers. If you find that your server is not sending the headers with the values given above, then you should contact your Web host. If you have problems convincing them to correctly configure their servers for SVG, there may be ways to do it yourself. See the server configuration page on the SVG wiki for a range of simple solutions.
为
SVG
配置你的服务器
这个问题不是
SVG
内容本身的问题,但是,服务器的错误配置是导致
SVG
加载失败的一个非常常见的原因。为了确保内容的安全和正确,一些浏览器根据服务器发送的
HTTP
头决定文件的处理方式。如果你的服务器没有为
SVG
发送正确的头信息,象
Mozilla
之类的浏览器不会将内容当作
SVG
处理,在大多数情况下浏览器将标记文件显示为文本或乱码,甚至请求用户选择一个应用程序以打开文件。对于一般的
SVG
文件,服务器应当发送以下
HTTP
头信息:
Content-Type: image/svg+xml
对
GZIP
压缩的
SVG
文件,应当发送
Content-Type: image/svg+xmlContent-Encoding: gzip
你可以通过一个网站,例如
web-sniffer.net
,来检查你的服务器是否为
SVG
发送了正确的
HTTP
头信息。通过向网站提交一个
SVG
文件的
URL
地址,可以得到并检查返回的
HTTP
头信息。如果发现服务器没有返回上述的正确信息,请联系你的站点提供者,如果不能说服他们为
SVG
正确的配置服务器,你可能需要自行解决这个问题。在
SVG
维基(
wiki
)中的服务器配置页面里可以找到一系列简单的解决办法。
Don't include a DOCTYPE declaration
XML Document Type Definitions, or DTDs for short, are a feature of XML used to validate the contents of a document. A DTD is associated with a document by placing a DOCTYPE declaration in the document. The following line is an example of an SVG DOCTYPE declaration.
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
Unfortunately the SVG DTDs are a source of so many issues that the SVG WG has decided not to write one for the upcoming SVG 1.2 standard. In fact SVG WG members are even telling people not to use a DOCTYPE declaration in SVG 1.0 and 1.1 documents. Instead always include the 'version' and 'baseProfile' attributes on the root
<svg>
tag, and assign them appropriate values as in the following example.
<svg version="1.1"
baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events">
baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events">
If for some reason you want to use the inline features of DOCTYPE declarations (to create entities, etc.), simply omit the public and system identifiers. Your DOCTYPE declaration should then look like this.
<!DOCTYPE svg [
<!-- entities etc. here -->
]>
<!-- entities etc. here -->
]>
不要包含
DOCTYPE
声明
XML
文档类型定义,简称为
DTD
,用来验证
XML
文档内容的有效性。在文档中使用
DOCTYPE
声明用于关联文档和
DTD
定义。下面是一个
SVG DOCTYPE
声明的例子。
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
不幸的是
SVG DTD
是很多问题的根源,因此
SVG WG
决定在将来的
SVG1.2
标准中不使用
DTD
。实际上
SVG WG
成员甚至建议人们在
SVG1.0
和
SVG1.1
中也不使用
DOCTYPE
。作为替代的是,应当总在
SVG
根元素中包含
'version'
和
'baseProfile'
属性,并设置相应的属性值,例如:
<svg version="1.1"
baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events">
baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events">
出于某些原因,如果希望使用
DOCTYPE
声明的内联特性(例如创建实体等),以避免公有和系统标识时,
DOCTYPE
声明应当如下使用:
<!DOCTYPE svg [
<!-- entities etc. here -->
]>
<!-- entities etc. here -->
]>
Bind the required namespaces
SVG is a namespaced XML dialect, and as a consequence all the XML dialects used in your SVG documents must be bound to their namespace as specified in the Namespaces in XML recommendation. It is sensible to bind the SVG and XLink namespaces at a minimum, and possibly also the XML Events namespace. Even if you don't use XLink or XML Events in the current incarnations of some of your SVG documents, including the bindings will prevent annoying errors if you decide to use them later and forget to add the bindings. This simply requires you to include the following three attributes on the root <svg> tag in your SVG documents.
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events">
Be careful not to type
xmlns:svg
instead of just
xmlns
when you bind the SVG namespace. This is an easy mistake to make, but one that can break everything. Instead of making SVG the default namespace, it binds it to the namespace prefix 'svg', and this is almost certainly not what you want to do in an SVG file. A standards compliant browser will then fail to recognise any tags and attributes that don't have an explicit namespace prefix (probably most if not all of them) and fail to render your document as SVG.
绑定必要的名字空间
SVG
是带名字空间的
XML
方言,因此
SVG
文档中使用的所有的
XML
方言必须绑定到
XML
推荐标准中指定的名字空间。至少应当绑定
SVG
和
XLink
名字空间,可能还要加上
XML Events
名字空间。即使目前在
SVG
文档中没有使用
XLink
或
XML Events
,绑定它们也将避免将来的麻烦和错误。这仅仅需要在
SVG
根元素下添加三个属性。
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events">
注意不要将
SVG
名字空间的
xmlns
敲成
xmlns:svg
,这是个容易犯而且严重的错误。它将
SVG
元素绑定到带有
svg
前缀的名字空间,而不是缺省的名字空间,这显然不是你在
SVG
文档中期望的。在这种情况下,与标准兼容的浏览器(如果不是全部的话,至少是大多数)将无法识别没有显式名字空间前缀的
SVG
标签和属性
,
更无法将文档作为
SVG
渲染和显示。
It is quite common to see the
style
attribute used to specify properties in SVG. For example, you may see source code that specifies the
fill
and
stroke
properties as follows:
<circle style="fill:red; stroke:blue;" ... />
Usually this is simply gratuitous use of the
style
attribute, and something that should be avoided. Contrary to popular belief the
style
attribute (note, that's
attribute
, not
element
) doesn't separate content from presentation, and unless you need to override properties set by a CSS selector, it is best to use the SVG formatting attributes instead. In other words it would be better to rewrite the previous code snippet as:
<circle fill="red" stroke="blue" ... />
Using the formatting attributes avoids the pitfalls that can be encountered when using CSS in SVG (see the following section, for example) and is generally considered to be better style. Unlike CSS and the
style
attribute, the formatting attributes are also supported in SVG Tiny, if that matters to you. Unfortunately many SVG authoring tools and human authors still make unnecessary use of the
style
attribute.
尽可能避免使用
style
属性
在
SVG
中设置某些属性值时使用
style
属性是很常见的。例如,设置
fill
和
stroke
属性
<circle style="fill:red; stroke:blue;" ... />
通常使用
style
是个简便的的方法,然而是应当避免使用的方法。与流行的想法相反,
style
属性(注意是属性而不是元素)没有将内容和显示分离,除非你需要覆盖
CSS
设置的属性,最好使用
SVG
格式的属性。也就是说上述代码应当改为:
<circle fill="red" stroke="blue" ... />
使用格式化属性避免了与
SVG
中使用的
CSS(
例子见下面)冲突的缺陷,一般也被认为是更好的风格。与
CSS
和
style
属性不同,
SVG Tiny
也支持格式化的属性(如果你关心
SVG Tiny
的话)。不幸的是很多
SVG
发布工具和作者还在不必要的使用
style
属性。
SVG uses styling properties to describe many of its document parameters such as
fill
and
stroke-width
. These properties can be set by CSS declarations or by presentation attributes (XML attributes that share the same name as the property and map to their corresponding CSS properties if the implementation supports CSS). For example, the
display
property is set on a circle by both:
<circle style="display:none;" ...>
and:
<circle display="none" ...>
For most properties there should be few interoperability problems, but frustratingly when properties are assigned a
length
the visual result can be completely different in the various SVG implementations. The problem arises because the SVG specification allows units to be omitted from lengths (in which case the lengths' units are the units of the current coordinate system (user units)), while on the other hand the CSS specification absolutely requires units to be
explicity
specified for all length values. The question is, are units required for lengths assigned to properties in SVG or not? Which specification takes precedence?
Unfortunately, this issue is a lot more compex than it first seems, and the answers to these questions are still disputed. The result is that implementations don't agree. Some require units, while others don't. The only way to avoid problems is to always specify a unit when assigning lengths to properties. Happily, in SVG, px units are defined to be equivalent to the units established by the current coordinate system (user units). In other words, wherever you would otherwise have omitted the unit from a length assigned to a property, use the px unit instead. For example, instead of writing:
<text stroke-width="2" style="font-size:20;" ...>
write:
<text stroke-width="2px" style="font-size:20px;" ...>
Note that units are only required for properties. Plain attributes such as the
width
or
height
attributes on the
<rect>
tag do not require a unit since they do not map to a CSS property. They can simply be assigned a number and it implicitly has the units of the current coordinate system.
According to the SVG 1.1 Property Index, there are only eight properties applicable to SVG 1.1 that accept a length value: stroke-width, stroke-dashoffset, font, font-size, baseline-shift, kerning, letter-spacing and word-spacing. It is these properties that you should be careful to always specify a length for.
为属性值分配长度时指定单位
SVG
使用风格属性描述很多文档参数,例如
fill
和
stroke-width
。这些属性可以通过
CSS
声明或显示属性(在支持
CSS
的情况下,同名的
XML
属性映射到相应的
CSS
属性)。例如圆弧的显示属性可以分别描述为:
<circle style="display:none;" ...>
和
<circle display="none" ...>
对大多数属性来说很少存在互用性的问题,但设置长度的属性可能在不同的
SVG
实现中显示为完全不同的图形结果。造成这些问题的原因是,
SVG
规范中允许属性省略长度单位(缺省长度单位为当前坐标系统长度单位(用户单位)),而另外一方面,
CSS
规范需要显式声明所有的长度单位。问题是,
SVG
到底需不需要指定长度单位,哪种规范的优先级更高呢?
这个问题比起初看起来更复杂一些,答案也是存在争议的。结果是
SVG
实现的不统一。一些实现要求设置单位,另外一些不要求。避免问题的唯一方法是设置属性时总是指定单位。令人高兴的是,
SVG
中的
px
单位与当前坐标系统长度单位(用户单位)是相同的。也就是说,在所有省略长度单位的属性上可以使用
px
单位。例如
<text stroke-width="2" style="font-size:20;" ...>
应改为
<text stroke-width="2px" style="font-size:20px;" ...>
注意只对某些属性值需要指定单位,对普通属性,例如
<rect>
中的
width
或
height
属性则不需要指定单位,因为这些属性并没有
CSS
属性映射。所以可以只设置一个数值,其单位隐式使用当前坐标系统的单位。根据
SVG1.1
属性索引,只有
8
种属性接受长度值:
stroke-width, stroke-dashoffset, font, font-size, baseline-shift, kerning, letter-spacing
和
word-spacing
。正是这些属性应当总是指定长度单位。
Use namespace aware DOM methods
The DOM Level 1 recommendation was created before the original Namespaces in XML recommendation was released, therefore DOM1 isn't namespace aware. This causes problems for namespaced XML such as SVG. To resove these problems, DOM Level 2 Core added namespace aware equivalents of all the applicable DOM Level 1 methods. When scripting SVG it is important to use the namespace aware methods. The table below lists the DOM1 methods that shouldn't be used in SVG along with their equivalent DOM2 counterparts that should be used instead.
DOM1 (don't use)
|
DOM2 (use these instead!)
|
The first argument for all the DOM2 namespace aware methods must be the "namespace name" of the element or attribute in question. For SVG
elements
this is 'http://www.w3.org/2000/svg'. However, note carefully: the Namespaces in XML 1.1 recommendation states that the namespace name for attributes without a prefix does not have a value. In other words
you must use null as the namespace name for SVG attributes
. As a result, to create an SVG 'rect'
element
using createElementNS you must write:
createElementNS('http://www.w3.org/2000/svg', 'rect');
However, to retrieve the value of the 'x'
attribute
on an SVG 'rect' element you must write:
getAttributeNS(null, 'x');
Note that this is not the case for attributes from other (non-SVG) namespaces such as the xlink:href attribute which use a namespace prefix. Since it has a namespace prefix in the markup ("xlink") it's namespace name is the value that was assigned to that prefix, 'http://www.w3.org/1999/xlink'. Hence to get the value of the xlink:href attribute of an 'a' element in SVG you would write:
getAttributeNS('http://www.w3.org/1999/xlink', 'href');
In summary the rule is simple. For elements with or without a namespace prefix, and for attributes
with
a namespace prefix, the namespace name is the namespace URI of the element/attribute in question. For attributes
without
a namespace prefix the namespace name is null.
使用名字空间敏感的
DOM
方法
DOM Level 1
推荐标准在
XML
标准中出现名字空间之前发布,因此
DOM1
不是名字空间敏感的。这就引发了名字空间化
XML
中的问题,例如
SVG
。为解决这些问题,
DOM Level 2
核心添加了与
DOM Level 1
对等的,但是名字空间敏感的方法。编写
SVG
时应使用名字空间敏感的方法。下表列出了不应再使用的
DOM Level 1
方法以及与之对应的并推荐使用的
DOM2
方法。
DOM1 (
不再使用
)
|
DOM2 (
推荐使用
)
|
所有
DOM2
名字空间敏感方法的第一个参数必须是所操作元素或属性的“名字空间名称”。对
SVG
元素是“
http://www.w3.org/2000/svg
”,然而,请注意:
XML 1.1
推荐标准中的名字空间规定,不带前缀属性的名字空间名称为空。也就是说,对
SVG
属性必须使用
null
名字空间。因此,使用
createElementNS
创建一个
SVG
“
rect
”
元素必须写为:
createElementNS('http://www.w3.org/2000/svg', 'rect');
然而取得该“
rect
”
元素中的“
x
”属性值必须写为:
getAttributeNS(null, 'x');
注意对其它(非
SVG
)名字空间的属性并不适用。例如
xlink:href
使用了一个名字空间前缀,因为存在一个名字空间前缀标记(
xlink
),名字空间名称为前缀的值即
http://www.w3.org/1999/xlink
,因此取得元素中
xlink:href
属性值应写为:
getAttributeNS('http://www.w3.org/1999/xlink', 'href');
总体说来规则是比较简单的。对带有或不带有名字空间前缀的元素,以及带有名字空间前缀的属性,名字空间名称为元素或属性名字空间的
URI
。对不带有名字空间前缀的属性,名字空间名称为
null
。
Don't use Adobe's getter and setter extensions
Long, long ago when Adobe first released their SVG viewer plug-in, Netscape 4 still had enough users that it was important to be compatible with it. To do this it seems it was necessary to extend the ECMAScript interfaces and provide corresponding getters and setters for all the properties defined by the specification. As a result in ASV it is possible to write code like this:
evt.getTarget().getOwnerDocument().getDocumentElement();
when the DOM and SVG specifications actually define properties, not methods, so the correct way to write this code is:
evt.target.ownerDocument.documentElement;
The problem is that no one else supports ASV's getter and setter extensions. Scripts that uses them will not work in other SVG implementations. Happily Netscape 4 is now irrelevant for most of us, and since ASV supports the properties too, new SVG scripts can conform to the standards and work in all SVG implementations by using the properties. (In fact old code could, and should, be updated too.)
It is difficult to give a list of what is and isn't an ASV extension since there are so many properties. If you aren't familiar enough with the specifications to know which getters and setters are defined by the W3C and which are ASV extensions, be sure to test your scripts using another SVG implementation such as Mozilla Firefox or Batik. If you get errors relating to getters or setters try using properties instead and see if that fixes things. You can also search for getter and setter names in the SVG, DOM2 Core, DOM2 Events and DOM2 Style IDL. If you can't find them in any of those documents they probably aren't part of any W3C standard.
不要使用
Adobe
的
getter
和
setter
扩展
在很久很久以前,
Adobe
第一次发布
SVG viewer
插件时,
Netscape 4
仍然拥有大量的用户,所以必须与之保持兼容。为达到这个目的,必须扩展
ECMAScript
接口并为规范中所有属性提供相应的
getters
和
setters
方法。因此在
ASV
中代码可能如下所示:
evt.getTarget().getOwnerDocument().getDocumentElement();
实际上
DOM
和
SVG
规范定义的是属性,而不是方法,因此正确的写法应为:
evt.target.ownerDocument.documentElement;
问题的原因是除
ASV
外,没有其它
SVG
实现支持
getters
和
setters
方法扩展。使用这些扩展方法的代码无法在其它
SVG
实现中使用。另人高兴的是现在
Netscape 4
已经不再重要,而且
ASV
也支持使用属性,因此新的
SVG
脚本应遵循标准,使用属性,以便在所有
SVG
实现中工作。(实际上旧的代码也可以,而且应当进行升级)
因为存在太多这种扩展属性,所以很难给出一个列表以说明哪些是
ASV
扩展,哪些不是。如果你不清楚哪些
getters
和
setters
方法是
W3C
规范中定义的,哪些是
ASV
扩展的,请使用
ASV
以外的一种
SVG
实现对代码进行测试,例如
Mozilla Firefox
或
Batik
。如果发现与
getters
和
setters
方法相关的错误,试试使用属性是否能够解决这些问题。也可以在
SVG, DOM2
核心,
DOM2
事件和
DOM2
风格
IDL
文档中搜索相关的
getters
和
setters
方法名称,如果在这些文档中找不到这些名字,它们很可能不是
W3C
标准中的一部分。