この日記はMozillaのプロダクトへの貢献者としての私の成果を中心に、気になったバグやWeb界隈の話題について書いていますが、 断り書きがある場合を除き、いかなる団体のオフィシャルな見解ではありません。あくまでも個人的なものです。 Mozilla Foundation、Mozilla Corporation、及び関連企業の公式情報ではないことに注意してください。

現在、XHTML 1.0 (もどき)から、HTML5なコンテンツに修正中です。古い日記は修正が完了していませんので表示が崩れます。 順次、修正していく予定ですのでしばらくお待ちください。

もずはっく日記(2013年4月)

2013年4月24日

<ruby>関連要素って駄目駄目
初回投稿日時: 2013年04月24日08時50分50秒
最終更新日時: 2015年02月21日15時45分29秒
カテゴリ: HTML XHTML 雑談
SNS: (list)

<ruby>関連要素の仕様について色々と思うところが多いので、この日記にまとめておこうと思います。

私の結論を先に述べておくと、一言、酷い仕様、です。

歴史

まず、<ruby>関連要素の歴史を振り返ってみましょう。

まず、<ruby>関連要素はIE5で独自拡張として実装されました。ルビを振りたい日本人に一定の支持を受けていた印象があります。ですが、独自に暴走して仕様を決めてしまっているため、他のブラウザベンダ等との協議を経て、ブラッシュアップされたものでないのは当然と言えます。これが第一の不幸です。

そして、Microsoft在籍のエディタを中心に、XHTML 1.1の拡張モジュールとして、2001年に、Ruby Annotationが勧告されました。その内容はIEの実装内容を基に、より複雑なルビをマークアップできるように、仕様も複雑化していました。ですが、IEをはじめ、この仕様を全て実装したブラウザは存在しません。ですが、標準仕様の策定になったという既成事実がこの時に成立してしまいました。これが第二の不幸です。

その後、WebKitが、何故か突然、<ruby>関連要素をIEの実装に基づいて実装してしまいました。これで、<ruby>関連要素はある意味で本当に市民権を得てしまったと言えます。これが第三の不幸。

そして今、HTML5で<ruby>関連要素は、必要最低限のものに絞り込まれ、勧告へ向けて着々と進んでしまっていて、もはやこの流れを止めることはできないでしょう。ですので、珍しく、W3Cで議論するわけでもなく、ここで愚痴るのみに留めています。

HTML5における<ruby>関連要素

HTML5で定義されている<ruby>関連要素について、簡単にまとめておきましょう。簡単な利用方法には二種類あります。<ruby>要素全体にまとめてルビを振るか、<ruby>内を複数のセグメントに区切って、ルビを振るかの二つです。

<ruby>不撓不屈<rp>(</rp><rt>ふとうふくつ</rt><rp>)</rp></ruby>
<ruby>不<rp>(</rp><rt>ふ</rt><rp>)</rp>撓<rp>(</rp><rt>とう</rt><rp>)</rp>不<rp>(</rp><rt>ふ</rt><rp>)</rp>屈<rp>(</rp><rt>くつ</rt><rp>)</rp></ruby>

これらは、それぞれ、非対応ブラウザだと、不撓不屈(ふとうふくつ)不(ふ)撓(とう)不(ふ)屈(くつ)と表示されます。

では、各要素の意味を簡単にまとめておきましょう。

ruby element

ルビを振りたいテキストと、ルビ全体を含む要素です。DOMツリーで考えた場合に、コンテナとして機能しますが、そういう意味では変な名前になってしまっています。

rt element

<ruby>要素内で、ルビとして振られるテキストを示す要素です。本来なら、これがruby要素という名前の方が正しかったのではないかという意見も見かけたことがあります。

rp element

<ruby>関連要素に対応していないブラウザでも、自然なテキストとしてルビを振られるテキストと、ルビを表示しようとすると、各境界線に括弧のような区切り文字が必要になります。しかし、対応しているブラウザでは逆に不要となります。この区切り文字部分を意味する要素です。

では、私が感じている問題点について解説していきます。

複雑すぎる仕様

まず、上記の例を見てもらえば分かりますが、そもそも複雑すぎます。明らかに手作業でマークアップするためのものとしてデザインされていません。SVGのように複雑すぎてツールが必要なものを制作するにあたって、手作業でのマークアップが不可能に近い、というのは分かりますが、文中に大量に出現する可能性のあるシンプルな機能を付与するマークアップがこれほど複雑であるというのはバランスを欠いていると言えます。

