ホーム(記事一覧)へ

CSSでul liが入れ子の横並びサブメニューありデザイン

ul liでメニューを作ることはよくあります。さらにサブメニューがあるときliの中にさらにul liを入れることになります。

ul liが入れ子になるとCSSが非常に複雑になります。

CSSでul liが入れ子の横並びサブメニューありデザインについて解説します。

完成形

完成形は下記のとおりです。

「メニュー2」「メニュー4」をクリックすると入れ子のサブメニューが表示されます。

レスポンシブ対応もしていますのでブラウザ幅を狭くしてみてください。

<script src="https://code.jquery.com/jquery.min.js"></script>
<script>
$(function() {
    $(".example>li>span").click(function() {                   		               if($(this).next().hasClass('open')){
            $(this).next().removeClass("open").slideToggle;
			return;
		}
        $(".example>li>ul").removeClass("open");
        $(this).next().addClass("open");
    });
});
</script>
<style>
.example,.example>li>ul.open{
    display: flex;
    padding: 0;
    margin: 0;
    list-style: none;
    border-top: 1px solid #333;
    border-left: 1px solid #333;
}
.example{
    position: relative;
}
.example>li,.example>li>ul>li{
    display: flex;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    border-bottom: 1px solid #333;
    border-right: 1px solid #333;
}
.example>li>a,.example>li>span,.example>li>ul>li>a{
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
}
.example>li>span{
    padding-right: 30px;
    position: relative;
    cursor: pointer;
}
.example>li>span::after{
    content: "";
    display: block;
    width: 10px;
    height: 10px;
    border-right: 2px solid #333;
    border-bottom: 2px solid #333;
    transform: rotate(45deg);
    position: absolute;
    right: 10px;
    top: 0;
    bottom: 5px;
    margin: auto;
}
.example>li>ul{
    display: none;
    width: 100%;
    position: absolute;
    left: -1px;
    top: calc(100% - 1px);
}
.example>li>ul>li>a{
    background: #f2f2f2;
    font-size: 85%;
}
@media(max-width:800px){
    .example,.example>li>ul.open,.example>li,.example>li>span{
        display: block;
    }
    .example>li>a,.example>li>span,.example>li>ul>li>a{
        justify-content: flex-start;
        text-align: left;
    }
    .example>li>ul.open{
        border-left: none;
        position: static;
    }
    .example>li>ul>li{
        border-right: none;
    }
    .example>li>ul>li>a{
        padding-left: 50px;
    }
}
</style>
<ul class="example">
    <li><a href="#">メニュー1</a></li>
    <li><span>メニュー2</span>
        <ul>
            <li><a href="#">サブメニュー2-1</a></li>
            <li><a href="#">サブメニュー2-2</a></li>
            <li><a href="#">サブメニュー2-3</a></li>
            <li><a href="#">サブメニュー2-4</a></li>
        </ul>
    </li>
    <li><a href="#">メニュー3</a></li>
    <li><span>メニュー4</span>
        <ul>
            <li><a href="#">サブメニュー4-1</a></li>
            <li><a href="#">サブメニュー4-2</a></li>
            <li><a href="#">サブメニュー4-3</a></li>
        </ul>
    </li>
    <li><a href="#">メニュー5</a></li>
</ul>

以下より手順を詳しく解説します。

1.html

htmlは下記のものをイメージしています。

<ul class="example">
    <li><a href="#">メニュー1</a></li>
    <li><span>メニュー2</span>
        <ul>
            <li><a href="#">サブメニュー2-1</a></li>
            <li><a href="#">サブメニュー2-2</a></li>
            <li><a href="#">サブメニュー2-3</a></li>
            <li><a href="#">サブメニュー2-4</a></li>
        </ul>
    </li>
    <li><a href="#">メニュー3</a></li>
    <li><span>メニュー4</span>
        <ul>
            <li><a href="#">サブメニュー4-1</a></li>
            <li><a href="#">サブメニュー4-2</a></li>
            <li><a href="#">サブメニュー4-3</a></li>
        </ul>
    </li>
    <li><a href="#">メニュー5</a></li>
</ul>

メインメニューが上段のul liです。サブメニューがある場合はli内にさらにul liを設置します。

サブメニューがないメインメニューはリンクをつけます。サブメニューがあるメインメニューはクリックしたらサブメニューが開く仕掛けにするためにaタグではなく別のタグ(span)にします。

