2009年8月アーカイブ

[追記:2009/12/29]
デザインによっては動作不良を起こす事がわかりました。改訂版を用意したのでそちらもあわせてご覧ください。

[追記ここまで]

Webページをスクロールしても、ある要素を固定した位置で表示したいときがあります。例えば、「ページのトップへの戻り」のリンクやヘッダーメニューなどです。

固定配置をするためには「position:fixed;」を使用します。しかし、IE6ではfixedはサポートされていません。そこでCSSを駆使して、IE6でも擬似的に「position:fixed;」と同じ動作するように指定します。

ポイントは、普通スクロールする際、htmlタグのスクロールを使用しているのですが、それを非表示にしてbodyをスクロールさせます。

(X)HTMLコード

<div id="totop">ページのトップへ戻る</div>
<div id="text"> 
<p>テキストテキスト</p>
<p>テキストテキスト</p>
(略)
<p>テキストテキスト</p>
<p>テキストテキスト</p>
</div>

最低限必要なCSSソースコードです。

CSSコード


#totop {
   position:fixed;
   right:0;
   bottom:0;
}

/* IE6用 */
* html {
   overflow:hidden;
}

* html body {
   height:100%;
   overflow:auto;
   margin:0;
}

* html #totop {
   position:absolute;
   right:16px;
}

注意点は、右の基点が、IE6ではブラウザの右端に対して、Firefoxなどの他のブラウザは、スクロールバーを含まない右端になります。つまり、IE6ではright:0を指定するとスクロールバーと要素が重なってしまいます。rightで位置を指定する場合、上記の例で言うと、IE6では「* html #totop」で指定、その他は「#totop」で指定します。

ドロップダウンメニューのようなダイナミックな動作はJavaScriptが得意としますが、CSSだけでも実装可能です。

JavaScriptを使用せず、CSSのみでドロップダウンメニューを作成するポイントは以下の3つ。

  1. postionプロパティ、displayプロパティを駆使する
  2. ダイナミック擬似クラスhoverを使用する
  3. 子セレクタを使用する

問題はIE6では、hoverはa要素しか適用範囲でないこと、さらに子セレクタも適用されないということです。

ie7-jsという、IE6でもa要素以外にも:hoverが使えたり子セレクタが使用できるスクリプトがあるので、それを利用することで代用が利きます。

今回はie7-jsを使用せず、どこまでできるかやってみたいと思います。

子孫セレクタを応用すると、IE6でも子セレクタと同様の動作するので、そちらのテクニックを使用します。以下のページを参考にしてください。

IE6でも子セレクタを使う - CSSデザインノート

hoverはダイナミックな動きですので、やはりJavaScriptを使用しなければなりません。簡単なのは、IEの独自拡張であるexpression() 関数を使用します。これはCSS内でJavaScriptコードを読み込めるものです。ただし、CSSの仕様にないものですので、ソースコードはinvalidになってしまいます。

完成サンプルは以下のとおりです。

サンプル

※ページの中にサンプルを記述しているため、ブラウザによっては正常に動作しない場合があります。ご了承ください。サンプルはWindows XPのIE6、Firefox3.5、Safari4.0.3、Opera9.64 、Chrome2.0で動作確認済みです。

基本のHTMLソースは以下のとおりです。メインメニューと3つのサブメニューを用意しました。

(X)HTMLコード

<div id="menu">
   <ul>
      <li><a href="#">menu1</a>
         <ul>
            <li><a href="#">submenu1</a></li>
            <li><a href="#">submenu2</a></li>
            <li><a href="#">submenu3</a>
               <ul>
                  <li><a href="#">submenu3-1</a></li>
                  <li><a href="#">submenu3-2</a></li>
                  <li><a href="#">submenu3-3</a>
                     <ul>
                        <li><a href="#">submenu3-3-1</a></li>
                        <li><a href="#">submenu3-3-2</a></li>
                        <li><a href="#">submenu3-3-3</a></li>
                     </ul>
                  </li>
               </ul>
            </li>
         </ul>
      </li>
     <li><a href="#">menu2</a>
         <ul>
            <li><a href="#">submenu4</a></li>
            <li><a href="#">submenu5</a></li>
         </ul>
      </li>
      <li><a href="#">menu3</a>
         <ul>
            <li><a href="#">submenu6</a></li>
            <li><a href="#">submenu7</a></li>
            <li><a href="#">submenu8</a></li>
            <li><a href="#">submenu9</a></li>
         </ul>
      </li>
   </ul>
</div>

最低限必要なCSSソースコードです。

CSSコード

/* メインメニュー */
#menu ul {
   display:block;
   list-style-type: none;
   margin:0;
   padding:0;
}

