一角獣は夜に啼く

ただの日記です。

思ってることとか考えたこととか適当に書きます。 主にソフトウェア開発の話題を扱う 「ひだまりソケットは壊れない」 というブログもやってます。

HTML の style 要素と script 要素の中身のテキストの制限について

style タグの中身に CSS 書く場合って中身を HTML エスケープしなければいけない?』 と同僚に聞かれたので調べた。 しなくていいという認識だった (し、実際にそうだった) のだけど、HTML Standard のどこに書かれているのか見つけるのに時間がかかったのでメモ書き程度に書き残しておく。

Living Standard を参照しているため、将来的に参照先の文書と本記事での引用内容が食い違う可能性があることに注意されたし。

style 要素と script 要素は raw text 要素である

現在の WHATWG の HTML Living Standard の HTML 構文 (XHTML 構文ではない) では、5 種類の要素の種類が定義されている。 その中に 「raw text 要素」 という種類があり、style 要素と script 要素はここに含まれる。

Raw text 要素の説明として、次のようなことが書かれている。

Raw text, escapable raw text, and normal elements have a start tag to indicate where they begin, and an end tag to indicate where they end.

12 The HTML syntax — HTML Standard

Raw text elements can have text, though it has restrictions described below.

12 The HTML syntax — HTML Standard
12.1.2.6 Restrictions on the contents of raw text and escapable raw text elements

The text in raw text and escapable raw text elements must not contain any occurrences of the string "</" (U+003C LESS-THAN SIGN, U+002F SOLIDUS) followed by characters that case-insensitively match the tag name of the element followed by one of U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), U+000C FORM FEED (FF), U+000D CARRIAGE RETURN (CR), U+0020 SPACE, U+003E GREATER-THAN SIGN (>), or U+002F SOLIDUS (/).

12 The HTML syntax — HTML Standard

つまり raw text 要素は、開始タグで始まり、終了タグで終わるものであり、その中身としては終了タグと誤解されかねない文字列以外の任意の文字列を持つことができる、というものである。

style 要素と script 要素、それぞれの制限

上で見た raw text 要素としての制限の他に、それぞれの要素で中身のテキストの制限がある。

style 要素の制限

Content model についてみると、次のように書かれている。

Content model:
Depends on the value of the type attribute, but must match requirements described in prose below.

4 The elements of HTML — HTML Standard

type 属性によるようだが、常に満たすべき条件もあるようだ。 読み進めていくと、中身については次のような記述があった。

The textContent of a style element must match the style production in the following ABNF, the character set for which is Unicode. [ABNF]

style         = no-c-start *( c-start no-c-end c-end no-c-start )
no-c-start    = < any string that doesn't contain a substring that matches c-start >
c-start       = "<!--"
no-c-end      = < any string that doesn't contain a substring that matches c-end >
c-end         = "-->"

つまり、style 要素の中に 「<!--」 という文字列を記述する場合は、「-->」 と対応付ける必要があり、入れ子にすることもできない、ということである。

script 要素の制限

script 要素の Content model を見ると次のように書かれている。

Content model:
If there is no src attribute, depends on the value of the type attribute, but must match script content restrictions.
If there is a src attribute, the element must be either empty or contain only script documentation that also matches script content restrictions.

4 The elements of HTML — HTML Standard

script content restrictions を見ると、style 要素の場合と同じく、「<!--」 という文字列を記述する場合は、「-->」 と対応付ける必要があり、入れ子にすることもできないとのこと。 さらに、「<!--」 という文字列と 「-->」 という文字列の間には 「<script」 という文字列 (より正確にいうと、「t」 の後ろにタグ名の終了だとみなせる文字列がある文字列) を書くことはできない。

要素の中に記述する言語的に可能であれば、「<!--」 という文字列は 「<\!--」 にエスケープし、「</script」 という文字列は 「<\/script」 とエスケープする、という風にエスケープを行うのが安全だろう。 (って HTML Standard にも書いてる!)

過去の話

HTML 4.01 などでは、style 要素の中に 「</style」 *1 という文字列が書けないだけではなく、単なる 「</」 という文字列も書けないということになっていた。 詳細は次のエントリが詳しい。

*1:より正確には、この後ろにタグ名の終了とみなせる文字列がある場合