マウスオーバーでサブメニューが開くようにする手もありますが、スマホやタブレットでは効かないことと、ユーザビリティを配慮してクリックしたらサブメニューが開く方法をおススメします。

ul liが入れ子になっているときのセレクタ指定

CSSの解説に入る前に、ul liが入れ子になっているときのセレクタ指定について解説します。

普段ならliを指定するときこのように指定するでしょう。

example li{}

※class="example"は上段のulです。

しかしこのように指定すると.example直下のliだけでなく、入れ子になっているサブメニューのliにも指定されてしまいます。

.example>li{}

上記のように「>」があると.example直下のliだけを指定できます。

.example>li>ul{}
.example>li>ul>li{}

上記のように指定すると入れ子のul、liを直接指定できます。

これをふまえてCSSの解説をします。

2.メインメニューのul liをデザイン

まずはメインメニューのul liをデザインします。

サブメニューはデザインのジャマになるので「display: none」でいったん隠します。

htmlは変わりありません。CSSは下記のとおりです。

.example{
    display: flex;
    padding: 0;
    margin: 0;
    list-style: none;
    border-top: 1px solid #333;
    border-left: 1px solid #333;
}
.example>li{
    display: flex;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    border-bottom: 1px solid #333;
    border-right: 1px solid #333;
}
.example>li>a,.example>li>span{
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
}
.example>li>ul{
    display: none;
}

ul liをflexで横並べする方法は下記記事で詳しく解説します。

サブメニューがあることがわかるようにアイコンをつける

サブメニューがあるメインメニューの横に下向きのアイコンを表示します。これにより他のメニューと違う動きをすることを伝えることができます。

「.example>li>span」と「.example>li>span::after」が追加部分です。

.example{
    display: flex;
    padding: 0;
    margin: 0;
    list-style: none;
    border-top: 1px solid #333;
    border-left: 1px solid #333;
}
.example>li{
    display: flex;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    border-bottom: 1px solid #333;
    border-right: 1px solid #333;
}
.example>li>a,.example>li>span{
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    width: 100%;
    padding: 10px;
    position: relative;
    box-sizing: border-box;
}
.example>li>span{
    padding-right: 30px;
    position: relative;
}
.example>li>span::after{
    content: "";
    display: block;
    width: 10px;
    height: 10px;
    border-right: 2px solid #333;
    border-bottom: 2px solid #333;
    transform: rotate(45deg);
    position: absolute;
    right: 10px;
    top: 0;
    bottom: 5px;
    margin: auto;
}
.example>li>ul{
    display: none;
}

矢印アイコンのつけかたはググればでてくるのでここでは解説を省略します。

3.サブメニュー(入れ子)のul liをデザイン

続いてサブメニュー(入れ子)のul liをデザインします。

サブメニューがたくさんあるとジャマなので、ひとつだけ表示されるようにします。

.example,.example>li:nth-of-type(2)>ul{
    display: flex;
    padding: 0;
    margin: 0;
    list-style: none;
    border-top: 1px solid #333;
    border-left: 1px solid #333;
}
.example{
    /*追加*/position: relative;
}
.example>li,.example>li>ul>li{
    display: flex;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    border-bottom: 1px solid #333;
    border-right: 1px solid #333;
}
.example>li>a,.example>li>span,.example>li>ul>li>a{
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
}
.example>li>span{
    padding-right: 30px;
    position: relative;
}
.example>li>span::after{
    content: "";
    display: block;
    width: 10px;
    height: 10px;
    border-right: 2px solid #333;
    border-bottom: 2px solid #333;
    transform: rotate(45deg);
    position: absolute;
    right: 10px;
    top: 0;
    bottom: 5px;
    margin: auto;
}
.example>li>ul{
    display: none;
}
.example>li:nth-of-type(2)>ul{
    width: 100%;
    position: absolute;
    left: -1px;
    top: calc(100% - 1px);
}
.example>li>ul>li>a{
    background: #f2f2f2;
    font-size: 85%;
}

メインメニューの下にサブメニューが横並びで表示されるようにします。

ポイントはサブメニューをposition: absoluteで下につけることです。

これにより、メニューより下の要素を動かさずにサブメニューを表示させることができます。

基準を上段のulである「.example」にします。これによりメインメニューの幅と同じ幅にできます。「position: relative」を指定すると基準にできます。

サブメニューのulに「position: absolute」を指定します。

top:100%と指定すると基準の要素である「.example」の下につけることができます。

