为什么自闭合的脚本元素不起作用?

1514

为什么浏览器不能正确识别:

<script src="foobar.js" /> <!-- self-closing script element -->

只有这个被识别:

<script src="foobar.js"></script>

这会破坏XHTML支持的概念吗?

注意:至少对于所有IE浏览器(6-8 beta 2)来说,这个陈述是正确的。


16
适用于Chrome和Opera浏览器。 - corymathews
57
最近的Chrome浏览器版本似乎存在问题,自闭合脚本标签在Chrome中不再起作用。 - Adam Ness
14
不仅仅是脚本标签,我认为自闭合的 div 标签也不起作用。 - DOK
8
截至2011年7月,Chrome和Firefox存在这个问题。“这不是一个漏洞,而是一个功能”-真的很让人恼火。 - Martin Konicek
4
两天后,有一个更一般的版本被问到:https://dev59.com/cnVD5IYBdhLWcg3wE3Xz - Ciro Santilli OurBigBook.com
显示剩余9条评论
12个回答

513

XHTML 1规范的非规范性附录“HTML兼容性指南”指出:

C.3.元素最小化和空元素内容

如果给定一个内容模型不是EMPTY(例如,一个空的标题或段落)的元素的空实例,则不要使用最小化形式(例如,使用<p> </p>而不是<p />)。

XHTML DTD将脚本元素指定为:

<!-- script statements, which may include CDATA sections -->
<!ELEMENT script (#PCDATA)>

126
“不要”并非“必须不”,这是一个指南(如章节标题所建议的一样)而非规定。 - Konrad Rudolph
55
实际上,我找不到这个限制的任何用处 :) 它似乎完全是人为的。 - squadette
22
正确答案由olavk给出。XHTML 1.0的附录C并不是事情变成现在这样的原因——它只是如何绕过现状的方法。 - hsivonen
33
这不是规范的规范部分,它只是关于如何处理不支持XHTML的浏览器的附录。 - Kornel
13
<script /> 的问题不在于规范不允许使用它,而是如果内容类型不是 application/xhtml+xml,浏览器不会将其解释为“非标签堆积”形式。参见:https://dev59.com/YnRC5IYBdhLWcg3wSu97#348818 @shabunc:浏览器可能看起来理解它,但实际上它会将 <p/> 标签后面的内容放到段落内部,因为它会把 squadette 的引语解释为由于 <p> 不为空,所以它不能是自闭合的。在 XHTML 1.1 中,它可以是自闭合的。 - Joe
显示剩余6条评论

255
为了补充Brad和squadette所说的,自闭合的XML语法<script />实际上是正确的XML格式,但要让它在实践中起作用,您的Web服务器还需要将文档作为XML正常格式发送,并在HTTP Content-Type头部中使用XML mimetype,例如application/xhtml+xml(而不是text/html)。
然而,发送XML mimetype会导致IE7无法解析您的页面,因为它只接受text/html
来自w3
总之,“应该使用'application/xhtml+xml'来处理XHTML Family文档,而'text/html'的使用应该仅限于兼容HTML的XHTML 1.0文档。可以使用“application/xml”和“text/xml”,但每当有必要时,应该使用“application/xhtml+xml”而不是那些通用的XML媒体类型。”。
几个月前我曾对此感到困惑,唯一可行的(与FF3 +和IE7兼容)解决方案是使用旧的<script></script>语法以及text/html(HTML语法+ HTML mimetype)。
即使您的服务器以其他方式正确格式化XHTML文档并发送text/html类型的HTTP标头,FF3 +也会使用其HTML呈现模式,这意味着<script />将无法工作(这是一种变化,Firefox以前不那么严格)。
这将发生在任何调整http-equiv元素、文档内的XML prolog或doctype的情况下——Firefox在获取text/html标头后就会分支,这就确定了HTML或XML解析器是否查看文档,并且HTML解析器不理解<script />

