<html>
  <body>
    <style type="text/css">
      p.first {color:blue}
      p.second {color:green}
    </style>

    <p class="first">Hello World</p>
    <p class="second">Hello World</p>

    <style type="text/css">
      p.first {color:green}
      p.second {color:blue}
    </style>

    <p class="first">Hello World</p>
    <p class="second">Hello World</p>
  </body>
</html>

一个浏览器应该如何渲染css是不连续的?它是否应该生成一些数据结构,使用页面上所有的css样式,并使用它进行渲染?

还是按照看到的顺序使用样式信息进行渲染?


当前回答

<style>标签属于<head>部分,与所有内容分开。

参考资料:W3C Specs和W3Schools

其他回答

对于“体内风格”爱好者来说,有一个坏消息:W3C最近在与WHATWG的HTML战争中失败了,WHATWG的无版本HTML“生活标准”现在已经成为官方标准,唉,它不允许体内风格。短暂的快乐时光一去不复返。,)W3C验证器现在也根据WHATWG规范工作。(谢谢@FrankConijn的提醒!)

(注意:这是“今天”的情况,但由于没有版本控制,链接可能在任何时候无效,而不通知或控制。除非你愿意链接到它在GitHub上提交的单个源代码,否则你基本上不能再稳定地引用新的官方HTML标准AFAIK。请纠正我,如果有一个规范的方法来正确地做这件事。)

过时的好消息:

耶,STYLE终于在BODY中生效了,从HTML5.2开始! (scoped也消失了。)

来自W3C规范(注意最后一行!):

4.2.6. 风格元素 ... 可以使用此元素的上下文: 需要元数据内容的地方。 在noscript元素中,它是head元素的子元素。 在正文中,期望流内容的地方。


元附注:

尽管遭受了“浏览器战争”的破坏,但我们仍然必须继续针对两个相互竞争的“官方”HTML“标准”(1个标准+ 1个标准< 1个标准)进行开发,这意味着“退回到战壕常识”的web开发方法从未真正停止应用。

This may finally change now, but citing the conventional wisdom: web authors/developers and thus, in turn, browsers should ultimately decide what should (and shouldn't) be in the specifications, when there's no good reason against what's already been done in reality. And most browsers have long supported STYLE in BODY (in one way or another; see e.g. the scoped attr.), despite its inherent performance (and possibly other) penalties (which we should decide to pay or not, not the specs.). So, for one, I'll keep betting on them, and not going to give up hope. ;) If WHATWG has the same respect for reality/authors as they claim, they may just end up doing here what the W3C did.

警告:这个答案指的是样式标签上的scoped属性,不应该再使用!

正如其他人已经提到的,HTML 4要求<style>标记放置在<head>部分(即使大多数浏览器允许在body中使用<style>标记)。

然而,HTML 5包含scoped属性(参见下面的更新),它允许您在<style>标记的父元素中创建范围内的样式表。这也允许你在<body>元素中放置<style>标签:

<!DOCTYPE html>
<html>
<head></head>
<body>

<div id="scoped-content">
    <style type="text/css" scoped>
        h1 { color: red; } 
    </style>

    <h1>Hello</h1>
</div>

    <h1>
      World
    </h1>

</body>
</html>

如果您在支持限定作用域的HTML-5浏览器中呈现上述代码,您将看到样式表的限定作用域。

这里有一个重要的警告……

在我写这个答案的时候(2013年5月),目前几乎没有主流浏览器支持scoped属性。(虽然显然Chromium的开发版本支持它。)

然而,与这个问题相关的scoped属性有一个有趣的含义。这意味着未来的浏览器必须通过标准来允许<style>元素在<body>中(只要<style>元素是作用域)。

因此,考虑到:

目前几乎所有现有的浏览器都忽略了scoped属性 几乎所有现有的浏览器目前都允许<style>标签在<body>中 未来的实现将需要在<body>中允许(scoped) <style>标记

...那么在主体中放置<style>标记实际上没有什么害处,只要您将来使用一个作用域属性来证明它们。唯一的问题是,当前的浏览器实际上并没有限制样式表的作用域——它们将它应用于整个文档。但关键是,出于所有实际目的,你可以在<body>中包含<style>标签,前提是你:

通过包含scoped属性来证明你的HTML是面向未来的 请理解,到目前为止,<body>中的样式表实际上还没有确定作用域(因为还没有主流浏览器支持)


* except of course, for pissing off HTML validators...

最后,关于常见的(但主观的)说法,即在HTML中嵌入CSS是一种糟糕的做法,应该注意的是,scoped属性的全部意义在于适应典型的现代开发框架,允许开发人员将HTML块作为模块或联合内容导入。为了开发具有特定样式的封装的模块化组件,使用只应用于特定HTML块的嵌入式CSS非常方便。


