◆ 「document.implementation.createDocumentType」 で作れる
◆ 「document.doctype」 と replace する
◆ 変えても互換(Quirks)モードか標準モードかは変わらない
   ◆ document.compatMode で確認できる
◆ document.write で新しく一から DOM を doctype 付きで作れば変えられる

doctype へアクセス

JavaScript で doctype を変えたくなったので調べてみました
doctype は
document.doctype

でアクセスできます
プロパティを見ればそれぞれの情報が取得できます

document.doctype.name
// "html"

document.doctype.publicId
// "-//W3C//DTD XHTML 1.0 Transitional//EN"

document.doctype.systemId
// "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"

でも変えることはできません

document.doctype.publicId
// "-//W3C//DTD HTML 4.01 Transitional//EN"
document.doctype.publicId = "-//W3C//DTD HTML 4.01//EN"
document.doctype.publicId
// "-//W3C//DTD HTML 4.01 Transitional//EN"

transitional なものを strict にしてみようとしましたがダメでした

doctype を変える

プロパティを変えれないなら doctype オブジェクトごと置き換えようと思ったのですが doctype って作れるものだっけ?


作った記憶ないですし document のメソッドを調べてもそれらしいのはありません
ググってみるとこうやってできるみたいでした

var doctype = document.implementation.createDocumentType("html", "", "")
document.doctype.replaceWith(doctype)

これはすでにある場合に置き換える方法で doctype 宣言がない場合には append (prepend) します
※ Chrome は append で body の後ろに doctype 置くこともできますが Firefox はエラーでした

var doctype = document.implementation.createDocumentType("html", "", "")
document.append(doctype)

本当にやりたかったこと

上の方法で doctype は変わりました
doctype は

ただやりたかったのは 「本当に doctype を変えるだけ」 じゃないんです
実際に変えても何も変化がないですし

transitional と strict のモードで HTML や CSS の挙動が変わるので strict モードに切り替えたいというのが目的です
特に about:blank で画面作ってると 互換モードになってるので HTML5 の doctype 付きのページに移植すると動かなかったりもします
html と body にも height の 100% が必要とか単位 px が必要とか

Quirks モード

HTML/CSS の解釈の違いなどのモードの違いは doctype が strict か transitional かの違いで決まってると思ってたのですが 調べてみると正確には違うようでした
transitional かつ URL がない場合に互換モードになるようです
もちろん doctype 自体がない場合もです

またこの互換モードには Quirks モードという名前がついてるようです

互換モードを調べていると 標準と互換モードの違いに 上で書いた「height の 100%」と「単位 (px など) が必要」以外にこんなものがありました

  • フォントサイズが small がデフォルトサイズになる
  • margin を auto にしてもセンタリングしない
  • デフォルトの box-sizing が border-box

これらは doctype 調べてるときにも見かけますし 昔 doctype を調べてた頃に サイズに padding が含んだり含まれなかったりで困った覚えがありますし フォントサイズの small や medium の指定がページによってサイズが違ってた覚えがあります

ですが URL なしの HTML4.01 のページや doctype なしの about:blank で試してもこれらの特徴は起きませんでした

フォントサイズを small にするとデフォルトより縮みますし margin:auto をつければセンタリングしますし width に padding は含みません
Chrome だけでなく Firefox も一緒でした


MDN には違いをまとめたページがあり ここではフォントサイズが違ったり margin が auto になるとは書かれていません
box-sizing は input と textarea でのみ適用されるようです

Quirks モードを変えたい

doctype を変えても 実際の挙動 (height: 100% など) は変わりませんでした

モードを確認する方法を調べてみると Firefox だと右クリックの 「ページの情報を表示」 からページ情報を開いて 描画モードを見ればわかります
後方互換モードと標準準拠モード | MDN

Quirks モードだと 「Quirks (後方互換) モード」
標準モードだと「Standards Compliant (標準準拠) モード」

と表示されます

Chrome だとこういう確認はできないみたいですが JavaScript でモードが取得できました
document.compatMode | MDN

document.doctype
// <!DOCTYPE html>
document.compatMode
// "CSS1Compat"
document.doctype
// null
document.compatMode
// "BackCompat"

もしかすると ここを変えるとモードが変わったり?

やってみると読み取り専用らしく 代入しても変化ありませんでした
なんとなくそんな気はしてましたけどね

document 全体を新しく作るしかないみたい

doctype を置き換えたあとに html 要素から全部を置き換えてみたり display: none にして戻してみたり試したのですが 全然ダメでした
StackOverlow を見てみると document を再び open して作り直す方法が紹介されていました

他に方法なさそうですし この方法しかなさそうです

document.write("<!doctype html>\n" + document.documentElement.outerHTML)

やってみると element タブで確認して doctype が表示されていて compatMode も CSS1Compat になっていました
特徴も標準モードのものになっています


ただ この方法は document を開いて HTML を再度パースして DOM を構築しています
html 要素の outerElement を使うので DOM の構造や各要素の属性は一緒になりますが  script タグは再び実行されますし 構造は一緒でも各要素は別物になるので 変数に保存していた要素や 要素のプロパティに保存していた値は使えなくなります
about:blank を使う時最初に実行する使い方なら問題ないですが 既存ページに使うのは問題がでるかもしれません



ところで transitional がよく traditional になってしまいます
似てる上に 言葉としても 古いものだから traditional で自然なのであまり違和感ないんですよね