Inline scripts: sometimes the web is just screwed up

I don’t know about you, but one of my favorite commands in the browser is “View Page Source”, especially on a site that’s modern, visually attractive, or shows off some clever interactions. After all, I’m a developer: I like to find out how things work so I can, if I want to, replicate on my own web sites.

Sculpture in New OrleansSome web pages though are really nasty when you look at their source. And one of the places they excel at nastiness is in their use of inline scripts. Now, don’t get me wrong, I’m not particularly objecting to inline scripts: sometimes they’re the biz when you just have some minor bit of JavaScript to execute, so minor it doesn’t seem efficient to create a brand new JS file and add the external script tag to the HTML on the page. And then sometimes you get web pages that can’t seem to decide how the heck they should represent inline scripts and throw everything but the kitchen sink at the problem.

Let’s take a look at the three main ways you can insert inline scripts into your HTML. First, there’s the obvious way, just unadorned:

<script type="text/javascript">
    $(function () {
        var inputText = $("#inputtext"),
            outputMath = $("#outputmath"),
            inlineMath = $("#inlinemath");

        inputText.on("keyup", function () {
            var expr = inputText.val();
            outputMath.text('\\[ ' + expr + ' \\]');
            inlineMath.text('The expression is <\\( ' + expr + ' \\)>.');
            MathJax.Hub.Queue(["Typeset", MathJax.Hub, "outputmath"]);
            MathJax.Hub.Queue(["Typeset", MathJax.Hub, "inlinemath"]);
        });

    });
<script>

Then, from way back when, there was the attempt to circumvent those browsers that didn’t support inline JavaScript by enclosing the code in HTML comments:

<script type="text/javascript">
    <!--
    $(function () {
        var inputText = $("#inputtext"),
            outputMath = $("#outputmath"),
            inlineMath = $("#inlinemath");

        inputText.on("keyup", function () {
            var expr = inputText.val();
            outputMath.text('\\[ ' + expr + ' \\]');
            inlineMath.text('The expression is < \\( ' + expr + ' \\) >.');
            MathJax.Hub.Queue(["Typeset", MathJax.Hub, "outputmath"]);
            MathJax.Hub.Queue(["Typeset", MathJax.Hub, "inlinemath"]);
        });

    });
    // -->
<script>

Notice that (1) the opening HTML comment tag is allowed to be “bare” (it’s not counted as part of the JavaScript code) but the closing end-comment tag must be itself commented out in the inline JavaScript.

Finally there’s the CDATA approach, which just seems wacky until you understand why it’s used:

<script type="text/javascript">
    // <!--[CDATA[
    $(function () {
        var inputText = $("#inputtext"),
            outputMath = $("#outputmath"),
            inlineMath = $("#inlinemath");

        inputText.on("keyup", function () {
            var expr = inputText.val();
            outputMath.text('\\[ ' + expr + ' \\]');
            inlineMath.text('The expression is < \\( ' + expr + ' \\) >.');
            MathJax.Hub.Queue(["Typeset", MathJax.Hub, "outputmath"]);
            MathJax.Hub.Queue(["Typeset", MathJax.Hub, "inlinemath"]);
        });

    });
    // ]]>
<script>

So what’s up with all this? Why the three different methods?

The first point to recognize is that there are two characters that should never be used un-escaped in HTML: the less-than angle bracket (<) and the ampersand (&). In the inline code I’m showing in method 1, there’s a left angle bracket. Luckily, in HTML, text that appears in a script element can contain these two characters un-escaped. (The only thing that cannot appear in a script element is the string “-->”, since that signals the end of the script.) So, with all modern day browsers, this kind of unadorned inline script is accepted in an HTML file without issues (except for one special case, which I’ll come to in a moment).

Batman slaps Robin about inline scriptMethod 2 was used purely for those browsers that didn’t understand inline scripts. To be exact, the <script> tag was introduced in HTML 3.2 as a placeholder and browsers from that point on would no longer display the inline code as text when displaying the page – which is what happened prior to that. If you can remember those days, more power to you; I certainly can’t. So, back in the dim and distant past the inline code had to be commented out HTML-wise to make sure it wasn’t displayed by a horse-drawn user agent. Fast forward to the 21st century where even – shock, horror – IE6 recognized inline script. Method 2 then is not required ever, anymore. Just say no. (Incidentally there’s another issue with the “commented out” inline script: the code could not contain dash-dash (--), since it was that character sequence that officially denoted the end of the comment. So no post- or pre-decrements in your code, OK?)

Method 3 is an interesting one. It’s the only allowed way to have general text embedded in an XML file that isn’t going to be parsed as XML. Hence it’s the only way to have valid un-escaped less-than signs or ampersands in the XML file. And, of course, an HTML file that is flagged as XHTML in the file’s DOCTYPE is supposed to be valid XML. However, that’s not the end of the story. Basically browsers have two parsers: an HTML parser and an XML parser, with the HTML parser being used the vast majority of the time. This is true even in the case of an HTML file flagged as XHTML in the DOCTYPE: the HTML parser will be used. Since the CDATA section is not part of the HTML spec, both the start and end CDATA tags are just ignored: and this is especially so since they are both commented out in the inline script. The only time the CDATA section is parsed as such is if (a) the HTML file is flagged as XHTML, and (b) the HTTP response header sent by the web server marks the content as the “application/xhtml+xml” MIME type. In this case, the XML parser is executed on the content and your inline script had better be in a CDATA section just in case.

So, where does this leave you?

Now isn’t that all just simple?

Album cover for Luck Be A Weirdo TonightNow playing:
Fila Brazillia - Pollo De Palo
(from Luck Be A Weirdo Tonight)


Loading similar posts...   Loading links to posts on similar topics...

6 Responses

julian m bucknall avatar
#1 julian m bucknall said...
01-Apr-13 9:03 PM

All: just realized something else. If you do go for method 3 and set up your web server's response content-type properly and you have some inline script blocks written with method 2, they will magically have disappeared in the browser. Comments in "XML parsing mode" are thrown away, whereas comments in HTML parsing mode stick around and will be further parsed... Boom!

Cheers, Julian

julian m bucknall avatar
#2 julian m bucknall said...
02-Apr-13 10:42 AM

All: Added the Batman cartoon: Mehul Harry made me do it...

Cheers, Julian

 avatar
#3 Drew Wells said...
03-Apr-13 10:23 AM

Inserting inline soundtrack --

Filla Brazilla - Pollo de Palo - YouTube

 avatar
#4 Richard said...
24-Apr-13 12:17 PM

If you're writing HTML5, you don't need the type attribute either:

<script>
$(function(){
   ...
});
</script> 
julian m bucknall avatar
#5 julian m bucknall said...
24-Apr-13 1:54 PM

Richard: Cool, didn't know that.

For other readers, here's the reference: 'The type attribute (of the script element) gives the language of the script or format of the data. [...] The default, which is used if the attribute is absent, is "text/javascript".'

Cheers, Julian

 avatar
#6 Mehul Harry said...
24-Apr-13 2:58 PM

Gotta join this party! :)

Great post and good advice here:

First, just avoid inline script.

However, I reserve the right to do this in the future. Sometimes it's just convenient during a demo or sample code. #muhahahaha

Richard, nice catch. Better than to just always define the type since cross-browser is still a concern.

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response