また、ルビそのものもテキストノードですので、選択してコピーすると、再利用しづらい文字列がクリップボードにコピーされてしまいます。

<rp>要素はそのうち無視されるようになる

このように複雑で面倒な代物だと、少しでも簡単に記述してしまいたいと思うのが人情です。現在、メジャーなブラウザで<ruby>をサポートしていないのは、FirefoxとOperaのみですが、Operaは近々、Chromiumベースのブラウザに生まれ変わることが発表されています。ですので、あとはFirefoxが対応し次第、意識の低いWeb開発者は喜んで、<rp>要素を利用しなくなるでしょう。

この流れは確実に発生すると考えていて、そうなった場合に、この仕様のアクセシビリティへの配慮は破綻することになります。

<ruby>要素には意味がない

HTML5の仕様書では、<ruby>関連要素の様々な使い方が例示されています。使い方としてパッと思いつくだけでも、「読み方を明示する」ためと、「当て字を表現する」という二つがあります。後者は、超電磁砲(レールガン)といった形です。

ですが、何故か、どういった目的をもってルビが振られたのかを指定する属性が用意されていません。このため、そもそも<ruby>には意味が定義されておらず、単に、ルビを振るという表現手法のための、プレゼンテーションのための要素となってしまっています。

つまり、CSS登場以前のHTMLの考え方に戻ってしまっていて、(今時の若いデザイナさんは知らないかもしれませんが、) <font color="red">赤いテキスト</font>と同じレベルのことをHTML5という最新仕様で、オトナ達が必死に定義しようとしているという悲しい状況になっています。

では、どのような仕様が望ましかったのか、これには色々な案があると思いますが、私がイチオシなのは、シンプルに属性を活用してしまうことです。

対案1

もっともシンプルなのは、HTML5では何も定義せず、CSSのrubyモジュールに頼るというものです。例えば、略語に対して、ルビを振りたい場合、意味の無い<ruby>要素を使うのは、典型的な残念なマークアップと言わざるを得ません。例えば、TKG(たまごかけごはん)といったケースを考えてみましょう。ルビを振る、という表現手法を頭から取り除いて考えてみてください。何が適切だと思いますか? そう、<abbr>要素ですよね? 略語のマークアップなのですから。ですので、

<abbr title="たまごかけごはん">TKG</abbr>

とマークアップし、CSS rubyモジュールを利用し、

abbr[title] {
  display: ruby;
}

abbr[title]::after {
  content: attr(title);
  display: ruby-text;
  font-size: 0.6em;
}

といった形で表現を定義してしまえば、良いのです。

Sample: TKG

対案2

しかし、対案1では、ルビとしては振りたくない場合にも、ルビが振られてしまう弊害があるため、ドキュメントの構成によっては、クラスを指定したりすることで、切り分けをしなくてはいけません。それは面倒ですよね。また、title属性とは異なるルビを振りたい場合に、data-*属性を利用するというのも、変な感じがします。そして、最大の問題は、CSS rubyモジュールに非対応のブラウザでの対応が、少し面倒になります。

じゃあ、そもそも、特定の要素にruby属性を持たせておくとシンプル、ということになります。つまり、

<abbr ruby="たまごかけごはん" title="たまごかけごはん">TKG</abbr>

というマークアップにし(この例では冗長な感じになってしまっていますが)、

*[ruby] {
  display: ruby;
}

*[ruby]::after {
  content: attr(title);
  display: ruby-text;
  font-size: 0.6em;
}

としてしまうことです。この場合、非対応ブラウザは、ブラウザのデフォルトスタイルシートで、

*[ruby]::after {
  content: " (" attr(title) ") ";
  display: inline;
}

と定義しておくことで、<ruby>要素の想定しているアクセシビリティを現代のブラウザでは簡単に確保できてしまうことになります。

Sample: TKG

要素 vs. 属性

そもそも、何故、ルビは要素で定義するようになったのでしょうか? これについてはMicrosoftの当時のエンジニアに聞いてみないと真実は分かりませんが、当時のWeb標準仕様に対する風潮や、各ブラウザのCSSの実装事情から考えると、やはり、非対応ブラウザのアクセシビリティに配慮したと考えるのが自然でしょう。

