【CSS】CSSのみで多階層ナビゲーションを作成する

2017.10.29|サイト構築

ちょっと前までは、CSSのみでドロップダウンメニューを作成するなんて、思ってもみなかったんですが、最近は、軽量化の面も考えてCSSのみでドロップダウンメニューを作成することも増えてきたのではないでしょうか。

最近やっと自分でもサクサク作れるようになってきたので、忘備録かねて…

CSSのみのドロップダウンメニュー

CSSのドロップダウンメニューの仕組みなども踏まえて解説していきたいと思います。

中には、もうちょっときちんと作成している方もいらっしゃるかとは思うんですが、私なりの解釈です。

基本のドロップダウンメニュー

基本のドロップダウンメニューです。

ソース(CSS)
ul.cdd_menu a {
 text-decoration: none;
 color: #646464;
 background: transparent;
}

ul.cdd_menu a:hover {
 opacity: .5;
 transition: .5s;
 background: rgba(225,225,225,.8);
}

ul.cdd_menu {
 width: 1200px;
 margin: 0 auto;
 position: relative;
 z-index: 9999;
 background: #EEE;
 text-align: center;
}

ul.cdd_menu > li {
 display: inline-block;
 }

ul.cdd_menu li a {
 display: block;
 margin: 0;
 padding: .5rem 2rem;
}

ul.cdd_menu,
li.cdd_menu-dropdown > ul {
 padding: 0;
 list-style: none;
}

li.cdd_menu-dropdown > ul {
 position: absolute;
 background: #CCC;
 visibility: hidden;
 opacity: 0;
}

li.cdd_menu-dropdown:hover > ul {
 visibility: visible;
 transition: .5s;
 opacity: 1;
 }
ソース(HTML)
<ul class="cdd_menu">
 <li class="cdd_menu-dropdown">
 <a href="#">メニュー1</a>
   <ul>
     <li><a href="#">メニュー2</a></li>
     <li><a href="#">メニュー2</a></li>
     <li><a href="#">メニュー2</a></li>
     <li><a href="#">メニュー2</a></li>
     <li><a href="#">メニュー2</a></li>
   </ul>
 </li>
 <li><a href="#">メニュー1</a></li>
 <li><a href="#">メニュー1</a></li>
 <li><a href="#">メニュー1</a></li>
 <li><a href="#">メニュー1</a></li>
</ul>

ドロップダウンメニュー解説

このメニューの一番初めのリストのliタグに.cdd_menu-dropdownを付けるだけでHTMLはとりあえず問題ないと思います。

仕組みはまずは「メニュー1」の部分を横並びのナビゲーションメニューにします。

今回はdisplay: inline-block;を使用して横並びにしていますが、flort: left;でも構いません。

今回flortを使用しなかったのは、CSSの記述を少なくするため、clearfixいらないパターンにしてみました。

「メニュー1」の部分は横並び、「メニュー2」の部分は縦並びにしたいので、
「メニュー1」の部分のみ横並びになるようにul.cdd_menuの直下のliのみdisplay: inline-block;がかかるようにul.cdd_menu > liとしています

ul.cdd_menu > li {
 display: inline-block;
 }

セレクタをで区切ることによって、そのセレクタの直下の子セレクタのみに要素が適応されます。

このままだと一つのブロックの中にメニューがダブってはいることになります。

ですので、「メニュー2」の部分を切り離したいので、「メニュー2」の部分をposition: absolute;します。

このままだと、ブラウザを親として、「メニュー2」の位置が決まってしまうので、
「メニュー1」にposition: relative;を入れます。

ul.cdd_menu {
 width: 1200px;
 margin: 0 auto;
 position: relative;
 z-index: 9999;
 background: #EEE;
 text-align: center;
}
.
.
.
li.cdd_menu-dropdown > ul {
 position: absolute;
 background: #CCC;
 visibility: hidden;
 opacity: 0;
}

これではまだ、「メニュー2」部分が表示されたままなので、
visibility: hidden;で隠します。

この隠した「メニュー2」を「メニュー1」にマウスオンした時に表示にさせたいので、
疑似要素の:hoverを使って、表示をさせます

li.cdd_menu-dropdown:hover > ul {
 visibility: visible;
 transition: .5s;
 opacity: 1;
 }

.cdd_menu-dropdownのクラスがついているliをマウスオンした時その直下の子要素のulが表示されます。

ここでポイントは、といっても当たり前のことなんですが、非表示にしたセレクタと同じセレクタがマウスオンした時表示になるようにすることです。

CSSのみで多階層ドロップダウンメニュー

では、基本のドロップダウンメニューができたところで、
多階層ドロップダウンメニューの作成をしたいと思います。

多階層ドロップダウンメニュー

ソース(CSS)

基本のドロップダウンメニューから増えた部分は赤文字になっています。

ul.cdd_menu a {
    text-decoration: none;
    color: #646464;
    background: transparent;
}
ul.cdd_menu a:hover {
    opacity: .5;
    transition: .5s;
    background: rgba(225,225,225,.8);
}
ul.cdd_menu {
    width: 1200px;
    margin: 0 auto;
    position: relative;
    z-index: 9999;
    background: #EEE;
    text-align: center;
}
ul.cdd_menu > li {
    display: inline-block;
}
ul.cdd_menu li a {
    display: block;
    margin: 0;
    padding: .5rem 2rem;
}
ul.cdd_menu,
li.cdd_menu-dropdown > ul {
    padding: 0;
    list-style: none;
}
li.cdd_menu-dropdown{
 position: relative;
}
li.cdd_menu-dropdown > ul {
    position: absolute;
    background: #CCC;
    visibility: hidden;
    opacity: 0;
}
li.cdd_menu-dropdown:hover > ul {
    visibility: visible;
    transition: .5s;
    opacity: 1;     }
