开发者

Using <style> tags in the <body> with other HTML

开发者 https://www.devze.com 2022-12-30 00:57 出处:网络
<html> <body> <style type=\"text/css\"> p.first {color:blue} p.second {color:green} </style>
<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&开发者_如何学编程gt;

    <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>

How is a browser supposed to render css which is non contiguous? Is it supposed to generate some data structure using all the css styles on a page and use that for rendering?

Or does it render using style information in the order it sees?


WARNING: This answer refers the scoped attribute on style tag which should not be used anymore!

As others have already mentioned, HTML 4 requires the <style> tag to be placed in the <head> section (even though most browsers allow <style> tags within the body).

However, HTML 5 includes the scoped attribute (see update below), which allows you to create style sheets that are scoped within the parent element of the <style> tag. This also enables you to place <style> tags within the <body> element:

<!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>

If you render the above code in an HTML-5 enabled browser that supports scoped, you will see the limited scope of the style sheet.

There's just one major caveat...

At the time I'm writing this answer (May, 2013) almost no mainstream browser currently supports the scoped attribute. (Although apparently developer builds of Chromium support it.)

HOWEVER, there is an interesting implication of the scoped attribute that pertains to this question. It means that future browsers are mandated via the standard to allow <style> elements within the <body> (as long as the <style> elements are scoped.)

So, given that:

  • Almost every existing browser currently ignores the scoped attribute
  • Almost every existing browser currently allows <style> tags within the <body>
  • Future implementations will be required to allow (scoped) <style> tags within the <body>

...then there is literally no harm * in placing <style> tags within the body, as long as you future proof them with a scoped attribute. The only problem is that current browsers won't actually limit the scope of the stylesheet - they'll apply it to the whole document. But the point is that, for all practical purposes, you can include <style> tags within the <body> provided that you:

  • Future-proof your HTML by including the scoped attribute
  • Understand that as of now, the stylesheet within the <body> will not actually be scoped (because no mainstream browser support exists yet)

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

Finally, regarding the common (but subjective) claim that embedding CSS within HTML is poor practice, it should be noted that the whole point of the scoped attribute is to accommodate typical modern development frameworks that allow developers to import chunks of HTML as modules or syndicated content. It is very convenient to have embedded CSS that only applies to a particular chunk of HTML, in order to develop encapsulated, modular components with specific stylings.


Update as of Feb 2019, according to the Mozilla documentation, the scoped attribute is deprecated. Chrome stopped supporting it in version 36 (2014) and Firefox in version 62 (2018). In both cases, the feature had to be explicitly enabled by the user in the browsers' settings. No other major browser ever supported it.

The website Can I Use reports that the "attribute has been removed from the current specification." since 2016.


BREAKING BAD NEWS for "style in body" lovers: W3C has recently lost the HTML war against WHATWG, whose versionless HTML "Living Standard" has now become the official one, which, alas, does not allow STYLE in the BODY. The short-lived happy days are over. ;) The W3C validator also works by the WHATWG specs now. (Thanks @FrankConijn for the heads-up!)

(Note: this is the case "as of today", but since there's no versioning, links can become invalid at any moment without notice or control. Unless you're willing to link to its individual source commits at GitHub, you basically can no longer make stable references to the new official HTML standard, AFAIK. Please correct me if there's a canonical way of doing this properly.)

OBSOLETED GOOD NEWS:

Yay, STYLE is finally valid in BODY, as of HTML5.2! (And scoped is gone, too.)

From the W3C specs (relish the last line!):

4.2.6. The style element

...

Contexts in which this element can be used:

Where metadata content is expected.

In a noscript element that is a child of a head element.

In the body, where flow content is expected.


META SIDE-NOTE:

The mere fact that despite the damages of the "browser war" we still had to keep developing against two ridiculously competing "official" HTML "standards" (quotes for 1 standard + 1 standard < 1 standard) means that the "fallback to in-the-trenches common sense" approach to web development has never really ceased to apply.

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.


When I see that the big-site Content Management Systems routinely put some <style> elements (some, not all) close to the content that relies on those classes, I conclude that the horse is out of the barn.

Go look at page sources from cnn.com, nytimes.com, huffingtonpost.com, your nearest big-city newspaper, etc. All of them do this.

If there's a good reason to put an extra <style> section somewhere in the body -- for instance if you're include()ing diverse and independent page elements in real time and each has an embedded <style> of its own, and the organization will be cleaner, more modular, more understandable, and more maintainable -- I say just bite the bullet. Sure it would be better if we could have "local" style with restricted scope, like local variables, but you go to work with the HTML you have, not the HTML you might want or wish to have at a later time.

Of course there are potential drawbacks and good (if not always compelling) reasons to follow the orthodoxy, as others have elaborated. But to me it looks more and more like thoughtful use of <style> in <body> has already gone mainstream.


I guess this may be an issue about limited contexts, e.g. WYIWYG editors on a web system used by not-programmers users, that limits the possibilities of follow the standards. Sometimes (like TinyMCE), it's a lib that puts your content/code inside a textarea tag, that is rendered by the editor as a big div tag. And sometimes, it may be an old version of these editors.

I'm supposing that:

  1. these not-programmers users don't have an open channel with the system admins (or institution's webdevs), to ask for including some CSS rules at the system's stylesheets. Actually, it would be impractical for the admins (or webdevs), considering the number of requests in that sense that they would have.
  2. this system is legacy and still doesn't support newer versions of HTML.

