ruby 要素

4.5.21 ruby 要素

カテゴリー:
フロー・コンテント
フレージング・コンテント
パルパブル・コンテント
この要素を使うことができるコンテキスト:
フレージング・コンテントが期待される場所
コンテントモデル:
本文参照。
コンテント属性:
グローバル属性
text/html におけるタグの省略:
どちらのタグも省略できません。
指定可能な ARIA role 属性 の値:
あらゆるロールの値
指定可能な ARIA ステートとプロパティ属性:
グローバル aria-* 属性
許可ロールに該当する aria-* 属性
DOM インタフェース:
HTMLElement を使う。

ruby 要素は、フレージング・コンテントの 1 つ以上の範囲を、ルビ注記を伴ってマークアップできるようにします。ルビ注記とはベーステキストにあわせて提供される短いテキストのことで、主に発音のガイドとして東アジアの印刷に使われたり、他の注記を加えるために使われたりします。日本語では、この印刷形式は ふりがな としても知られています。ルビテキストは、ベーステキストのどちらか一方の側に、ときには両側に現れることもあります。それは、CSSを使って位置を調整することが可能です。ルビの詳細については、Use Cases & Exploratory Approaches for Ruby Markup のドキュメントを参照してください。また、CSS Ruby Module Level 1 にもあります。 [RUBY-UC] [CSSRUBY]

ruby 要素のコンテントモデルは、次のリストの 1 つ以上から構成されます:

  1. 1 つ以上のフレージング・コンテントのノード、または、rb 要素
  2. 1 つ以上の rt または rtc 要素。それぞれは、rp 要素の直前か直後に来ます。

ruby, rb, rtc, rt 要素は、とりわけ(制限するものではありませんが)後述のものを含めて、さまざまな種類の注記に使うことができます。特に日本語ルビの詳細や日本語のルビの表示方法については、Requirements for Japanese Text Layout をご覧ください。 [JLREQ] rp 要素は、ルビのレンダリングがサポートされていない場合に、フォールバックコンテントとして使うことができます。

ベース文字ごとに振るモノルビ

注記(ルビテキスト)が個々の表意文字(ベーステキスト)ごとに関連付けられます。これは、日本語では通常、漢字文字の読み方を伝えるために、平仮名文字かカタカナ文字になります。

<ruby>ベース<rt>注記</ruby>

rb 要素が使われていない場合、前述のとおり、そのベースは暗黙的になります。しかし、それを明示的にすることもできます。これはとりわけ、後述の熟語ルビの例のように、スタイリングや、連続したベースがグループとして扱われる場合に便利です。

<ruby><rb>ベース<rt>注記</ruby>

次の例では、ひとつのベース文字に、どうやって注記を関連付けているのかに注目してください。

<ruby>日<rt>に</rt></ruby><ruby>本<rt>ほん</rt></ruby>
<ruby>語<rt>ご</rt></ruby>で<ruby>書<rt>か</rt></ruby>
いた<ruby>作<rt>さく</rt></ruby><ruby>文<rt>ぶん</rt></ruby>です。
      

通常のテキストに割り振られたルビテキストは、次のイメージと同様の構造を提供します:

An example of ruby text mixed up with regular text.

この例は、1 つのベーステキストのセグメントと注記を ruby 要素に入れて、それを連続して 2 つ用意する(前述のマークアップのように)のではなく、2 つのセグメントのベーステキストと 2 つの注記(それぞれに対応)を 1 つの ruby 要素に入れて、次のように書くこともできます:

<ruby>日<rt>に</rt>本<rt>ほん</rt>語<rt>ご</rt></ruby>
で<ruby>書<rt>か</rt></ruby>
いた<ruby>作<rt>さく</rt>文<rt>ぶん</rt></ruby>です。
      
グループルビ

グループルビは、表音注記がベース文字に対応付けられない場合や、ベーステキスト全体に及ぶ意味的な注釈によく使われます。たとえば、単語 "today" は 今日 という文字で書かれます。これは文字通りに言えば "this day" です。しかし、これは きょう (kyou) と発音され、"this" と "day" の部分に分割することができません。通常のレンダリングにおいては、グループルビで注記されたテキストを分離することはできません。だから、1 つの単位として次の行にワードラップしなければならないのです。ルビテキスト注記が 1 つ以上の文字から構成されるベースに対応付けるとき、そのベースはグループ化されます。

次のグループルビは:

Group ruby example with きょう annotating 今日

次のようにマークアップできます:

<ruby>今日<rt>きょう</ruby>
熟語ルビ

