Folio Vol.9 contents目次など

"いろは"の先のCSS 第9回

徳保隆夫

今回のテーマは「プルダウンメニュー」です。プルダウンメニューがデザイン要素として素晴らしいかどうか、という問題はさておき、CSS を駆使してこれを実現する方法について考えて見ます。

2つのプルダウンメニュー

一般にウェブデザインの世界でプルダウンメニューと呼ばれるデザイン要素は、大きく2種類あります。

フォーム部品の select 要素 + option 要素

select 要素によるプルダウンメニュー

<select>
<option>select from here</option>
<option>a</option>
<option>b</option>
<option>c</option>
</select>

select 要素はフォーム部品なのですが、W3C の勧告ではデザイン要素として用いてもよいことになっています。多くの選択肢をコンパクトの表示できる特徴があるので、様々に利用されています。「本来、ウェブでプルダウンメニューといえばこれのことだ!」という主張も目にしたことがあります(私は賛同しません)。

ソースも単純明快だし、なかなかよさそうに見えますが、このタイプのプルダウンメニューには、ひとつ大きな欠点があります。option 要素はテキストしか内包できないのです。a 要素もダメなんですね。

したがってナビゲーションリンク群を select 要素で置き換えるためには、選択された option 要素の情報を受け取って、ページ移動などの処理を行う CGI や JavaScript を用意しなければなりません。それは必ずしも困難ではありませんが、非常に不自然な作業には違いありません。単にナビゲーションが画面を占有する面積を減らしたいだけなのに、a 要素や、それを内包するリスト要素を select 要素と option 要素、そして CGI や JavaScript などに置き換えてしまうのですから。

今回、私はこのタイプのプルダウンメニューは解説しません。興味のある方には、以下の記事が参考になるでしょう。

リスト要素の装飾を工夫

この記事の読者の方をはじめ、ストリクターの皆さんはナビゲーションリストをリスト要素としてマークアップされていることが多いでしょう。プルダウンメニューも、リストの装飾スタイルをいじるだけで実現できたら嬉しいですよね。

リスト要素を装飾したプルダウンメニュー

<ul>
<li><a href="index2/">About(I)</a></li>
<li <strong>onmouseover="showhide(this)" onmouseout="showhide(this)"</strong>>
<a href="computer/">My Computer(O)</a>
<ul>
<li><a href="computer/tuneup01.php">改造記</a></li>
<li><a href="computer/levinspc.php">Old PC</a></li>
<li><a href="computer/athlon.php">自作機</a></li>
<li><a href="computer/parts.php">Parts</a></li>
</ul></li>
<li><a href="prelude/">My Prelude(P)</a></li>
</ul>

ソース(一部改変)と画面写真は Web Cafe' "Prelude" のもの。このタイプと似て非なる(主としてマークアップに難がある)プルダウンメニューが世の中には非常に多いのですが、基本的な発想は例示したものと同じ。カーソルを合わせると、隠されていたナビゲーションが表示されるわけです。Flash を使った事例もありますが、見た目も基本的な発想も似ているため、ここでは割愛。

Web Cafe' "Prelude" はアクセシビリティなど諸問題への配慮が行き届いた作例なので、ひとつの到達点として高く評価されてきました。けれども、このソースを調べて真似するのは簡単ではありません。雑誌にもしばしば作例記事が掲載されてきましたが、当然ながら、買わなきゃ見られない。ソースが汚くても、いい加減でもかまわないというのなら、いくらでも作例や紹介記事が見つかるのですが、"いろは"の先のCSSでそれを取り上げるのもいかがなものか……。

Web工房きくちゃんという Web サイト作成支援サイトをご存知でしょうか? 初心者から面倒見てくれる親切な解説と、概ね W3C 勧告に忠実なソースの記述を両立させている数少ない良サイトのひとつです。そのきくちゃんが2005年4月に公開した

は、まさに私の求めていた解説。2005年5月8日に公開されたばかりの画面中央に配置するなど、きくちゃんのCSSテクニックには、"いろは"の先のアイデアがたくさん紹介されています。興味のある方はぜひご一読を。

今回の解説方針

というわけで、「これでお終い」といったら怒られますよね? ちょっと言い訳させていただくと、最初は自分で全部記事を書くつもりだったのですが、きくちゃんの作例がよくできているので、「結論はこちらをご覧ください」でいいのではないかと。ただ、きくちゃんの記事にはこう書かれています。

