Short answer
According to the current spec, yes, style
elements must always be in the head
. There are no exceptions (except a style
element inside a template
element, if you want to count that).
This has not always been the case historically. If you care about the details of the spec and its history, keep reading.
No matter what the spec says, using style
elements in the body
does more-or-less work in all major browsers. However, it is considered a bad practice both because it violates spec and because it can cause undesirable consequences like worse rendering performance or a "flash of unstyled content".
Spec history
style
elements didn't exist in HTML 2. They were introduced in HTML 3.0, where they were included in the list of elements that could be included in The Head Element, but not included in the list of elements that could be present in The Body Element. Thus, at the moment the element was first specced, it could only be included in the head
.
This remained the case (albeit expressed using different wording) until HTML 5, which introduced the (since removed) scoped
attribute for style
elements. This attribute, when present, was meant to allow a style
element to be placed within an element in the body to style only that element's descendants. However, that feature never made it to any real browser (at least not without needing to be enabled via a developer flag) and was removed from both the W3C and WhatWG specs "due to lack of implementer interest". Thereafter, style
elements were only permitted in contexts that allow metadata content, which is only the head. Thus we were back to the same rules as before HTML 5.
However, due to an error made by both spec organisations, a non-normative index of elements included as an appendix in both specs was not properly updated to reflect the removal of scoped
, rendering it inconsistent with the normative spec. I pointed this out both to the WhatWG and to the W3C, and in doing so unwittingly set in motion events that caused the two specs to diverge.
WhatWG's solution to the inconsistency between the normative spec and non-normative index was to accept my patch correcting the non-normative index.
The W3C, on the other hand, rejected my equivalent patch in favour of instead updating the normative spec to allow the use of style
elements in the body
, while caveating this with a note that it can cause problems and should be done "with care". The reasoning behind this change was to make the spec align with real-life browser behaviour.
Thus, from March 2017, it was the case that the official answer to this question depended upon which standards organisation you chose to listen to. If you listed to the (generally more respected) WhatWG spec, then a style
element was not allowed in the body
. If you listed to the W3C spec, then it was allowed, but not recommended.
This silly state of affairs was ended (perhaps like many other such inconsistencies) with the April 2019 peace treaty between W3C and WhatWG, which agreed that the WhatWG spec would become the one true living HTML standard, with W3C merely releasing snapshots from it as numbered HTML specifications instead of developing a competing spec in parallel. Thus, the change from 2017 to the W3C fork that allowed style
elements in the body
is no longer part of any current spec; it is merely a curiosity of history.
So, today, we need only look to the WhatWG spec to determine what is officially allowed. It has this to say:
4.2.6. The style
element
Metadata content.
Where metadata content is expected.
In a <noscript>
element that is a child of a <head>
element.
CTRL-Fing through the single-page spec reveals that the only element whose content model includes metadata content is the head
element.
The non-normative index of elements I mentioned fixing earlier also confirms that the only permissible parents for a style
element are a head
or noscript
element.
style
in thebody
, so that's good enough for me, regardless of what's implied by the author guideline sections. – Immersed