熟語 とは日本語の複合名詞のことを指します。つまり、ひとつ以上の漢字文字から作られる単語のことです。熟語ルビ という用語は、熟語のテキスト全体にわたってルビ注記を記述するためには使われるのではなく、モノまたはグループ・ルビとはやや異なる作法を持ったルビを記述するために使われます。熟語ルビはモノルビに似ています。その中には、ルビテキストと個々のベース文字との間に強い関連性がありながらも、ルビテキストは、通常は、それらが同じ行にある場合は、複数の表意文字をグループ化するようにレンダリングされます。

次の例では、その差異が分かります:

Example of jukugo ruby

これは次のようにマークアップすることができます:

<ruby>法<rb>華<rb>経<rt>ほ<rt>け<rt>きょう</ruby>

この例では、それぞれの rt 要素が、それに対応する rb 要素と対になっています。 rb/rt 交互のアプローチとの違いは、ベーステキストとルビ注記の両方の連続が暗黙的に共通のコンテナに配置され、それによって、グループ化の情報が捕捉される点です。

熟語ルビ・レンダリングの詳細は、Requirements for Japanese Text Layout の Appendix F、そして、Use Cases & Exploratory Approaches for Ruby Markup の Use Case C: Jukugo ruby をご覧ください。 [JLREQ] [RUBY-UC]

インラインルビ

コンテキストによっては、たとえば、フォントサイズや行の高さが小さすぎてルビが読めないようなとき、ルビ注記をインラインで表示したいことがあります。これは、注記されているテキストの後ろで、そのルビ注記が括弧の中に現れます。これは、また、ルビ注記のレンダリングをサポートしていないユーザーエージェントに対する便利なフォールバック戦略を提供します。

インライン化はグループ化を考慮に入れます。たとえば、Tokyo は二つの漢字文字で書かれます。ひとつは 東 で とう と発音し、もうひとつは 京 で きょう と発音します。それぞれのベース文字は別々に注記するべきですが、フォールバックされるときは、東(とう)京(きょう) ではなく、東京(とうきょう) となるべきです。これは次のようにマークアップすることができます:

<ruby>東<rb>京<rt>とう<rt>きょう</ruby>

前述のマークアップは、ルビ・レイアウトをサポートするブラウザーに対してであれば、インライン化の際に括弧の利用が可能になる点に注意してください。サポートしていないブラウザーでは、カッコつきフォールバックの提供に失敗してしまいます。ここでは rp 要素が役に立ちます。ルビ・レイアウトがサポートされていないとき、適切なフォールバックを提供するために前述の例に挿入することができます:

<ruby>東<rb>京<rp>(<rt>とう<rt>きょう<rp>)</ruby>
読み方と意味の両方の注記を伴うテキスト(両側ルビ)

ときには、ルビが、1 つのベースに対して 2 度の注記を行うために使われることがあります。

次の例では、San Francisco (旧金山, つまり “old gold mountain”) を表す中国語の単語に、ピンインを使って発音が与えられ、そして、元の英語も注記されています。

San Francisco in Chinese, with both pinyin and the original English as annotations.

これは次のようにマークアップされます:

<ruby><rb>旧<rb>金<rb>山<rt>jiù<rt>jīn<rt>shān<rtc>San Francisco</ruby>
      

この例では、3 つのベース文字からなる 1 つのベースが、1 つ目の(暗黙の)コンテナの中の 3 つのピンインのルビテキストのセグメントで注記されています。そして、rtc 要素を導入することで、2 つ目となる 1 つのルビテキスト注記を提供して、都市の英語名を表しています。

前述の熟語の例に戻ってみましょう。今度は 上手 ("skill") です。どうやってこれに対して、かなとローマ字読みの両方を使って注記しながらも、ベースと注記のグループ化の情報の組み合わせを維持できるのかを見てみましょう。

上手 ("skill") annotated in both kana and romaji, shown in both jukugo and mono styles.

これは次のようにマークアップされます:

<ruby><rb>上<rb>手<rt>じよう<rt>ず<rtc><rt>jou<rt>zu</ruby>
      

rtc 要素の直接の子であるテキストは暗黙的にルビテキストのセグメントを生成します。これはあたかも rt 要素に入れられているかのようです。この架空の例では、英語とフランス語の名前の注記を伴ったシンボルがいくつか表示されますが、注記がベースのシンボルの一方の側に現れるよう考えられています。

<ruby>
  ♥<rt>Heart<rtc lang=fr>Cœur</rtc>
  ☘<rt>Shamrock<rtc lang=fr>Trèfle</rtc>
  ✶<rt>Star<rtc lang=fr>Étoile
</ruby>
      

同様に、ruby 要素に直接入れられたテキストは暗黙的にルビベースを生成します。そのテキストがあたかも rb 要素の中に入れられているかのようです。そして、ruby の子の rt は暗黙的に rtc コンテナに入れられます。実質的に、上記の例は次と同等(DOM では生成されていませんが、意味的に)です:

