style and script tags in HTML body... why not?

Although the specs explicitly state style tags are not permitted in the body tag, specs aren't all that matters. Style tags are supported in the body by every major browser, and that's ultimately how users see your site.* While there has long been a drive for better standards and standards support in the browser industry, there's also long been a general push to render broken documents as well as can be.

Google, who leads the HTML5 spec effort, simultaneously maintains google.com which violates specs to save bytes, by leaving the quotes out of its attribute values, using selector hacks against the CSS spec, including script tags with no type or language, and link tags with no type. A purist could argue one of the most used sites on the internet is violating the specs and in serious danger of being horribly misrendered. Or, we can reason that no browser will enter popular use that can't render such widely used hacks on the spec.

So, the question is more of which way the browser industry is going - which again is one of both better specs, but also doing their best to honor the intent of pages that violate those specs. My bet is style tags will keep working in the body for a long time to come.

*As of this writing, style tags in the body are supported with an HTML5 doctype in Firefox 3+, IE6+, Safari 2+, Chrome 12+. Support likely goes back farther but those browsers are rarely seen on the interwebs.


The contexts in which the <script> and <style> tags can be used depends on the doctype you're using. For instance, I'll assume you're using the HTML5 doctype:

<!DOCTYPE html>

The script tag has three contexts under the HTML5 doctype:

  1. Where metadata content is expected.
  2. Where phrasing content is expected.
  3. Where script-supporting elements are expected.

The style tag has a slightly more complicated context-structure under the HTML5 doctype:

  1. If the scoped attribute is absent: where metadata content is expected.
  2. If the scoped attribute is absent: in a noscript element that is a child of a head element.
  3. If the scoped attribute is present: where flow content is expected, but before any other flow content other than inter-element whitespace and style elements, and not as the child of an element whose content model is transparent.

Essentially, this states that you can place the style tag and the script tag in the body, since the body is where we place flow content, and phrasing content.

As always, consult the spec for the doctype you're using.


The short answer:

  • STYLE element is only allowed as child of the HEAD element
  • SCRIPT element is allowed as child of the HEAD element, the BODY element and wherever inline-level elements are allowed.

The detailed answer:

STYLE is defined to be in head.misc:

<!ENTITY % head.misc "SCRIPT|STYLE|META|LINK|OBJECT" -- repeatable head elements -->

And elements of head.misc are only allowed to be children of the HEAD element. So STYLE is only allowed to be child of the HEAD element.

SCRIPT is defined to be in head.misc and in special:

<!ENTITY % special
   "A | IMG | OBJECT | BR | SCRIPT | MAP | Q | SUB | SUP | SPAN | BDO">

And special is defined to be in inline:

<!ENTITY % inline "#PCDATA | %fontstyle; | %phrase; | %special; | %formctrl;">

Additionally SCRIPT is also allowed to be child of the BODY element. So SCRIPT is allowed in the HEAD element nad wherever inline is allowed.


Two possible answers for style in the body:

  1. Use inline styling. True, you'll lose the advantages of internal and external styling, but if you don't have access to the header, then you don't have access to the header.

  2. Use the scoped attribute in the style element. This is new to HTML5, but the idea is to limit the scope of the CSS to a part of a page, for example to a single div. The bad news is that it is not yet supported (as of July 2011), nor is it backwards compatible. But there is (allegedly) a JQuery plugin that can help. For more info:

    • http://thingsinjars.com/post/359/css-scoped/
    • http://thingsinjars.com/post/360/scoped-style/