HTMLで文字エンコーディングを指定する

対象の読者: HTML制作者(編集者でもコーダーでも)や、スクリプト開発者(PHPやJSPなど)、ウェブ・プロジェクト・マネージャー、そしてどうやればHTMLファイルへ文字エンコーディングを指定できるかの解説を必要とする人々。

Question

どうやって私のHTML5ファイルのエンコーディングを指定すれば良いのでしょうか?

HTMLやXMLのページで使われているエンコーディングは常に指定するべきです。もし指定しないと、コンテンツ内の文字が誤って解釈される可能性があります。それは単に人が読めるかどうかという問題であるだけでなく、コンピューターがデータを処理する必要がますます出てきたからでもあります。また文字エンコーディングは、フォームへ入力されたり、スクリプトにより生成されたURLなどなど、非ASCII文字を処理する際にも必要になります。

もし文字や文字エンコーディングについてちゃんと理解する必要がありそうなら、Character encodings for beginnersも参照しましょう。またCSSでエンコーディングを指定する方法については、CSS character encoding declarationsを参照しましょう。

Quick answer

meta要素でcharset属性を使うか、http-equivcontent属性(プラグマ・ディレクティブと呼ばれています)を使って、常に文書へエンコーディングを指定しましょう。この指定は必ずファイルの先頭から1024バイトまでに含まれるべきであるため、head開始タグの直後に置くのが最善でしょう。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
...

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
...

どちらの方法で指定しても構いませんが、前者の方が書きやすいはずです。またUTF-8でもutf-8でも問題ありません。

文字エンコーディングは常にUTF-8を使用するべきです(UTF-8でファイルを保存することも忘れないようにしてください)。どうしてもUTF-8を使えない場合は、考慮すべきことを参照してください。

ウェブ・サーバーの設定をする権限があるならば、HTTPヘッダーを利用するのも悪くないことも頭に入れておくべきです。しかしながら注意点として、HTTPヘッダーによる指定の方が文書内でのmeta指定よりも優先度が高いため、ページ製作者は既にHTTPヘッダーで文字エンコーディングが指定されているかどうかについて常に頭の中に入れておくべきです。もし既に指定されている場合、meta要素では同じエンコーディングを指定しなければなりません。

HTTPヘッダーとして送信される文字エンコーディングはInternationalization Checkerを利用すると確認できるでしょう。

Details

バイトオーダーマークとはなんですか?

UTF-8のバイトオーダーマーク(BOM)がファイルの先頭にある場合、Internet Explorer 10や11以外の最近のブラウザーはそれを使ってウェブページのエンコーディングをUTF-8と決定します。この仕組みはHTTPヘッダーを含めたあらゆる指定方法より高い優先度を持ちます。

BOMがあるならmetaでのエンコーディング指定をしなくても良いですが、指定することをお勧めします。そのページがどのエンコーディングなのかをソースコードを参照するだけで誰にでもわかるからです。

バイトオーダーマークについてを参照してください。

HTTPヘッダーでエンコーディングを指定するべきですか?

仕組みを理解しており、可能であるなら、どのようなコンテンツであれHTTPヘッダーでエンコーディングを指定しましょう。しかし必ず同時に文書内での指定も行うべきです。

ページ製作者はHTTPによる指定と文書内での指定を確実に一致させるべきです。

HTTPヘッダーを利用するメリットとデメリット

HTTPヘッダーを利用するメリットとしては、まずHTTPヘッダーを受信し次第ユーザーエージェントが文字エンコーディングの情報を確認できることでしょう。

