Reputation: 947
I have a site where I have a <noscript>
tag below my <script>
tag in case the javascript fails to load. It basically turns off some CSS values to do with some smooth scroll JS code and a pre-loader.
However when I run the site through the w3c HTML validator it says:
Element style not allowed as child of element noscript in this context. (Suppressing further errors from this subtree.)
The code I'm using is:
<noscript>
<style type="text/css" media="screen">#main-body {opacity: 1 !important; } .viewport {position: static; overflow: visible;} h1, h2, h3 {opacity: 1} .st-ca-title, .st-ca-sub, .st-co-title, .st-co-sub, .js-client-stagger, .btn, .btn a, .st-ho-title, .st-ho-sub, .st-ho-p {opacity: 1}
</style>
</noscript>
This code does do what I want it to (i.e. ensures the site still works OK if the JS fails to load), but have I done something wrong here to get this error?
I can't put the <noscript>
tag in the head of the document because it has to come after the main js script tag.
Any suggestions are most welcome.
Paul.
Upvotes: 2
Views: 2678
Reputation: 172
For those arriving here with the same question years later like me: Putting a style tag inside a noscript tag is not only valid, it's explicitly mentioned by the HTML specs (WHATWG, and lately W3):
4.2.6 The style element
Categories:
Metadata content.
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.
...but note the "is a child of a head element." Are we supposed to read between the lines that you can't do that outside of a head element? What about style tags more generally?
Practically speaking, it seems cleanest to try to minimize doing this at all, like jaasum said, but I also ran into a scenario where I needed it: progressive enhancement of a site where I wanted an element invisible until it was enabled later, unless JavaScript wasn't enabled, in which case it should be visible from the start. But, if I start it visible and hide it on load (the "having a class that applies your styles, and then removing that class with JavaScript" approach jaasum mentioned) there's a flicker that registers as a layout shift. Using a noscript tag to apply a simple style to override the display in the noscript case covers all the angles. If you make the logic simple enough that it can happen in the page head, then everything validates happily, too.
Down the rabbit hole of "where are you allowed to put a style tag":
It says you can put a style element "where metadata content is expected", and the link for metadata content gives examples of stuff inside head
, but it doesn't say they have to be there. I tried searching for other interpretations, and this answer links to the same WHATWG definition I had found and interprets it to say that style tags are not allowed in the body. It looks like the W3C definition previously had the text "in the body, where flow content is expected," but took it out later when syncing with WHATWG (implying it's now not OK after all?) The W3 validator yells at me if I try to put one in with a Element style not allowed as child of element body in this context
message, so that seems to be the case, even though it isn't explicitly spelled out.
If you instead come at it with the question, "what's allowed as a child of a body element," that's listed as flow content only, and flow content does not include style elements (even though some elements that are metadata content are also flow content). So there you have it.
Whew. This is what I get for trying to wrap my head around these ever-changing specs.
Upvotes: 0
Reputation: 586
I agree with @jaasum don't mix them like that
regardless it wouldn't have the restricted affect you are looking for, scope the css like so.. here the color red is applied inside the noscript tag, otherwise green is applied.
<!DOCTYPE html>
<html>
<head>
<style>
.danger {
color: green; font-weight: bold;
}
noscript .danger {
color: red; font-weight: bold;
}
</style>
<script>
function myStuff() {
let p = document.createElement('p');
p.innerHTML = '<p>you seem to have <span class="danger">scripts enabled...</span></p>';
document.body.appendChild( p);
}
</script>
</head>
<body onload="myStuff()">
<noscript>
<h1>Script</h1>
<p>you need <span class="danger">scripts enabled</span></p>
</noscript>
</body>
</html>
Upvotes: 0
Reputation: 558
There doesn't appear to be any reason why this code would be considered invalid. A <style>
element is a valid child of a <noscript>
element and both are valid children of either <head>
or <body>
.
Typically though you want to avoid mixing your markup with your scripts and styling. I'd recommend having a class that applies your styles, and then removing that class with JavaScript. This way to you can keep your styles in one place and then include the logic to remove those styles along with your script avoiding the nested <noscript>
and <style>
approach entirely.
<!DOCTYPE html>
<html>
<head>
<style>
.no-js {
/* "no script" styles here */
}
</style>
</head>
<body class="no-js">
<script>
document.querySelector('body').classList.remove('no-js');
</script>
</body>
</html>
Upvotes: 2