かなりデリケートな構造で、ここがこう働いているから、こうなるんだよ。 という説明はちょっと難しいです。

ポイントは.main li.offと.main li.onです。ブラウザーによる解釈の違いもろもろを抑えるため、 あちこちいじっているうちに完成したものなので、考えた本人もよくわかってないです。

実践では「適当にコピペ」でもいいのですが(少なくとも趣味の個人サイトにおいては)、最初のお勉強では、基本の仕組みは理解しておいた方がよいでしょう。きくちゃんの作例は、かなり作り込まれたもので、最初からきれいにできている反面、記述量が多すぎて何がなんだか分からない。本稿では、中核技術を抜き出して、段階を踏んで理解を深めていただこうと思います。

プルダウンメニュー作成 7STEP

ここでルートを2つに分けます。最低限の内容は以下の作例7STEPに示します。最後まで読み進めば、きくちゃんの99%CSSで作るプルダウンメニュー1に似たプルダウンメニューをあなたも自力で作れるようになるでしょう。

  1. 作例1
  2. 作例2
  3. 作例3
  4. 作例4
  5. 作例5
  6. 作例6
  7. 作例7

基本的には作例だけで話は足りるのですが、本文では補足的な薀蓄を少し書きます。興味のある方はこちらもどうぞ。

:hover と WinIE

:hover 擬似要素は、ふつう a 要素についてのみ用いられます。それはなぜかといえば、WinIE が a 要素以外の要素について :hover 擬似要素をフォローしていないからです。

a 要素はブロックレベル要素を内包できませんので、:hover 擬似要素の使い道といえばたいてい、背景色を変えるとか枠線を変えるといった程度にとどまってきました。けれども、W3C 勧告では、:hover 擬似要素は a 要素専属だなんて一言も書いてありません。本来なら、:hover 擬似要素はどの要素にも設定できるものなのです。

WinIE が未対応なので実際にウェブサイトで用いることはできないでしょうが、:hover によるプルダウンメニューの基本的な考え方を示します。

<div>
<ul class="main">
<li class="parent">ぬるぽ
<ol>
<li>ガッ</li>
<li>ガッガッ</li>
<li>ガッガッガッ</li>
</ol>
</li>
</ul>
</div>

このようなリストがあったとしまして、ここに以下のようなスタイルを設定しますと、プルダウンメニューの原型が得られます。

div
{height:3em;}
ul.main
{position:absolute; width:100%;}
li.parent ol
{display:none;}
li.parent:hover ol
{display:block;}

肝腎なのは強調部分。:hover 擬似要素が有効な場合(=マウスカーソルが li.parent に重なっている状態など)だけ、子要素の ol 要素が display:block; されるよう指定しています。ふだんは隠しておくわけですね。

ul.main に position.absolute; が指定されているのは、:hover 発動時に他の要素の配置に影響を与えないための配慮です。

div 要素の height:3em; は、ul.main を絶対配置するスペースを作るための設定です。:hover 発動時だけ展開される子要素の ol 要素と異なり、平常時の li.parent が他の要素と重なってしまうとうまくありません。ようは平常時の li.parent を配置するためのスペースさえ作れれば何でもいいのであって、div 要素とか height:3em; といった記述自体に必然性はありません(コピペで動作確認するのに便利な記述を選んだだけ)。

JavaScript による代替案

作例 7STEP では、JavaScript による代替案により、WInIE でもプルダウンメニューを実現しています。

詳細は作例をご覧いただきたいのですが、要点のみこちらでも紹介しておきましょう。

<li class="off" onmouseover="this.className='on'" onmouseout="this.className='off'">

この意味は「マウスカーソルがこの li 要素に重なると、class 属性値が 'on' に設定される」。平常時は class 属性値が 'off' ですね。なので、

li.parent ol
{display:none;}
li.parent:hover ol
{display:block;}

という記述を、

li.off ol
{display:none;}
li.on ol
{display:block;}

のように置き換えれば OK ということになります。

プルダウンメニュー作成の中核技術は以上で全部なのですが、ではどうして7段階もの作例が必要になるのか。それは、現状の CSS デザインは果てしないブラウザの実装ミスとの戦いになるためです。とくに WinIE は不思議な挙動が目立ちます。無視できるレベルの不具合が大半ですが、毎回のように、非常に嫌な形で不具合が顕在化するケースが1つか2つ、出てきます。今回も、いささかてこずらされました。

プルダウンメニューの是非