<ruby>
  <rb>♥</rb><rtc><rt>Heart</rt></rtc><rtc lang=fr><rt>Cœur</rt></rtc>
  <rb>☘</rb><rtc><rt>Shamrock</rt></rtc><rtc lang=fr><rt>Trèfle</rt></rtc>
  <rb>✶</rb><rtc><rt>Star</rt></rtc><rtc lang=fr><rt>Étoile</rt></rtc>
</ruby>
      

ruby 要素の中では、コンテンツは一連のルビセグメントに分配されます。それぞれのルビセグメントは次のとおりです:

  • 0 個以上のルビベース。 それぞれは、フレージング・コンテントまたは rb 要素を含むことができる DOM range です。
  • ひとつのベースの範囲。これはすべてのベースを含んだ DOM range で、ルビベース・コンテナといいます。
  • 0 個以上のルビテキスト・コンテナ。これは、明示的な rtc 要素、または、無名のルビテキスト・コンテナに含まれるときに暗黙的に認識された連続した rt 要素に結び付けることができます。

それぞれのルビテキスト・コンテナは、フレージング・コンテントか rt 要素を含むことができる DOM range となる 0 個以上のルビテキスト注記によって表され、そのコンテナに対して、すべての注記を含む範囲となる注記範囲です。ルビテキスト・コンテナは、ルビ注記コンテナとしても知られています(主に CSS の文脈で)。

さらに、ruby 要素は無視されるルビコンテントを含みます。無視されるルビコンテントは、ドキュメントのセマンティクスを形成しません。これは、いくつかの要素間ホワイトスペースrp 要素から構成されます。後者は、ルビを全くサポートしていない古いユーザーエージェント向けに使われます。

注記ペアリングの処理は、ルビ注記ルビベースと結び付けます。それぞれのルビセグメントの中で、ルビベース・コンテナの中のルビベースは、順に、ルビテキスト・コンテナからの 1 つのルビテキスト注記と対になります。ルビ注記コンテナに十分なルビテキスト注記がなければ、最後の注記に超過分のルビベースが結び付けられます。(ルビ注記コンテナに注記 1 つもなければ、無名の空の注記が存在すると想定されます)十分なルビベースがなければ、残りのルビテキスト注記は空に結び付けられ、無名のベースがルビベース・コンテナの最後に挿入されたと想定されます。

ルビセグメント, ルビベース, ルビテキスト注記, ルビテキスト・コンテナ, ルビベース・コンテナ, ルビ注記コンテナという用語は、CSS Ruby Module Level 1 と同じである点に注意してください。 [CSSRUBY]

非公式ですが、後述のセグメント化とカテゴリー化のアルゴリズムは、シンプルなタスクのセットを実行します。 まず、隣り合う rb 要素、テキストノード、非ルビ要素をベースのリストに入れます。次に、rtc 要素、または、無名のルビテキスト・コンテナに自動的に対応付けられると判断された連続した rt 要素を処理します。前述のデータモデルで説明したとおり、ルビセグメントのこれらデータ項目を 1 つにまとめます。ruby 要素のコンテンツの最後に到達するまで、このようなセグメントが生成され続けることになります。後述のアルゴリズムの複雑さは、この非公式な説明とくらべると、製作者にやさしい構文をサポートする必要性や、要素間ホワイトスペースを考慮しなければいけない点から生じるものです。

