CSS3プルダウンメニュー

2010/05/25

このサイト(HTML版)のプルダウンメニューの作成をCSS3のみで実現してみました。

まず、HTMLの構造から ■HTML


 

ul、liの入れ子で階層を作っていきます。 最初のul(id=menu)をトップ階層とし、メインメニューはliで横並びにします。 次の階層のul,liがサブメニューになります。

■CSS gradientで背景をグラデーション、border-radiusで枠を角丸に [css]

menu {

display: inline-block;
margin: 15px 0 0 0;
padding: 5px 0 0 0;
line-height: 100%;

font-size: 14px;

background: -moz-linear-gradient(top, #406b9f, #588ab5);
background: -webkit-gradient(linear, left top, left bottom, from(#406b9f), to(#588ab5)); 

-webkit-border-radius: 6px;
-moz-border-radius: 6px;

} [/css] text-shadowでリンクテキストに影をつける

[css]

menu a {

display: block;

margin: 0;
padding: 8px 20px;
color: #eeeeee;
text-decoration: none;

text-shadow: 5px 5px 5px rgba(0, 0, 0, 1.0);

}

menu a:hover {

color: #ff2222;
text-shadow: 2px 2px 2px rgba(0, 0, 0, 1.0);

} [/css]

▽第1階層 トップメニューはliを横並び [css]

menu li {

position: relative;
float: left;
margin: 0 5px;
padding: 0 0 5px;
list-style: none;

} [/css]

liをロールオーバーした時に色を変更 [css]

menu li:hover {

background: -moz-linear-gradient(top, #406b9f, #588ab5);
background: -webkit-gradient(linear, left top, left bottom, from(#406b9f), to(#588ab5)); 

} [/css]

▽第2階層 ここがポイントで、第2階層にあたるulをvisibility=hiddenで予め隠しておく。 Fadeアニメーションするために、opacity=0と設定する。 [css]

menu li > ul {

visibility: hidden;
opacity: 0;

} [/css]

FireFox3.5ではまだアニメーションは未対応 また、アニメーションを利用するとiPhoneだとメインメニュークリック時に、 サブメニューが現れる前にリンクしてしまう。 逆に言えば、iPhoneはhoverの挙動はクリックすると状態がキープされるようだ。

次もポイントで、liをロールオーバーした時にul(第2階層)を表示する。 ここで第2階層をFadeアニメーションするために、opacity=1とtransitionを設定 [css]

menu li:hover > ul {

visibility: visible;
opacity: 1;

-moz-transition: all 0.3s ease-in-out;
-webkit-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;

} [/css]

「li:hover > ul」は新しい書き方ですね。 transitionのプロパティはActionScriptと同じぽいですね。 これもECMAScript準拠なのかね?

第2階層の外枠のレイアウトは#menuから絶対座標に指定 [css]

menu ul {

position: absolute;
font-size: 12px;
margin: 0;
padding: 0;
left: 0;
width: 185px;
border: solid 1px #ffffff;

-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;

} [/css]

第2階層のメニューのレイアウト [css]

menu ul a {

text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
padding: 8px 10px;

}

menu ul li {

float: none;
margin: 0;
padding: 0;
background: -moz-linear-gradient(top, rgba(66, 110, 161, .8), rgba(66, 110, 161, .8));
background: -webkit-gradient(linear, left top, left bottom, from(rgba(66, 110, 161, .8)), to(rgba(66, 110, 161, .8)));  

} [/css]

第2階層の外枠に沿うように、最初と最後のメニューは上下の角丸をつける [css]

menu ul li:first-child {

-webkit-border-top-left-radius: 6px;
-moz-border-radius-topleft: 6px;

-webkit-border-top-right-radius: 6px;
-moz-border-radius-topright: 6px;

}

menu ul li:last-child {

-webkit-border-bottom-left-radius: 6px;
-moz-border-radius-bottomleft: 6px;

-webkit-border-bottom-right-radius: 6px;
-moz-border-radius-bottomright: 6px;

} [/css]

このサンプルの問題点は、階層が増える毎に追加してやらないといけないけど、 何階層にもなるメニューは現実的ではないので、ある程度力技でもいいのかなと? その分ソースわかりにくくなるけど。

level1、level2をclassとして作ってみたけど、WebKit側で思った動作が得られなかった。 どうしても複数階層に対応するなら、JavaScriptやPHP等で動的にCSSを書き出すって感じ?

本当は、CSSも使いまわしのできる関数・プロパティやクラス化できれば、 リファクタリングできてライブラリ化できそうなんだけどなぁ。