/* サブメニュー1段目 */
#menu ul ul{
   display:none;
   position:absolute;
   top:100%;
   left:0;
}

/* サブメニュー2段目以降 */
#menu ul ul ul {
   top:0;
   left:100%;
}

/* リスト */
#menu li {
   float:left;
}

#menu li li {
   clear:both;
}

#menu li:hover {
   position:relative;
}

#menu li:hover > ul {
   display: block
}

/* IE6用 */
* html #menu li {
   behavior: expression(
      this.onmouseover=new Function("this.className='column1'"),
      this.onmouseout=new Function("this.className=''"),
      this.style.behavior = 'none'
   );
}

* html #menu li li {
   behavior: expression(
      this.onmouseover=new Function("this.className='column2'"),
      this.onmouseout=new Function("this.className=''"),
      this.style.behavior = 'none'
   );
}

* html #menu li li li {
   behavior: expression(
      this.onmouseover=new Function("this.className='column3'"),
      this.onmouseout=new Function("this.className=''"),
      this.style.behavior = 'none'
   );
}

#menu .column1 {position:relative;}
#menu .column1 ul {display:block;}
#menu .column1 * ul {display:none;}

#menu .column2 {position:relative;}
#menu .column2 ul {display:block;}
#menu .column2 * ul {display:none;}

#menu .column3 {position:relative;}
#menu .column3 ul {display:block;}
#menu .column3 * ul {display:none;}

後半部分がIE6用のソースコードになります。

hoverの代わりにJavaScriptのonmouseoverイベントハンドラを使用しています。サブカテゴリの数だけliの入れ子の指定が必要です。

本来なら、「* html li」の指定だけでドロップダウンできるはずなのですが、その入れ子の「* html li li」、さらにその入れ子の「* html li li li」と指定が必要となります。

例えばメインのメニューのli要素にマウスが載ったときに.column1のスタイルが実行されるのですが、onmouseoverの適用範囲が表示されたサブメニューまで及びます。

サブメニューのサブメニューを表示したくても、onmouseoverのままなので、新しくonmouseoverイベントハンドラを呼び出す必要があります。そのため、サブメニューの数分expression()関数が必要になってしまいます。

もっとよい書き方があるのかもしれませんが、あまりJavaScriptに詳しくないので、これが私にとっての最善の書き方になります。

これだけでは味気ないのでデザインしていきます。ここでは簡単に背景と余白を体裁します。

CSSコード

/* デザイン */
#menu li {
   line-height:1.6em;
   text-align: center;
   background:#ddd;
}

#menu li li {
   text-align: left;
}

#menu li a{
   display: block;
   width:100px;
   text-decoration:none;
   color:#333;
   padding:0 10px;
}

#menu li:hover {
   background:#7BBA10;
   color:#333;
}

#menu .column1, #menu .column2, #menu .column3 {
   color:#333;
   background:#7BBA10;
}

この例のようにwidthとpaddingを同時に指定する場合は、HTMLファイルが「完全標準モード」になるようにDOCTYPE宣言を指定する必要があります。

例えば、XHTMLファイルなら、

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

などです。

ドロップダウンメニューはJavaScriptで実装したほうがよりリッチに

以上、CSSのみでドロップダウンメニューを作成しましたが、やはりJavaScriptのほうがよりスムーズで美しいドロップダウンメニューができるので、そちらがお勧めではあります。

参考までに素敵なJavaScriptで実装する素敵なドロップダウンメニューはこちら。

参考サイト

子セレクタは親要素の直下の子要素のみに適用されるセレクタです。しかし、IE6では子セレクタは 実装されていません。しかし、子孫セレクタをうまく組み合わせることで、擬似的に子セレクタと同様の動作をすることが可能です。

(X)HTMLコード

<div class="section">
   <p>
      直接の子要素なので子セレクタが適用されます。文字色は赤です。
   </p>
   <div>
      <p>
         直接の子要素ではありません。文字色は緑です。
      </p>
   </div>
</div>

CSSコード

div.section p  {
   color:red;
}

div.section * p {
   color:green;
}

まず、子セレクタとして適用したいスタイルを、子孫セレクタで指定します。

さらにこの子孫セレクタを上書きします。子孫セレクタの途中に、特定の要素ではなくアスタリスク (*) を入れると、ワイルドカードの役割を果たします。

つまりこの場合、"クラス「section」を指定されたdiv要素の、任意の子孫要素(*) の、さらに子孫要素である p 要素にスタイルシートを適用する"となります。

要は、親要素の直下以外の孫子要素にスタイルが適用されるということです。

参考サイト