3
如果你放弃支持IE7,发送text/xml文档将获得广泛的浏览器支持来使用<script/>标签,这个结论是正确的吗? - Chris Moschini
8
简而言之,<script/> 只会在页面的 MIME 类型为 xhtml/xml 时才起作用。对于常规的 text/html 页面,它不起作用。如果我们尝试使用 "xhtml/xml" MIME 类型,它将破坏 IE 的兼容性。总之,保持冷静并使用 <script> ... </script>谢谢 Joe ;-) - Navin Israni
1
非常好的解释。另一个值得注意的点是,无论是否有元标记,Firefox也会将本地.html文件呈现为标签混乱的形式,原因类似。对于XHTML文件,只有在它们被命名为.xhtml时,Firefox才会相应地呈现它们。 - alecov
@ChrisMoschini。可能是,但要使用 application/xhtml+xml,而不是 text/xml - TRiG

216

其他人已经回答了“如何”并引用了规范。在经过数小时挖掘错误报告和邮件列表后,这里是“为什么没有<script/>”的真实故事。


HTML 4

HTML 4基于SGML

SGML有一些短标签,例如<BR//><B>text</><B/text/><OL<LI>item</LI</OL>。 XML采用第一种形式,将结尾重新定义为">"(SGML是灵活的),因此它变成了<BR/>

然而,HTML没有重新定义这个,所以<SCRIPT/>应该意味着<SCRIPT>>
(是的,'>'应该是内容的一部分,标签仍然没有关闭。)

显然,这与XHTML不兼容,并且会破坏许多网站(在浏览器足够成熟关注此问题 之前),因此没有人实现短代码,规范建议避免使用它们

实际上,所有“有效”的自闭合标签都是在技术上不符合规范的解析器上具有禁止结束标记的标签,事实上是无效的。 正是W3C提出了这个技巧来帮助过渡到XHTML,使其兼容HTML

<script>的结束标签并不是被禁止的

在HTML 4中,“自闭合”标签是一种hack,没有意义。


HTML 5

HTML5有五种标签类型,只有“void”和“foreign”标签可以自闭合

因为<script>不是void(它可能有内容),也不是foreign(像MathML或SVG一样),无论如何使用,<script>都不能自闭合。

但为什么呢?他们不能将其视为foreign,做出特殊处理或其他吗?

HTML5旨在与HTML4和XHTML1的实现向后兼容。 它不基于SGML或XML;其语法主要涉及记录和统一实现。 (这就是为什么<br /><hr />虽然无效HTML4,但仍然是有效的HTML5的原因)。

自闭合的<script>是标记之一,实现曾经存在差异。 它曾经在Chrome、Safari中工作, 以及Opera;据我所知,在Internet Explorer或Firefox中从未工作。

当HTML 5起草时,曾讨论过此事,但被拒绝了,因为这会破坏 浏览器 兼容性。 自关闭脚本标记的网页可能在旧版浏览器中无法正确渲染(如果能渲染的话)。 虽然有其他提议,但它们也无法解决兼容性问题。

在起草版本发布后,WebKit更新了解析器以符合标准。

自关闭<script>在HTML 5中不会发生,因为需要向后兼容HTML 4和XHTML 1。


XHTML 1 / XHTML 5

当真正作为XHTML时,<script/>确实被关闭了,如其他答案所述。

规范说明它在被作为HTML时也应该可用:

XHTML文档...可以被标记为“text/html”[RFC2854]的互联网媒体类型,因为它们与大多数HTML浏览器兼容。

那么,发生了什么事?

人们要求Mozilla让Firefox解析符合标准的文档,而不考虑指定的内容头部信息(即称为内容嗅探)是否正确。这将允许自闭合脚本,并且无论如何也需要进行内容嗅探,因为Web主机不能够成熟地提供正确的头部信息。IE在这方面做得很好(译注:指解析并渲染网页)

如果第一次浏览器战争没有以IE 6结束,XHTML也可能在列表中。但它确实结束了。而IE 6 与XHTML有问题。 事实上,IE 根本不支持正确的MIME类型全部, 强制每个人使用text/html来处理XHTML,因为IE在整整十年中占据了主要市场份额

而且内容嗅探可能会 非常糟糕,人们正在说应该停止