一方、デメリットもいくつか考えられます:

  • 製作者がウェブサーバー — 特にISPが管理している — 上にある静的なファイルのエンコーディング情報を変更しづらくするかもしれません。制作者はウェブサーバーの設定方法を理解しているだけでなく、実際にアクセスする必要もあるでしょう。

  • ウェブサーバーでの設定は、様々な理由でドキュメント側での指定とずれてしまうことがあります。例えばウェブサーバーのデフォルト設定に依存していた場合、そのデフォルトが変更されてしまうとずれるでしょう。これはかなりまずい状況です。HTTPヘッダーによる指定が文書内での指定より優先されてしまうため、文書が読めなくなってしまうかもしれません。

  • ウェブサーバーを経由しない場合、静的であっても動的であっても問題が起こる可能性があります。例えば、CDやハードディスクから読み込まれる場合などがそうです。このような場合、HTTPヘッダーからエンコーディング情報を得ることはできません。

    ファイルが編集される時やXSLTやスクリプトで処理される時、翻訳のために送信される時などに同じように、HTTPヘッダーのみで文字エンコーディングが指定されていた場合、同じようにエンコーディング情報を利用することはできません。

この指定方法を利用すべきですか?

ウェブサーバーからHTTPでファイルを配信するなら、HTTPヘッダーにより文字エンコーディングについての情報を送ることは、その情報が間違っていない限りまったく問題ないでしょう。

一方で上記デメリットのことも考え、同時に文書内でも常にエンコーディングを指定することをお勧めします。文書内での指定は開発者やテスター、翻訳マネージャーなど、文書のエンコーディングを確認したい人たちの役に立ちます。

(文書内でエンコーディングを指定するつもりならば、HTTPヘッダーでもそれを指定することが適切であるとは到底考えられない、という人もいます。この場合、HTTPヘッダーでは文書のエンコーディングについて何も教えないようにするわけです。ウェブサーバーのデフォルト設定を無効にすることをお忘れなく。)

PolyglotやXMLフォーマットへの対応

XHTML5: XML文法が使われており、かつXMLとして配信されているXHTML5文書です。XMLパーサーはmeta要素を使ったエンコーディング指定を認識せず、XML宣言だけ認識します。以下は例です:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html ....

XML宣言はUTF-8(もしくはUTF-16)でページが配信されない場合にのみ必須ですが、含めることで開発者やテスター、翻訳マネージャーなどがソースから文書のエンコーディングを確認でき、有用でしょう。

Polyglot markup: Polyglot markupを利用しているページはXML文法によるHTMLのサブセットで書かれており、HTMLパーサーでもXMLパーサーでもパースすることができます。これはPolyglot Markup: A robust profile of the HTML5 vocabularyで定義されています。

Polyglot文書はUTF-8でなければならず、XML宣言は必要ないどころか、指定してはいけません。その一方でそのファイルはHTMLとして読まれるため、meta要素やバイトオーダーマーク、そしてHTTPヘッダーのどれかでエンコーディングを指定する必要があるでしょう。

meta要素による指定はHTMLパーサーでのみ認識されることを考えると、content属性を使う方法の場合、その値はtext/html;で始めるべきです。

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

meta要素でcharset属性を使うならこの辺りのことは考える必要はありません。

Additional information

このセクションの情報は通常知る必要はありませんが、網羅するために含めます。

非UTF-8なエンコーディングの扱い

UTF-8を利用することは何もウェブページ制作の簡便さのためだけではありません。そうすることによりフォームの送信やURLエンコードなど通常文書の文字エンコーディングを利用する仕組みにおいて予期しない結果に陥ることを避けられます。どうしても非UTF-8な文字エンコーディングを使うしかない場合、互換性を最大限確保することやコンテンツがなるべくきちんと読めることを考慮する必要があるため、かなり限られた種類のエンコーディングから選択することになるでしょう。

つい最近まではIANAのレジストリーがエンコーディングの名称を探すための場所でした。このIANAレジストリーは、多くの場合、同じエンコーディングに対して複数の名称を含んでいます。その時には「preferred」とされている名称を使用するべきです。

新しいEncodingの仕様ではブラウザーの実装に基づいて確認されたリストを提供しています。そのリストはEncodingsというセクションにて表で参照できます。一番左の列の名称を使うと良いでしょう。

しかし注意すべきなのは、これらの参照元に掲載されているからといって、必ずしもそのエンコーディングを使っても大丈夫だということではありません。いくつかのエンコーディングには問題があります。本当にUTF-8を使えないなら、Choosing & applying a character encodingという記事で書かれている忠告に注意深く耳を傾けるべきでしょう。