ruby 要素のコンテンツのセグメント化とカテゴリー化は、次のアルゴリズムを実行して得られる結果です:

  1. Let root be the ruby element for which the algorithm is being run.
  2. Let index be 0.
  3. Let ruby segments be an empty list.
  4. Let current bases be an empty list of DOM ranges.
  5. Let current bases range be null.
  6. Let current bases range start be null.
  7. Let current annotations be an empty list of DOM ranges.
  8. Let current annotations range be null.
  9. Let current annotations range start be null.
  10. Let current annotation containers be an empty list.
  11. Let current automatic base nodes be an empty list of DOM Nodes.
  12. Let current automatic base range start be null.
  13. Process a ruby child: If index is equal to or greater than the number of child nodes in root, then run the steps to commit a ruby segment, return ruby segments, and abort these steps.
  14. Let current child be the indexth node in root.
  15. If current child is not a Text node and is not an Element node, then increment index by one and jump to the step labelled process a ruby child.
  16. If current child is an rp element, then increment index by one and jump to the step labelled process a ruby child. (Note that this has the effect of including this element in any range that we are currently processing. This is done intentionally so that misplaced rp can be processed correctly; semantically they are ignored all the same.)
  17. If current child is an rt element, then run these substeps:
    1. Run the steps to commit an automatic base.
    2. Run the steps to commit the base range.
    3. If current annotations is empty, set current annotations range start to the value of index.
    4. Create a new DOM range whose start is the boundary point (root, index) and whose end is the boundary point (root, index plus one), and append it at the end of current annotations.
    5. Increment index by one and jump to the step labelled process a ruby child.
  18. If current child is an rtc element, then run these substeps:
    1. Run the steps to commit an automatic base.
    2. Run the steps to commit the base range.
    3. Run the steps to commit current annotations.
    4. Create a new ruby annotation container. It is described by the list of annotations returned by running the steps to process an rtc element and a DOM range whose start is the boundary point (root, index) and whose end is the boundary point (root, index plus one). Append this new ruby annotation container at the end of current annotation containers.
    5. Increment index by one and jump to the step labelled process a ruby child.
  19. If current child is a Text node and is inter-element whitespace, then run these substeps:
    1. If current annotations is not empty, increment index by one and jump to the step labelled process a ruby child.
    2. Run the following substeps:
      1. Let lookahead index be set to the value of index.
      2. Peek ahead: Increment lookahead index by one.
      3. If lookahead index is equal to or greater than the number of child nodes in root, then abort these substeps.
      4. Let peek child be the lookahead indexth node in root.
      5. If peek child is a Text node and is inter-element whitespace, then jump to the step labelled peek ahead.
      6. If peek child is an rt element, an rtc element, or an rp element, then set index to the value of lookahead index and jump to the step labelled process a ruby child.
  20. If current annotations is not empty or if current annotation containers is not empty, then run the steps to commit a ruby segment.
  21. If current child is an rb element, then run these substeps:
    1. Run the steps to commit an automatic base.
    2. If current bases is empty, then set current bases range start to the value of index.
    3. Create a new DOM range whose start is the boundary point (root, index) and whose end is the boundary point (root, index plus one), and append it at the end of current bases.
    4. Increment index by one and jump to the step labelled process a ruby child.
  22. If current automatic base nodes is empty, set current automatic base range start to the value of index.
  23. Append current child at the end of current automatic base nodes.
  24. Increment index by one and jump to the step labelled process a ruby child.

前述の手順がルビセグメントをコミットと言うとき、それは、そのアルゴリズムのその時点で、次の手順を実行することを意味します:

  1. Run the steps to commit an automatic base.
  2. If current bases, current annotations, and current annotation containers are all empty, abort these steps.
  3. Run the steps to commit the base range.
  4. Run the steps to commit current annotations.
  5. Create a new ruby segment. It is described by a list of bases set to current bases, a base DOM range set to current bases range, and a list of ruby annotation containers that are the current annotation containers list. Append this new ruby segment at the end of ruby segments.
  6. Let current bases be an empty list.
  7. Let current bases range be null.
  8. Let current bases range start be null.
  9. Let current annotation containers be an empty list.

前述の手順がベースの範囲をコミットと言うとき、それは、そのアルゴリズムのその時点で、次の手順を実行することを意味します:

  1. If current bases is empty, abort these steps.
  2. If current bases range is not null, abort these steps.
  3. Let current bases range be a DOM range whose start is the boundary point (root, current bases range start) and whose end is the boundary point (root, index).

前述の手順が現在の注記をコミットと言うとき、それは、そのアルゴリズムのその時点で、次の手順を実行することを意味します:

  1. If current annotations is not empty and current annotations range is null let current annotations range be a DOM range whose start is the boundary point (root, current annotations range start) and whose end is the boundary point (root, index).
  2. If current annotations is not empty, create a new ruby annotation container. It is described by an annotations list set to current annotations and a range set to current annotations range. Append this new ruby annotation container at the end of current annotation containers.
  3. Let current annotations be an empty list of DOM ranges.
  4. Let current annotations range be null.
  5. Let current annotations range start be null.

前述の手順が自動のベースをコミットと言うとき、それは、そのアルゴリズムのその時点で、次の手順を実行することを意味します:

  1. If current automatic base nodes is empty, abort these steps.
  2. If current automatic base nodes contains nodes that are not Text nodes, or Text nodes that are not inter-element whitespace, then run these substeps:
    1. It current bases is empty, set current bases range start to the value of current automatic base range start.
    2. Create a new DOM range whose start is the boundary point (root, current automatic base range start) and whose end is the boundary point (root, index), and append it at the end of current bases.
  3. Let current automatic base nodes be an empty list of DOM Nodes.
  4. Let current automatic base range start be null.

※ 原文:http://www.w3.org/TR/2014/REC-html5-20141028/text-level-semantics.html#the-ruby-element