最后,事实证明W3C并不希望XHTML被探测:该文档是同时具有 HTML 和 XHTML,并遵循Content-Type规则。可以说他们坚定地坚持“只需遵循我们的规范”,并且忽略了实际情况。这个错误一直延续到后来的XHTML版本

无论如何,这个决定为Firefox解决了问题。在Chrome 出现之前还有7年时间,也没有其他重要的浏览器。因此就这样决定了。

仅指定DOCTYPE不会触发XML解析,因为要遵循规范。


1
目前还不清楚提案被拒绝的主要原因,因为讨论突然结束了,尽管用新代码破坏现有浏览器是其中提出的问题之一。我只是指出<script>作为一个允许自闭合的HTML5元素是独特的。我的第一条评论中所说的是,向后兼容性没有受到影响,因为向后兼容性是指旧代码在新浏览器中运行——在这种情况下是可以的。 - Andy E
2
@AndyE:你所描述的是向前兼容性 - 即旧代码能够与新编译器/解释器/解析器一起工作的能力。向后兼容性是新代码能够与旧编译器/解释器/解析器一起工作的能力。因此,向后兼容性是问题所在,否则以新规范为基础编写的页面将无法在旧浏览器中运行(是的,尽可能让新代码在旧浏览器中工作是Web编程的传统)。 - slebetman
3
@Dmitry,事实上,禁止自闭合脚本标签是单向道。正如链接中所述,自闭合的<script>将破坏所有浏览器,用户将只能看到空白页面——游戏机、互联网电视、新型企业Win7 PC上的IE 11、数百万个Java运行时或数十亿部智能手机。你能升级大多数语言的大多数设备上的大多数WebView吗?如果HTML5尝试这样做,它们就会像XHTML2一样失败。 - Sheepy
10
非常被低估的回答 - Kamil Tomšík
2
稍作更正:在HTML中看起来像是自闭合的标签不是那些有可选结束标签的标签,而是那些有禁止结束标签(空或无效)的标签。具有可选结束标签的标签,例如<p><li>,不能被“自闭合”,因为它们可以有内容,所以像<p/>这样的代码只是一个(格式错误的)开始标签,如果允许在此元素中使用,则其后面的内容将最终出现在其中。 - Ilya Streltsyn
显示剩余7条评论

179

如果有人感兴趣,根本原因在于HTML最初是SGML的一种方言,而SGML是XML的怪异老兄。在SGML领域中,元素可以在DTD中被指定为自闭合(例如BR,HR,INPUT),隐含可关闭(例如P,LI,TD)或显式可关闭(例如TABLE,DIV,SCRIPT)。当然,在XML中没有这个概念。

现代浏览器使用的标记解析器源自这个遗产,尽管它们的解析模型不再是纯SGML。当然,除非您用XML类型的mime类型发送它,否则您精心制作的XHTML将被视为糟糕编写的受SGML启发的标记语言。这也是为什么......

<p><div>hello</div></p>

浏览器将其解释为:

<p></p><div>hello</div><p></p>

...这是一个美妙的晦涩bug的配方,它在你尝试编写DOM代码时会让你陷入疯狂的状态。


6
我很好奇,为什么浏览器选择以那种方式解释它? - Ahmed Aeon Axan
36
“P”元素不能包含“DIV”元素(这是无效的HTML),因此浏览器会在开放的“DIV”标签之前_隐式_关闭“P”元素(定义为“隐式可关闭”)。但是,不同浏览器在这方面的行为确实不同(就像它们处理任何无效的HTML一样)。 - MrWhite
6
不,这不是标签混乱;greim混淆了有效和无效HTML之间的边界。标签混乱是当作者不遵守规则时出现的情况,因为浏览器会使用错误纠正功能。而另一方面,缺少</p>闭合标签实际上是HTML定义的一部分! - Mr Lister
3
“标签汤”描述的是HTML的解析方式,而不是HTML的编写方式。这个术语用来描述浏览器用来理解HTML的不同策略,与严格的XML解析形成对比。XML解析只允许针对XML MIME类型进行,但由于这些类型从未得到广泛使用,因此浏览器退而求其次,采用各种“标签汤”方案,即使是对于其他有效的文档也是如此。 - greim
8
HTML5 实际上标准化了“标记混乱”的解析,包括一种处理无效标记的一致方式。在那之前,浏览器必须自行确定如何处理无效标记,从而导致不一致性。当前浏览器中的 HTML 解析器是有史以来编写的最先进的软件之一。运行速度极快,并且可以处理大多数任何输入,产生一致的结果。 - Stijn de Witt
显示剩余3条评论