x-で始まる独自のエンコーディング名を発明してはいけません。それが悪いアイディアな理由は、互換性を制限してしまうからです。

旧式のHTML文書での扱い

HTML 4.01ではmeta要素のcharset属性の利用について定義していません。しかし多くの著名なブラウザーはHTML5ではなくHTML4でページが書かれていたとしても認識し、利用してくれます。このセクションの内容はブラウザー以外で古い形式のHTMLを扱う場合にのみ意味があります。上記要約的な回答のセクションで書かれたこととは違うかもしれません。

XMLとして配信されるページについてはPolyglotやXMLフォーマットへの対応を参照してください。

HTML4: すぐ上で書いたように、HTML 4.01へ完全に適合させるためには、charset属性ではなくプラグマ・ディレクティブを使う必要があります。

text/htmlで配信されるXHTML 1.x: こちらもまたHTML 4.01へ完全に適合させるためには、charset属性ではなくプラグマ・ディレクティブを使う必要があります。HTMLとして配信されるため、XML宣言は必要ありません。

XMLとして配信されるXHTML 1.x: 最初の行でXML宣言を使ってencodingの指定をしましょう。半角スペースを含め、それより前に何もないようにもしましょう(もっともバイトオーダーマークはOKです)。

リンクでのcharset属性

HTML5ではalink要素でのcharset属性は廃止されたので、なるべく使うべきではありません。HTML 4.01仕様ではalinkscript要素で使い、リンク先の文書のエンコーディングを示すことを想定していました。

以下のように埋め込まれたリンク要素で利用されることを意図していました:

 悪い例です。コピーしないように!
See our <a href="/mysite/mydoc.html" charset="iso-8859-15">list of publications</a>.

文書にどのような形でもエンコーディングが指定されていなかったとしても、ブラウザーが正しいエンコーディングを適用できるだろうという考えに基づくものでした。

この属性の利用にはいくつもの問題がありました。まず、著名なブラウザーであまりサポートされてなかったことです。この属性をサポートしない第一の理由は、特別な扱いをしないとXSS攻撃を助長する結果になりかねないことです。また、その属性で指定された値がずっと正しいとは限らないことです。リンク先の文書を製作した人はあなたが知らない間に文書のエンコーディングを変更するかもしれません。もしその製作者が引き続き文書のエンコーディングを指定しないままだと、ブラウザーへ間違ったエンコーディングを適用するよう要求する羽目になります。更に、人々がこの記事のガイドラインに従い、文書を正しくマークアップするならば、まったくもって不要なものだということです。その方がずっと良いやり方でしょう。

この方法によるエンコーディング指定は最も低い優先度になります(例えば他の何かしらの方法でエンコーディングが指定されていた場合、無視されます)。つまりこの方法を利用して間違ったエンコーディング指定を修正することはできないということです。

UTF-16の扱い

Googleによる数十億ページの解析結果によると、UTF-16を使用しているウェブページは0.01%以下だそうです。対してUTF-8はウェブページの60%を超え、サブセットであるASCIIを含めると80%に上ります。このことはウェブページのエンコーディングにUTF-16を利用することを諦めさせるに十分でしょう。

もし、何らかの理由で、選択肢がない場合、エンコーディングの指定にはいくつか規則があります。他のエンコーディングとは少し違うのです。

HTML5仕様ではUTF-16の指定をmeta要素で行うことを禁じています。なぜならばmeta要素の値はASCII互換である必要があるからです。代わりにUTF-16のファイルの先頭でバイトオーダーマークを置くことで行うべきでしょう。事実上、文書内での指定と同じです。

なお、ページがUTF-16で符号化されているなら、"UTF-16BE"や"UTF-16LE"とは指定せず、"UTF-16"だけで指定しましょう。ファイル先頭のバイトオーダーマークにより、符号化スキームとしてリトルエンディアンビッグエンディアンのどちらを使うかを示せる。(UTF-16BEではバイトオーダーマーク使うべきではないとされているが、HTML5ではUTF-16のウェブページにはバイトオーダーマークが必須であるため、このようにしてどうやって符号化されているかを明示する必要がある。)