更新至2019年2月,根据Mozilla文档,scoped属性已弃用。Chrome在36版(2014年)和Firefox在62版(2018年)停止支持它。在这两种情况下,该功能都必须由用户在浏览器设置中显式启用。没有其他主流浏览器支持它。

网站Can I Use报告称,自2016年以来,“属性已从当前规范中删除”。

我认为,在现代浏览器中,你只需付出一点努力,就可以获得完全合法的“作用域样式”。考虑下面的HTML文档:

<!doctype html>
<html>
    <head>
    </head>
    <style>p{background:red}</style>
    <body>
        <template>
            <style>p{background:green}</style>
            <p>I am green</p>
        </template>
        <p>I am red!</p>
        <script>
         document.querySelectorAll('template').forEach((template)=>{
             const div = document.createElement('div');
             div.remove(); // detach div from document
             let shadow = div.attachShadow({mode:'open'});
             shadow.replaceChildren(template.content);
             template.replaceWith(div);
         });
        </script>
    </body>
</html>

我使用了一个模板来封装HTML,我想包含自己的样式元素,不影响模板之外的任何HTML。当然,默认情况下,在呈现期间忽略模板。JavaScript代码

查找文档中的每个模板 创建一个分离的空div 赋予div一个“阴影根”(本地化样式的关键) 将模板内容复制到影子根目录 用包含相同内容的div替换原来的模板(除了在阴影根)

几乎所有HTML内容(包括样式)在模板中都是合法的。

使用最新的Chrome/Firefox/Edge测试。给我一个免费的MacBook Pro,我会用Safari进行测试!: -)

我想这可能是关于有限上下文的问题,例如,非程序员用户使用web系统上的wywyg编辑器,这限制了遵循标准的可能性。有时(像TinyMCE),它是一个库,把你的内容/代码在一个文本区域标签,这是由编辑器渲染为一个大的div标签。有时,它可能是这些编辑器的旧版本。

我假设:

这些非程序员用户没有与系统管理员(或机构的web开发人员)开放的渠道,要求在系统的样式表中包含一些CSS规则。实际上,这对管理员(或web开发人员)来说是不切实际的,考虑到他们会有这样的请求数量。 这个系统是遗留的,仍然不支持更新版本的HTML。

在某些情况下,没有使用样式规则,可能是一个非常糟糕的设计体验。所以,是的,这些用户需要定制。好的,但是在这种情况下,解是什么呢?考虑到在html页面中插入CSS的不同方法,我认为这些解决方案:


第一个选择:询问你的系统管理员

要求系统管理员在系统的样式表中包含一些CSS规则。这将是一个外部或内部的CSS解决方案。如前所述,这可能是不可能的。


第二个选项:<link> on <body>

在主体标签上使用外部样式表,即在您可以访问的区域内使用链接标签(即,在网站上,在主体标签内而不是在头部标签内)。一些消息来源说这是可以的,但“不是一个好的做法”,比如MDN:

<link>元素既可以出现在<head>元素中,也可以出现在<body>元素中,这取决于它的链接类型是否为body-ok。例如,样式表链接类型是body-ok,因此<link rel="stylesheet">在正文中是允许的。然而,这并不是一个好的实践;将<link>元素从body内容中分离出来,将它们放在<head>中更有意义。

其他一些则将其限制在<head>部分,如w3schools:

注意:该元素只出现在头部部分,但它可以出现任意次数。

测试

我在这里测试了它(桌面环境,在浏览器上),它适合我。 创建一个文件foo.html:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <link href="bar.css" type="text/css" rel="stylesheet">
    <h1 class="test1">Hello</h1>
    <h1 class="test2">World</h1>
</body>
</html>

然后是一个CSS文件,在同一个目录下,叫做bar.css:

.test1 { 
    color: green;
};

好吧,如果你知道如何在机构系统的某个地方上传CSS文件,这将是可能的。也许情况就是这样。


第三个选项:<style> on <body>

在主体标签上使用互联网样式表,即在您有权访问的区域内使用样式标签(即,在网站上,在主体标签内而不是在头部标签内)。这就是Charles Salvia和Sz的答案。选择这个选项时,要考虑他们的担忧。


第4、5、6个选项:JS方式

警报 这些元素与修改页面的<head>元素有关。也许学校的系统管理员不允许这样做。所以,建议先征求他们的同意。

假设许可被授予,策略是访问<head>。怎么做?JavaScript方法。

第四个选项:在<head>上新建<link>

这是第二个选项的另一个版本。在<head>标签上使用外部样式表,即在您可以访问的区域之外使用<link>元素(也就是说,在站点上,不在body标签内,在head标签内)。这个解决方案符合上文提到的MDN和w3schools关于第二种解决方案的建议。将创建一个新的Link对象。