45

Internet Explorer 8及更早版本不支持XHTML解析。即使您使用XML声明和/或XHTML doctype,旧版IE仍将文档解析为纯HTML。而在纯HTML中,自闭合语法不被支持。尾随斜杠只是被忽略了,您必须使用显式的闭合标签。

即使支持XHTML解析的浏览器(如IE 9及更高版本),除非您使用XML内容类型服务文档,否则它们仍会将文档解析为HTML。但在这种情况下,旧版IE根本不会显示该文档!


9
“IE does not support XHTML parsing.” 这个说法在此文写作时的 IE 版本上是正确的,但现在已经不再适用。 - EricLaw
@EricLaw,您能澄清一下哪个版本的IE修复了这个问题吗?(以及任何特定条件 - 例如需要有效的doctype) - scunliffe

29

上面的人已经基本解释了这个问题,但可能会有一件事情让事情更加清晰,即使人们在HTML文档中经常使用<br/>等,但在这种位置上的任何/基本上都会被忽略,并且只有在尝试创建可解析为XML和HTML的内容时才会使用。例如,尝试<p/>foo</p>,您将得到一个常规段落。


26

自闭合的脚本标签无法工作,因为脚本标签可以包含内联代码,并且HTML不能根据属性的存在与否来开启或关闭该功能。

另一方面,HTML确实有一个非常好的标签用于包含对外部资源的引用:<link>标签,而且它可以是自闭合的。它已被用于包括样式表、RSS和Atom订阅源、规范URI以及各种其他好东西。为什么不包括JavaScript呢?

如果你想要自闭合的脚本标签,就像我之前说过的那样是行不通的,但有一个替代方法,虽然不是很智能。你可以使用自闭合的链接标签,并通过将其类型设置为text/javascript和rel设置为script来链接到JavaScript,类似于下面的示例:

<link type="text/javascript" rel ="script" href="/path/tp/javascript" />

5
我喜欢它,但为什么它不够“智能”呢? - Josh M.
5
因为已经有一个预定义的脚本标签可以执行加载脚本的工作,为什么要使用其他东西来混淆问题呢?锤子是用来敲钉子的工具,用鞋子会聪明吗? - Dave Lawrence
11
@daveL说我们有<style>标签,但在使用外部CSS文件时需要用到链接标签。链接标签的定义是:“<link>标签定义文档与外部资源之间的链接。”所以用链接标签来引入外部CSS或JS似乎很合理...因为这就是它的作用——链接外部文件。请注意,我并不是在谈论规范/跨浏览器等问题,我只是评论了使用链接标签来引入CSS和JS的逻辑性...如果真是这样,这实际上是很有道理的。不确定这个鞋子[比喻]是否贴切。 - Jimbo Jonny

24

与XML和XHTML不同,HTML没有自闭合语法的概念。将XHTML解释为HTML的浏览器并不知道/字符表示标签应该是自闭合的;相反,他们将其解释为一个空属性,并且解析器仍然认为标签是“打开”的。

就像<script defer>被视为<script defer="defer">一样,<script />被视为<script /="/">


36
尽管这个解释非常优雅,但实际上是错误的。如果它是正确的,那么在DOM中脚本元素会有一个“/”属性。我已经检查了IE、Firefox和Opera,实际上它们都没有这样的属性。 - Alohci
12
“/” 不是一个有效的属性名称字符,因此它被舍弃了。除此之外,这个解释还是相当清晰易懂的。 - hallvors
2
实际上,一些HTML解析器(尤其是验证器)可能会将“/”解释为NET(Null End Tag)结构的一部分。 - IS4

19