In some cases, without use style rules, it may be a very poor design experience. So, yes, these users need customization. Okay, but what would be the solutions, in this scenario? Considering the different ways to insert CSS in a html page, I suppose these solutions:


1st option: ask your sysadm

Ask to your system adm for including some CSS rules at the system's stylesheets. This will be an external or internal CSS solution. As already said, it might be not possible.


2nd option: <link> on <body>

Use external style sheet on the body tag, i.e., use of the link tag inside the area you have access (that will be, on the site, inside the body tag and not in the head tag). Some sources says this is okay, but "not a good practice", like MDN:

A <link> element can occur either in the <head> or <body> element, depending on whether it has a link type that is body-ok. For example, the stylesheet link type is body-ok, and therefore <link rel="stylesheet"> is permitted in the body. However, this isn't a good practice to follow; it makes more sense to separate your <link> elements from your body content, putting them in the <head>.

Some others, restrict it to the <head> section, like w3schools:

Note: This element goes only in the head section, but it can appear any number of times.

Testing

I tested it here (desktop environment, on a browser) and it works for me. Create a file 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>

And then a CSS file, at the same directory, called bar.css:

.test1 { 
    color: green;
};

Well, this will just looks possible if you have how upload an CSS file somewhere at the institution system. Maybe this would be the case.


3rd option: <style> on <body>

Use internet style sheet on the body tag, i.e., use of the style tag inside the area you have access (that will be, on the site, inside the body tag and not in the head tag). This is what Charles Salvia's and Sz's answers here are about. Choosing this option, consider their concerns.


4th, 5th and 6th options: JS ways

Alert These ones are related to modifying the <head> element of the page. Maybe this will not be allowed by the institution's system administrators. So, it's recommended to ask them permission first.

Okay, supposing permission granted, the strategy is access the <head>. How? JavaScript methods.

4th option: new <link> on <head>

This is another version of the 2nd option. Use external style sheet on the <head> tag, i.e., use of the <link> element outside the area you have access (that will be, on the site, not inside the body tag and yes inside the head tag). This solution complies with the recommendations of MDN and w3schools, as cited above, on 2nd option solution. A new Link object will be created.

To solve the matter through JS, there are many ways but at the following codelines I demonstrate one simple.

Testing

I tested it here (desktop environment, on a browser) and it works for me. Create a file 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>

Inside the script tag:

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

And then at the CSS file, at the same directory, called bar.css (as at the 2nd option):

.test1 { 
    color: green;
};

As I already said: this will just looks possible if you have how upload an CSS file somewhere at the institution system.

5th option: new <style> on <head>

Use new internal style sheet on the <head> tag, i.e., use of a new <style> element outside the area you have access (that will be, on the site, not inside the body tag and yes inside the head tag). A new Style object will be created.

This is solved through JS. One simple way is demonstrated following.

Testing

I tested it here (desktop environment, on a browser) and it works for me. Create a file 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>

Inside the script tag:

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

6th option: using an existing <style> on <head>

Use an existing internal style sheet on the <head> tag, i.e., use of a <style> element outside the area you have access (that will be, on the site, not inside the body tag and yes inside the head tag), if some exists. A new Style object will be created or a CSSStyleSheet object will be used (in the code of the solution adopted here).

This is at some point of view risky. First, because it may not exists some <style> object. Depending of the way you implement this solution, you may get undefined return (the system may use external style sheet). Second, because you will be editing the system design author's work (authorship issues). Third, because it may not be allowed at your institution's IT politics of safety. So, do ask permission to do this (as at in other JS solutions).