要通过JS解决这个问题,有很多方法,但在下面的代码行中,我演示了一个简单的方法。

测试

我在这里测试了它(桌面环境,在浏览器上),它适合我。 创建一个文件f.html:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <h1 class="test1">Hello</h1>
    <h1 class="test2">World</h1>
    <script>
        // JS code here
    </script>
</body>
</html>

在脚本标签内部:

var newLink = document.createElement("link");
newLink.href = "bar.css";
newLink.rel = "stylesheet";
newLink.type = "text/css";
document.getElementsByTagName("head")[0].appendChild(newLink);

然后在CSS文件中,在相同的目录中,称为bar.css(与第二个选项一样):

.test1 { 
    color: green;
};

正如我已经说过的:如果你知道如何在机构系统的某个地方上传CSS文件,这将看起来是可能的。

第5个选项:新建<style> on <head>

在<head>标签上使用新的内部样式表,即在您可以访问的区域之外使用新的<style>元素(也就是说,在站点上,不在body标签内,在head标签内)。一个新的Style对象将被创建。

这是通过JS解决的。下面演示一种简单的方法。

测试

我在这里测试了它(桌面环境,在浏览器上),它适合我。 创建一个文件foobar.html:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <h1 class="test1">Hello</h1>
    <h1 class="test2">World</h1>
    <script>
        // JS code here
    </script>
</body>
</html>

在脚本标签内部:

var newStyle = document.createElement("style");
newStyle.innerHTML = 
    "h1.test1 {"+
        "color: green;"+
    "}";
document.getElementsByTagName("head")[0].appendChild(newStyle);

第6个选项:在<head>上使用现有的<style>

在<head>标签上使用现有的内部样式表,即在您可以访问的区域之外使用<style>元素(也就是说,在站点上,不在body标签内,在head标签内),如果存在的话。将创建一个新的Style对象或使用一个CSSStyleSheet对象(在这里采用的解决方案的代码中)。

从某种角度来看,这是有风险的。 首先,因为它可能不存在某个<style>对象。根据实现此解决方案的方式,可能会得到未定义的返回值(系统可能使用外部样式表)。 其次,因为您将编辑系统设计作者的工作(作者身份问题)。 第三,因为你所在机构的it安全政策可能不允许这样做。 所以,这样做的时候一定要征求许可(就像在其他JS解决方案中一样)。

假设,再次允许:

您需要考虑这种方法的一些限制:insertRule()。建议的解决方案使用默认场景和第一个样式表上的操作(如果存在的话)。

测试

我在这里测试了它(桌面环境,在浏览器上),它适合我。 创建一个文件foo_bar.html:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <h1 class="test1">Hello</h1>
    <h1 class="test2">World</h1>
    <script>
      // JS code here
    </script>
  </body>
</html>

在脚本标签内部:

function demoLoop(){ // remove this line
    var elmnt = document.getElementsByTagName("style");
    if (elmnt.length === 0) {
        // there isn't style objects, so it's more interesting create one
        var newStyle = document.createElement("style");
        newStyle.innerHTML =
            "h1.test1 {" +
                "color: green;" +
            "}";
        document.getElementsByTagName("head")[0].appendChild(newStyle);
    } else {
        // Using CSSStyleSheet interface
        var firstCSS = document.styleSheets[0];
        firstCSS.insertRule("h1.test2{color:blue;}"); // at this way (without index specified), will be like an Array unshift() method
    }
} // remove this too
demoLoop(); // remove this too
demoLoop(); // remove this too

这个解决方案的另一种方法是使用CSSStyleDeclaration对象(w3schools和MDN的文档)。但是考虑到覆盖系统CSS上现有规则的风险,这可能并不有趣。


第7个选项:内联CSS

使用内联CSS。这解决了问题,尽管根据页面大小(代码行),代码的维护(由作者自己或其他指定人员)可能非常困难。

但根据您在机构中的角色背景或其web系统安全政策,这可能是您唯一可用的解决方案。

测试

创建一个文件_foobar.html:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <h1 style="color: green;">Hello</h1>
    <h1 style="color: blue;">World</h1>    
  </body>
</html>

严格地回答了加根提出的问题

一个浏览器应该如何渲染css是不连续的? 它是否应该生成一些数据结构,使用页面上所有的css样式,并使用它进行渲染? 还是按照看到的顺序使用样式信息进行渲染?

(引用改编)

为了得到更准确的答案,我建议阅读以下文章:

浏览器如何工作:现代网络浏览器的幕后 渲染树的构造、布局和油漆 “渲染”网页意味着什么? 浏览器渲染是如何工作的——在幕后 渲染- HTML标准 10渲染- HTML5

<style>标签属于<head>部分,与所有内容分开。

参考资料:W3C Specs和W3Schools