<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样式,并使用它进行渲染?

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


当前回答

警告:这个答案指的是样式标签上的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年以来,“属性已从当前规范中删除”。

其他回答

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

参考资料:W3C Specs和W3Schools

浏览器的真正功能是什么?

这又是一场理论与实践的辩论。没有真正的赢家。 首先让我给你们看一个CodePen:

https://codepen.io/dkellner/pen/gOzXGjz?editors=1100

CSS:

.jeff { background:red; transform:rotate(2deg); color:white; }

HTML:

<style> .jeff { margin:20% 0 0 20%; width:400px; } </style>
<div class="jeff">
  
    This is Jeff.

    <style> .jeff {background:blue; padding:40px;} </style>
</div>

<style> .jeff {background:green} </style>

解释

在这个例子中,我使用了4个不同的样式块。一个直接放在CodePen的CSS盒子里,他们会把它放在一个很好的地方,可能在头部之类的地方。下一个在div之前,然后在div里面,最后一个在div之后。杰夫现在经历了很多事。他是绿色的,因为这是最后一个规则告诉他的,但他也被旋转和定位,里面的文本是白色的,所以我们可以安全地说他已经阅读了样式标签告诉他的所有内容,并且:

应用了所有的样式块; 它们的应用顺序是正确的; 它们完全凌驾于彼此之上; 整个过程就像一个大样式表。

这就是发生的事情。

同样,浏览器是耐心的野兽。他们想让你享受互联网,而创建网站的人没有很好的纪律,所以浏览器进化到可以容忍他们疯狂的行为。

底线

是的,你可以在主体中放置样式标签 是的,正如你所期望的那样 尽可能避免,这是一个持续的争论,谁知道我们最终会在哪里结束。

我想这将因浏览器的不同而有所不同:全局显示规则可能会随着浏览器运行代码而更新。

当外部样式表加载延迟时,有时可以在全局显示规则中看到此类更改。类似的事情也可能发生在这里,但在如此短的连续时间内,它实际上没有被渲染。

无论如何,它都不是有效的HTML,所以我认为考虑它是徒劳的。<style>标签属于页面的头部部分。

我想这可能是关于有限上下文的问题,例如,非程序员用户使用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

在您的示例中,浏览器“不应该”做任何事情。HTML无效。要么触发错误恢复,要么解析器自行处理。

在有效实例中,多个样式表被视为一个接一个出现,级联计算正常。