Supposing, again, permission was granted:

You will need to consider some restrictions of the method available to this way: insertRule(). The solution proposed uses the default scenario, and a operation at the first stylesheet, if some exists.

Testing

I tested it here (desktop environment, on a browser) and it works for me. Create a file 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>

Inside the script tag:

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

Another approach to this solution it's using CSSStyleDeclaration object (docs at w3schools and MDN). But it may not be interesting, considering the risk to override existing rules on the system's CSS.


7th option: inline CSS

Use inline CSS. This solve the problem, although depending of the page size (in code lines), the maintenance (by the author itself or other assigned person) of code can be very difficult.

But depending of the context of your role at the institution, or its web system security policies, this might be the unique available solution to you.

Testing

Create a file _foobar.html:

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

Answering strictly the question asked by Gagan

How is a browser supposed to render css which is non contiguous?

  1. Is it supposed to generate some data structure using all the css styles on a page and use that for rendering?
  2. Or does it render using style information in the order it sees?

(quote adapted)

For a more accurate answer, I suggest Google these articles:

  • How Browsers Work: Behind the scenes of modern web browsers
  • Render-tree Construction, Layout, and Paint
  • What Does It Mean To “Render” a Webpage?
  • How browser rendering works — behind the scenes
  • Rendering - HTML Standard
  • 10 Rendering — HTML5


Not valid HTML, anyway pretty much every browser seems to consider just the second instance.

Tested under the last versions of FF and Google Chrome under Fedora, and FF, Opera, IE, and Chrome under XP.


I guess this will vary from browser to browser: The global display rules will probably be updated as the browser goes along through the code.

You can see such changes in the global display rules sometimes when an external style sheet is loaded with a delay. Something similar might happen here but in such short succession that it doesn't actually get rendered.

It's not valid HTML anyway, so I'd say that it is a futile thing to think about. <style> tags belong in the head section of the page.


As others have said, this isn't valid html as the style tags belong in the head.

However, most browsers dont' really enforce that validation. Instead, once the document is loaded then the styles are merged and applied. In this case the second set of styles will always override the first because they were the last definitions encountered.


The <style> tag belongs in the <head> section, separate from all the content.

References: W3C Specs and W3Schools


In your example, a browser isn't "supposed" to do anything. The HTML is invalid. Either error recovery is triggered, or the parser makes of it as it will.

In a valid instance, multiple stylesheets are just treated as appearing one after the other, the cascade is calculated as normal.


Because this is HTML is not valid does not have any affect on the outcome ... it just means that the HTML does adhere to the standard (merely for organizational purposes). For the sake of being valid it could have been written this way:

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

My guess is that the browser applies the last style it comes across.


What browsers really do...

Again, this is a theory vs practice debate. No real winners.
First of all let me show you a 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>
    

Explanation

In this example, I used 4 different style blocks. One directly in the CSS box of CodePen, they'll put it somewhere nice, probably in the head, whatever. The next one is right before the div, then one inside the div, and the last one is after it. Jeff is going through a lot right now. He's green, because that's what the last rule told him, but he's also rotated and positioned and the text inside is white, so we can safely say he's read everything the style tags told him, and:

  • All style blocks were applied;
  • They were applied in the correct order;
  • They properly override each other;
  • The whole thing acts like one big stylesheet.

That's what happens.

Again, browsers are patient beasts. They want you to enjoy the internet, and people creating websites are not very well disciplined so browsers evolved to tolerate their insane behaviour.

Bottom line

  1. Yes you can put style tags in the body
  2. Yes it works as you'd expect
  3. Avoid if possible, it's an ongoing debate, who knows where we end up.


Yes it can. I checked on Mozilla's page. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style


I think you can get completely legal "scoped styles" in modern browsers with a small amount of effort. Consider this HTML document:

<!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>

I used a template to enclose HTML that I wanted to contain its own style element that doesn't affect any HTML outside that template. Of course, by default, a template is ignored during rendering. So the JavaScript code

  1. locates each template in the document
  2. creates a detached empty div
  3. gives the div a "shadow root" (the key to localizing a style)
  4. copies the template contents to the shadow root
  5. replaces the original template with the div that contains the same stuff (except in a shadow root)

Almost any HTML content--including style-- is legal inside a template.

Tested with the latest Chrome/Firefox/Edge. Send me a free MacBook Pro and I'll test it with Safari! :-)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号