ただし、borderの太さ分調整が必要です。

ここではサブメニューのli、aをメインメニューとほぼ同じにしていますが、必要に応じて調整してください。

とりあえず背景色と文字サイズを変えています。

4.クリックしたら表示

メインメニューをクリックしたら表示されるようにします。

これにはjQueryを利用します。

「メニュー2」「メニュー4」をクリックしてみてください。

jQueryは下記をhtmlに追記します。headタグ内が望ましいでしょう。

<script src="https://code.jquery.com/jquery.min.js"></script>
<script>
$(function() {
    $(".example>li>span").click(function() {                   		               if($(this).next().hasClass('open')){
            $(this).next().removeClass("open");
			return;
		}
        $(".example>li>ul").removeClass("open");
        $(this).next().addClass("open");
    });
});
</script>

spanがクリックされたらサブメニューのulにclass="open"をつけます。このopenにはCSS側で「display:flex」が指定されており、「display:none」を打ち消して表示されるようになります。

サブメニューが複数あり、その複数がopenしないように、先にすべてのサブメニューのulからclass="open"を削除しましょう。

class="open"がすでについている、つまりサブメニューが開いているときにクリックされたらそのメニューをとじさせるためclass="open"を削除しましょう。

ちなみに「slideToggle」を利用すると、表示するとき「display:block」が指定されflexが効かなくなります。どうしても利用したいときはサブメニューの外側にdivをつけ、それを開くようにするなど工夫しましょう。

jQueryについては下記をご覧ください。

CSSは下記のとおりです。

.example,.example>li>ul.open{
    display: flex;
    padding: 0;
    margin: 0;
    list-style: none;
    border-top: 1px solid #333;
    border-left: 1px solid #333;
}
.example{
    position: relative;
}
.example>li,.example>li>ul>li{
    display: flex;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    border-bottom: 1px solid #333;
    border-right: 1px solid #333;
}
.example>li>a,.example>li>span,.example>li>ul>li>a{
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
}
.example>li>span{
    padding-right: 30px;
    position: relative;
    cursor: pointer;
}
.example>li>span::after{
    content: "";
    display: block;
    width: 10px;
    height: 10px;
    border-right: 2px solid #333;
    border-bottom: 2px solid #333;
    transform: rotate(45deg);
    position: absolute;
    right: 10px;
    top: 0;
    bottom: 5px;
    margin: auto;
}
.example>li>ul{
    display: none;
    width: 100%;
    position: absolute;
    left: -1px;
    top: calc(100% - 1px);
}
.example>li>ul>li>a{
    background: #f2f2f2;
    font-size: 85%;
}

サブメニューを「display: none」でいったん全部消します。

サブメニューに.openがついたとき表示されるように「.example>li>ul.open」に「display: flex」が指定されるようにします。

あとはspanにマウスが乗ったときクリックできることがわかるように「cursor: pointer」を指定するといいでしょう。

5.レスポンシブ対応

スマホに対応させましょう。

スマホでは縦のメニューにします。

ブラウザ幅を狭くして下記を確認してみてください。

CSSは下記を追加しています。

@media(max-width:800px){
    .example,.example>li>ul.open,.example>li,.example>li>span{
        display: block;
    }
    .example>li>a,.example>li>span,.example>li>ul>li>a{
        justify-content: flex-start;
        text-align: left;
    }
    .example>li>ul.open{
        border-left: none;
        position: static;
    }
    .example>li>ul>li{
        border-right: none;
    }
    .example>li>ul>li>a{
        padding-left: 50px;
    }
}

スマホ対応時のCSSを指定するためメディアクエリを利用します。

「display:flex」を指定していると横並びになってしまうため「display:block」を指定して縦並びにします。

縦並びにすると中央寄せの文字は読みづらいため左寄せにします。

サブメニューはメインメニュー全体の下に付けるのではなく、クリックしたメニュー直下に付けます。よってpositionを解除するために「position: static」を指定します。

あとは線やインデントなどデザインを調節しましょう。

これで完成です。

まとめ

  • ul liの入れ子をセレクタ指定するときは「>」を利用する
  • 横並べはdisplay:flexを利用する
  • サブメニューはposition:absoluteでメインメニューの下につける
  • クリックしたら表示させるにはjQueryを利用する
  • レスポンシブ対応としてスマホでは縦並びにする。

以上、CSSでul liが入れ子の横並びサブメニューありデザインの解説でした。

関連記事