li.cdd_menu-dropdown > ul > li > ul {
    background: #999999;
    position: absolute;
    left: 100%;
    top: 0;
    width: 100%;
}
ソース(HTML)

基本のドロップダウンメニューから増えた部分は赤文字になっています。

 <ul class="cdd_menu">
   <li class="cdd_menu-dropdown"><a href="#">メニュー1</a>
     <ul>
       <li><a href="#">メニュー2</a></li>
       <li class="cdd_menu-dropdown"><a href="#">メニュー2</a>
        <ul>
          <li><a href="#">メニュー3</a></li>
          <li><a href="#">メニュー3</a></li>
          <li><a href="#">メニュー3</a></li>
          <li><a href="#">メニュー3</a></li>
          <li><a href="#">メニュー3</a></li>
        </ul>
       </li>
       <li><a href="#">メニュー2</a></li>
       <li><a href="#">メニュー2</a></li>
       <li><a href="#">メニュー2</a></li>
     </ul>
   </li>
   <li><a href="#">メニュー1</a></li>
   <li><a href="#">メニュー1</a></li>
   <li><a href="#">メニュー1</a></li>
   <li><a href="#">メニュー1</a></li>
</ul>

多階層ドロップダウンメニュー解説

基本のドロップダウンメニューでは、真下に入れればよかったですが、
第三階層以降はどんどん右側に出していきたいので、その部分のCSSの処理が問題となってきます。

それをこの新しく追加した

li.cdd_menu-dropdown > ul > li > ul {
     background: #999999;
     position: absolute;
     left: 100%;
     top: 0;
     width: 100%;
 }

これで解消しています。

ただこれだけだと、メニューの位置がうまく真横に来てくれないので、

li.cdd_menu-dropdown{
 position: relative;
}

これを追加することで、positionの正確な位置を表示させます。

これでどんどん増やしたい箇所に

<li class="cdd_menu-dropdown"><a href="#">メニュー</a>
   <ul>
      <li><a href="#">メニュー</a></li>
      <li><a href="#">メニュー</a></li>
      <li><a href="#">メニュー</a></li>
      <li><a href="#">メニュー</a></li>
      <li><a href="#">メニュー</a></li>
    </ul>
</li>

このソースを入れていけばどんどん横に展開していきます。

でも、このソースだと、一番右端のメニューは横展開しすぎたら見えなくなるので…

多階層ドロップダウン作ってみたけど、これじゃあどのメニューがオープンするのかわからない!
矢印でもつけてよ!!

ということで、矢印を付ける場合はCSSがこうなります。

ソース(CSS)

増えた部分は赤文字になっています。

ul.cdd_menu a {
    text-decoration: none;
    color: #646464;
    background: transparent;
}
ul.cdd_menu a:hover {
    opacity: .5;
    transition: .5s;
    background: rgba(225,225,225,.8);
}
ul.cdd_menu {
    width: 1200px;
    margin: 0 auto;
    position: relative;
    z-index: 9999;
    background: #EEE;
    text-align: center;
}
ul.cdd_menu > li {
    display: inline-block;    
}
ul.cdd_menu li a {
    display: block;
    margin: 0;
    padding: .5rem 2rem;
} 
ul.cdd_menu,li.cdd_menu-dropdown > ul {
    padding: 0;
    list-style: none;
}
li.cdd_menu-dropdown{
    position: relative;
}
li.cdd_menu-dropdown > ul {
    position: absolute;
    background: #CCC;
    visibility: hidden;
    opacity: 0;
}
li.cdd_menu-dropdown:hover > ul {
    visibility: visible;
    transition: .5s;
    opacity: 1;     
}
li.cdd_menu-dropdown > ul > li > ul {
    background: #999999;
    position: absolute;
    left: 100%;
    top: 0;
    width: 100%;
}
li.cdd_menu-dropdown > a:after {
    content: "▼";
    margin-left: 5px;
}
li.cdd_menu-dropdown > ul > li.cdd_menu-dropdown > a:after {
    content: ">>";
}

:afterの疑似要素でマークを付けています。

一番簡易で作成しているので、矢印をフォントアイコンにしたいとか、
位置の調整をちゃんとしたいとかも可能ですが今回は割愛します。

余談…アニメーションついてますが…

こちらのメニュー、ちなみに、通常メニューにアニメーションを付けて、リンクをマウスオンした時にスムーズに色が変化したり、
ドロップダウンが出るときにぱきっとでずにフェードインして出るようにしています。

リンクに関しては、

ul.cdd_menu a:hover {
    opacity: .5;
    transition: .5s;
    background: rgba(225,225,225,.8);
}

こちらで設定しています。

ドロップダウンをうっすらフェードインしている部分は

li.cdd_menu-dropdown > ul {
    position: absolute;
    background: #CCC;
    visibility: hidden;
    opacity: 0;
}

まずここで、ドロップダウンするメニューを隠すだけでなく、
opacity: 0;にします。

li.cdd_menu-dropdown:hover > ul {
     visibility: visible;
     transition: .5s;
     opacity: 1;     
 }

opacity: 1;に0.5秒かかるように設定しています。

それだけでございます。

ああ、ちょっと前まではこれらもjs使わないとできなかったのにな。

CSSの進歩もすごいでス。

仕組みがわかれば、ドロップダウンメニューを作るのも怖くないですね!

なんて!

私もよくコピペで作っておりましたよ!!

やっとちゃんと覚えました。