Internet Explorer 8 及以前的版本不支持 XHTML 的正确 MIME 类型application/xhtml+xml。如果你将 XHTML 以 text/html 格式提供,这些较旧版本的 Internet Explorer 只会将其解释为 HTML 4.01。你只能在任何允许省略闭合标签的元素中使用短语法。请参阅 HTML 4.01规范

XML 的“短格式”被解释为一个名为“/”的属性,因为没有等号,所以被解释为具有隐含值“/”。严格来说,在 HTML 4.01 中这是不正确的——未声明的属性是不允许的,但浏览器会忽略它。

IE9 及更高版本支持以application/xhtml+xml格式提供的XHTML 5


IE 9支持XHTML,并且IE的市场份额已不再超过51%。您能否更新您的答案? - Damian Yerrick

6
这是因为SCRIPT标签不是VOID元素。
在HTML文档中,VOID元素根本不需要“关闭标签”!
在xhtml中,一切都是通用的,因此它们都需要终止符,例如“关闭标签”;包括br,一个简单的换行符,如<br></br>或其简写形式<br />
然而,脚本元素从来不是一个VOID元素或参数元素,因为script标签首先是浏览器指令,而不是数据描述声明。
原则上,语义终止指令,例如“关闭标签”,仅在语义不能被后续标签终止的处理指令需要时才需要。例如:

的语义不能由后续的

终止,因为它没有足够的自身语义来覆盖并因此终止前面的H1指令集。虽然它能够将流分裂成一个新的段落行,但它不足以覆盖当前字体大小和样式行高度从H1泄漏下来(因为P没有这个)。

这就是为什么“/”(终止)信号的发明方式和原因。
一个通用的无描述终止标记,如< />,对于任何单独的级联失效都足够了,例如:<H1>Title< />,但这并不总是情况,因为我们还想能够“嵌套”,在流中分割成多个中间标记:在包裹/落入另一个级联之前分成几个部分。因此,通用终止器,如< />,将无法确定要终止属性的目标。例如:<b>bold <i>bold-italic < /> italic </>normal。毫无疑问,将无法正确理解我们的意图,并且很可能将其解释为bold bold-itallic bold normal。
这就是包装器(容器)的概念产生的原因。(这些概念如此相似,以至于无法区分,有时同一个元素可能同时具有两者。<H1>既是包装器又是容器。而<B>只是一个语义包装器。)我们需要一个普通的、没有语义的容器。当然,DIV元素的发明就来了。
DIV元素实际上是一个2BR容器。当然,CSS的出现使整个情况比原本更加怪异,并导致了很多严重的混乱 - 间接地!因为使用CSS可以轻松地覆盖新发明的DIV的本机pre&after BR行为,所以它经常被称为“无用容器”,这是自然错误的! DIV是块级元素,本质上将在流的信号之前和之后换行。不久,WEB开始遭受页面DIV-itis。大多数仍然是如此。CSS的出现使得它完全覆盖并完全重新定义任何HTML标记的本机行为,某种程度上管理混淆和模糊了HTML存在的整个意义......突然间,所有HTML标记都似乎已过时,它们被玷污,剥夺了它们所有的原始含义、身份和目的。你会有这样的印象:它们不再需要了。说:单个容器包装器标记就足以满足所有数据呈现的需要。只需添加所需的属性。为什么不使用有意义的标记; 随着您的创造,发明标记名称,让CSS处理其余部分。这就是xhtml的诞生方式,当然对新手和扭曲的视角付出了巨大的代价,对这一切的真正目的感到困惑。 W3C从万维网转向了“同志们,发生了什么?”HTML的目的是将有意义的数据流传递给人类接收者。为了传递信息。正式部分仅用于帮助信息交付的清晰度。xhtml对信息没有丝毫考虑。-对它来说,信息是绝对无关紧要的。在这个问题中最重要的事情是知道并能够理解xhtml不仅仅是一种扩展HTML的版本,而是完全不同的东西;从头开始;因此,将它们分开是明智的。


我认为 HTML 的目的是将数据流传输到代理(通常是浏览器),而不是人类。 - David Spector

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接