そもそもプルダウンメニューは素晴らしいデザインアイデアといえるのか? という疑問の声は、初めてプルダウンメニューがウェブに持ち込まれた頃より強く存在します。

IT用語辞典の解説を引用しましょう。

プルダウンメニュー 【pull-down menu】
読み方:プルダウンメニュー
別名:ドロップダウンメニュー, drop-down menu
WindowsやMac OSなどの操作画面で、メニューから項目を選択する方式の一つ。メニューのタイトル部分にマウスカーソルをあわせてボタンをクリックすると、そこから選択項目の一覧が引き出されたように垂れ下がってくる表示方法のこと。「ドロップダウンメニュー」ともいう。

Windows のメインウィンドウにはスクロールバーがないので、アプリケーションのメニューを最初から全部表示しておくのは現実的ではありません。だから仕方なくメニューを階層化し、子メニューは平常時には非表示としているわけです。

けれども、スクロールバーのないウェブブラウザは滅多にありません(特別な設定を選択しない限りは)。

スペースに余裕があるのなら、情報をよく整理したうえで全部公開しておいた方が便利に使えるケースが多いはずです。プルダウンメニューを使う場合、まず親メニューの上にカーソルを移動し、子メニューが表示されたのを確認してから、所定の子メニューまで更にカーソルを移動しなければなりません。この過程で親メニューの支配領域からカーソルが外れてしまうと、再び子メニューは隠されてしまいます。

  • 一部の情報をデフォルト設定で「隠す」ことの是非
  • マウス操作の複雑化(アクセシビリティの低下)
  • WinIE では JavaScript 必須(同上)

3番目の批判は時間が解決するでしょうが、上記2点の批判はプルダウンメニューの本質に関わります。

趣味の個人サイトどころか、大手企業の公式サイトでも平気で使われているのが現状ではあって、「別にほとんどの人は気にしていないよ」というのが実態なのかもしれませんけれども、一応、こうした批判があることには留意すべきでしょう。(逆に、ビジネス上、有意なレベルで障害となる問題ではない、という割り切りもあってよいかとは思います)

アクセシビリティを確保するために

プルダウンメニューには JavaScript 必須という条件がありますが、JavaScript を無効化している環境にも一定の配慮をすることは可能です。

<div>
<ul class="main">
<li class="parent">親メニュー
<ol>
<li>子メニュー1</li>
<li>子メニュー2</li>
<li>子メニュー3</li>
</ol>
</li>
</ul>
</div>

JavaScript を無効化している場合、親メニューにカーソルを重ねても子メニューが展開されません。したがって、ナビゲーションリストをプルダウンメニューの形で提供している場合、子メニューだけにリンクを設定すると問題が生じます。

最も単純で強力な解決策は、親メニューに小目次のページへのリンクを設定することでしょう。

<div>
<ul class="main">
<li class="parent"><a href="小目次">親メニュー</a>
<ol>
<li><a href="コンテンツ1">子メニュー1</a></li>
<li><a href="コンテンツ2">子メニュー2</a></li>
<li><a href="コンテンツ3">子メニュー3</a></li>
</ol>
</li>
</ul>
</div>

小目次のページには、以下のようなリストを用意します。目次だけのページなら、プルダウンメニューは必要ないでしょう(目次自体がコンテンツなので、スペースには十分な余裕があるはず)。

<ol>
<li><a href="コンテンツ1">子メニュー1</a></li>
<li><a href="コンテンツ2">子メニュー2</a></li>
<li><a href="コンテンツ3">子メニュー3</a></li>
</ol>

面倒に思われるかもしれませんけれども、検討の価値はあります。

プルダウンメニューは多くの場合、リッチなグローバルナビゲーションを設置するために用いられます。あれば便利だけれども、誰もが利用するわけではない大量のナビゲーション情報を小さなスペースに押し込む魔法のような手段はありません。「メニューを階層化し子メニューをデフォルト非表示とすればよい」というのは、自然な発想といえます。

このようなケースでは、わざわざ新しく小目次を作成する必要はないはず。既に小目次のページは存在しているだろうからです。

たいてい問題になるのは、プルダウンメニューを作るためだけに情報の階層構造をでっち上げたケース。小手先の対策でお茶を濁してはいけません、というのは「いつもの話」ではあります。

今回は以上です。お疲れ様でした。(2005-05-07)

Profile

コメント
徳保隆夫 「それは論理の問題ではなくて、価値観の問題でしょう」……十年一日のごとく。
URL:趣味のWebデザイン