当時は、generated contentはもとより、そもそもCSSにまともに対応できているのはIEだけという時代でした。また、時代は、SGMLベースのHTMLから、XMLベースのXHTMLに移行し、より、マシンリーダブルなセマンティックウェブを実現しようと、今よりもアクシビリティ等、地味な部分への意識が高い時代でした。

このため、ルビはIEで独自実装する際には、要素として表現するしか、選択肢がなかったのではないかと思います。

しかし、HTML5の時代が来つつある今、理想よりも現実的なアプローチがより好まれるようになってきました。また、各ブラウザのCSS実装は高度に進化し、上述のスタイルの実現は技術的には可能になっています。

そして、各ブラウザのメジャーリリースの間隔は非常に短いサイクルになりました。企業向けに慎重である必要があるIEですら、年一度程度のペースになりつつあります。

ですので、このような時代に、未対応ブラウザでは標準の動作で非表示となってしまう属性に、新機能であるルビの機能を持たせるのはアクセシビリティ上好ましくないと考えることは、非常に古い考えであると言えます。上述の非対応ブラウザ向けのスタイルを定義することを、非対応ブラウザに義務づけてしまえば、間違いなく、HTML5の正式仕様勧告までに、各ブラウザ、間に合うでしょう。たとえ、間に合わなかったとしても各Webページは自前で記述することにより、対応させることができます。

結局、何が不幸を加速させたのか?

歴史的な事情を踏まえると、ある意味、今の形は自然な結果であると言えます。

しかし、XHTML1.1がまったく実用化されなかったことを踏まえると、初のマトモな仕様化はHTML5が最初と言えますので、ここまでに何度も、このような悲惨な状況になることを回避するチャンスはあったと思います。

まず、HTML5仕様案登場以前に、IEの独自仕様である<ruby>関連仕様を誰も支持しなければ良かったのです。Webサイトは利用せず、WebKitも追っかけ実装をしなければ、既成事実がほとんど存在せず、<blink><marquee>のように、あたかも存在しなかったかのように、無視し、HTML5では、別のより使いやすい仕様を模索できたのではないかと思います。

つまり、HTML5仕様でIE独自仕様の<ruby>関連仕様をそのまま採用しようとしてしまったことが不幸な結果へと突き進むしかなくなった現状の直接的な原因であると言えます。この時点で誰かが、独自拡張を採用しているサイトを無視する、という英断ができていれば、より、今風のシンプルな仕様になっていたでしょう。ここに関われなかったことを非常に個人的にも後悔していますが、時、既に遅しですね。

脱法ルビ

私の、ルビは属性で十分、というアイデアに共感できる方は、お勧めはしませんが、脱法ルビ(HTML5的にInvalidではない)を利用することは将来的には可能です。

HTML5では、<ruby>要素に意味が定義されていないことが逆に幸運だったと言えます。意味が定義されていない以上、これを利用すべき理由が実は無いのです。

そして、HTML5では、data- prefixを付与した属性を独自に、あらゆる要素に勝手に付けることができます。これはつまり、以下の例がまかり通ることを意味します。

<span data-ruby="ふとうふくつ">不撓不屈</span>
<span data-ruby="ふ">不</span><span data-ruby="とう">撓</span><span data-ruby="ふ">不</span><span data-ruby="くつ">屈</span>
/* for ruby unaware browsers */
*[data-ruby]::after {
  content: " (" attr(data-ruby) ") ";
}

@supports (display: ruby-text) {
  *[data-ruby] {
    display: ruby;
  }
  *[data-ruby]::after {
    content: attr(data-ruby);
    display: ruby-text;
    font-size: 0.6em;
  }
}

Sample:

この手法のメリットは、何よりも、最低限の記述なので、手書きに無理が無いレベルのマークアップだという点です。

難点は、DOMでスクリプトから何らかの処理をしづらい点と、現状、まだブラウザの実装が追いついていない点、そして、将来的に、<ruby>要素がHTMLElementではなく、独自APIを持った、派生オブジェクトを生成するようになった場合に、それが利用できない、という点です。

関連するかもしれないエントリ

関連するかもしれないエントリを発見できませんでしたが、無いとは限りません。

このエントリへのリンク元