CSSだけ!クリックでスムーズに開閉するアコーディオンメニュー

以前書いた「jQueryとCSS3を使ったアコーディオンメニューを詳しく説明します|Webpark」という記事でCSSのみで作れないかというコメントをいただきましたので作ってみました。

accordion-css.png

この前「CSSだけで作る動きのあるドロップダウンメニュー|Webpark」という記事を書きました。jQueryでしそうなことをCSSのみで作ったのですが、これはマウスを乗せたとき動くようにしたいのでhoverを使いました。

今回はクリックで開閉するということで、hoverは使えません。では何を使うのか。

ラジオボタンを使います。ある項目にチェックするとそれまでチェックされていた項目のチェックが外れる。アコーディオンメニューと仕組みが一緒です。

今回もサンプルを用意していますのでご覧ください。

IE8以下の場合「:checked」が非対応なのでうまく表示されません。しかし、CSS3セレクタはSelectivizrを使えば簡単に対応できます。使い方は「CSS3を使うにあたって知っておきたいIE対策のまとめ|Webpark」をご参考に。

それではHTMLから紹介します。

HTML

<div id="accordion">
  <form> 
    <label>
      <input type="radio" name="btn" checked />
      <div>
        <div>カテゴリー1</div>
        <ul>
          <li><a href="#">サブカテゴリー1</a></li>
          <li><a href="#">サブカテゴリー2</a></li>
          <li><a href="#">サブカテゴリー3</a></li>
        </ul>
      </div>
    </label>
    <label>
      <input type="radio" name="btn" />
      <div>
        <div>カテゴリー2</div>
        <ul>
          <li><a href="#">サブカテゴリー1</a></li>
          <li><a href="#">サブカテゴリー2</a></li>
          <li><a href="#">サブカテゴリー3</a></li>
        </ul>
      </div>
    </label>
    <label>
      <input type="radio" name="btn" />
      <div>
        <div>カテゴリー3</div>
        <ul>
          <li><a href="#">サブカテゴリー1</a></li>
          <li><a href="#">サブカテゴリー2</a></li>
          <li><a href="#">サブカテゴリー3</a></li>
        </ul>
      </div>
    </label>
    <label>
      <input type="radio" name="btn" />
      <div>
        <div>カテゴリー4</div>
        <ul>
          <li><a href="#">サブカテゴリー1</a></li>
          <li><a href="#">サブカテゴリー2</a></li>
          <li><a href="#">サブカテゴリー3</a></li>
        </ul>
      </div>
    </label>
    <label>
      <input type="radio" name="btn" />
      <div>
        <div>カテゴリー5</div>
        <ul>
          <li><a href="#">サブカテゴリー1</a></li>
          <li><a href="#">サブカテゴリー2</a></li>
          <li><a href="#">サブカテゴリー3</a></li>
        </ul>
      </div>
    </label>
  </form> 
</div>

CSS

続いてCSSです。かなり長くなっています。先に全体を載せて、後で個別に解説します。

@font-face {
  font-family: 'Typicons';
  src: url('fonts/typicons-regular-webfont.eot');
  src: url('fonts/typicons-regular-webfont.eot?#iefix') format('embedded-opentype'),
    url('fonts/typicons-regular-webfont.woff') format('woff'),
    url('fonts/typicons-regular-webfont.ttf') format('truetype'),
    url('fonts/typicons-regular-webfont.svg#TypiconsRegular') format('svg');
  font-weight: normal;
  font-style: normal;
}
#accordion{
  position:relative;
  width: 500px;
  margin: 0 auto;
  padding: 0;
  border-top: 15px solid #1b4958;
  border-bottom: 15px solid #1b4958;
  border-radius: 3px;
  font-size: 16px;
  line-height: 1;
}
#accordion input{
  position:absolute;
  height: 0;
  padding: 0;
}
#accordion div div{
  position: relative;
  padding: 15px 10px 12px 40px;
  border-top: 1px solid #d4ebf2;
  border-bottom: 1px solid #86c5da;
  background: #add8e6;
}
#accordion label:first-child div div{
  border-top: 0;
}
#accordion label:last-child div div{
  border-bottom: 0;
}
#accordion div div:hover{
  background: #a0d2e2;
  cursor: pointer;
}
#accordion div div:before{
  position:absolute;
  top: 13px;
  left:10px;
  color: #2f7f99;
  font: 24px/100% 'Typicons';
  content: "\0023";
}
#accordion div div:after{
  position:absolute;
  top: 15px;
  right:10px;
  color: #2f7f99;
  font: 20px 'Typicons';
  content: "7";
  -moz-transition: .3s;
  -webkit-transition: .3s;
  -o-transition: .3s;
  -ms-transition: .3s;
  transition: .3s;
}
#accordion input:checked + div div:after{
  top: 12px;
  right: 15px;
  -moz-transform: rotate(90deg);
  -webkit-transform: rotate(90deg);
  -o-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
}
#accordion ul{
  list-style: none;
  margin: 0;
  background: #e1f1f6;
}
#accordion ul li a{
  display: block;
  overflow: hidden;
  height: 0;
  padding: 0px 70px;
  color: #333;
  text-decoration: none;
  -moz-transition: .3s;
  -webkit-transition: .3s;
  -o-transition: .3s;
  -ms-transition: .3s;
  transition: .3s;
}
#accordion ul li a:hover{
  border-top-color: #c7e4ee;
  background: #d4ebf2;
  color: #1b4958;
}
#accordion input:checked + div ul li a{
  position:relative;
  background: none;
  line-height: 1;
  height: 16px;
  padding: 13px 70px;
  border-top: 1px solid #fff;
  border-bottom: 1px solid #a0d2e2;
}
#accordion input:checked + div ul li a:before{
  position: absolute;
  top: 16px;
  left: 45px;
  color: #2f7f99;
  font:16px/100% 'Typicons';
  content: "x";
  -moz-transition: .3s;
  -webkit-transition: .3s;
  -o-transition: .3s;
  -ms-transition: .3s;
  transition: .3s;
}
#accordion input:checked + div ul li:first-child a{
  border-top: 0px;
  box-shadow: 0 7px 7px -7px rgba(0,0,0,.5) inset;
}
#accordion input:checked + div ul li:last-child a{
  border-bottom: 1px solid #d4ebf2;
}
#accordion input:checked + div ul li a:hover{
  background: #d4ebf2;
  border-top-color: #eef7fa;
}

セレクタはどこか分かりやすいように省略さずに書いています。

Webフォントの読込み
@font-face {
  font-family: 'Typicons';
  src: url('fonts/typicons-regular-webfont.eot');
  src: url('fonts/typicons-regular-webfont.eot?#iefix') format('embedded-opentype'),
    url('fonts/typicons-regular-webfont.woff') format('woff'),
    url('fonts/typicons-regular-webfont.ttf') format('truetype'),
    url('fonts/typicons-regular-webfont.svg#TypiconsRegular') format('svg');
  font-weight: normal;
  font-style: normal;
}

アイコンにWebフォント使っていますので最初に読み込みます。Webフォントについては「IEでもWebフォントが使えることを知ったので勉強してみました|Webpark」をご参考に。

アコーディオン全体
#accordion{
  position:relative;
  width: 500px;
  margin: 0 auto;
  padding: 0;
  border-top: 15px solid #1b4958;
  border-bottom: 15px solid #1b4958;
  border-radius: 3px;
  font-size: 16px;
  line-height: 1;
}

これは特に問題ないですね。

ラジオボタン
#accordion input{
  position:absolute;
  height: 0;
  padding: 0;
}

ラジオボタンは表示されないようにします。表示はされませんがlabelで囲まれた部分をクリックするとチェックされたことになります。

親カテゴリー
#accordion div div{
  position: relative;
  padding: 15px 10px 12px 40px;
  border-top: 1px solid #d4ebf2;
  border-bottom: 1px solid #86c5da;
  background: #add8e6;
}

カテゴリー1~5の部分です。ボーダーを2本重なるようにしています。後で紹介する左右のアイコンの表示位置の基準となるため「position: relative;」を指定します。

親カテゴリーの最初と最後
#accordion label:first-child div div{
  border-top: 0;
}
#accordion label:last-child div div{
  border-bottom: 0;
}

先ほど2本のボーダーを重ねましたが、必要のないカテゴリー1の上のボーダーとカテゴリー5の下のボーダーをなくします。

カテゴリー1~5(オンマウス)
#accordion div div:hover{
  background: #a0d2e2;
  cursor: pointer;
}

マウスを乗せたときに少しだけ色は濃くなります。この辺の色の使い方は0to255を使って決めています。使い方は「カラーツール「0to255」で色を決めてメニューを作ってみる|Webpark」をご参考に。

カテゴリー1~5の左右にあるアイコン
#accordion div div:before{
  position:absolute;
  top: 13px;
  left:10px;
  color: #2f7f99;
  font: 24px/100% 'Typicons';
  content: "\0023";
}
#accordion div div:after{
  position:absolute;
  top: 15px;
  right:10px;
  color: #2f7f99;
  font: 20px 'Typicons';
  content: "7";
  -moz-transition: .3s;
  -webkit-transition: .3s;
  -o-transition: .3s;
  -ms-transition: .3s;
  transition: .3s;
}

擬似要素で左右にアイコンを表示します。右側のアイコンはアコーディオンが開く際に下を向きます。その変化に動きをつけるためにtransitionを使います。

開いたときの右側のアイコン
#accordion input:checked + div div:after{
  top: 12px;
  right: 15px;
  -moz-transform: rotate(90deg);
  -webkit-transform: rotate(90deg);
  -o-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
}

ラジオボタンにチェックが入っているときのカテゴリー1~5の右側のアイコンの設定です。90度傾いて矢印が下を向くようになります。

サブカテゴリー全体
#accordion ul{
  list-style: none;
  margin: 0;
  background: #e1f1f6;
}

ここからはサブカテゴリー内の設定になります。

サブカテゴリーのリンク
#accordion ul li a{
  display: block;
  overflow: hidden;
  height: 0;
  padding: 0px 70px;
  color: #333;
  text-decoration: none;
  -moz-transition: .3s;
  -webkit-transition: .3s;
  -o-transition: .3s;
  -ms-transition: .3s;
  transition: .3s;
}

普段は閉じていますので表示しないようにします。開くときに動きをつけるため「transition」を使います。

サブカテゴリーのリンク(チェック)
#accordion input:checked + div ul li a{
  position:relative;
  background: none;
  line-height: 1;
  height: 16px;
  padding: 13px 70px;
  border-top: 1px solid #fff;
  border-bottom: 1px solid #a0d2e2;
}

アコーディオンが開いているときに設定です。「input:checked + div」でチェックがされているinput要素の隣のdiv要素ということになります。

サブカテゴリーの最初と最後
#accordion input:checked + div ul li:first-child a{
  border-top: 0;
  box-shadow: 0 7px 7px -7px rgba(0,0,0,.5) inset;
}
#accordion input:checked + div ul li:last-child a{
  border-bottom: 0;
}

親カテゴリーと同じように最初サブカテゴリーの上と最後のサブカテゴリーの下のボーダーを消します。また、最初のサブカテゴリーの上側にシャドウを付けています。

サブカテゴリー(オンマウス)
#accordion input:checked + div ul li a:hover{
  background: #d4ebf2;
  border-top-color: #eef7fa;
}

サブカテゴリーにマウスを乗せたときに背景を少し濃くします。

サブカテゴリーの左側のアイコン
#accordion input:checked + div ul li a:before{
  position: absolute;
  top: 16px;
  left: 45px;
  color: #2f7f99;
  font:16px/100% 'Typicons';
  content: "x";
  -moz-transition: .3s;
  -webkit-transition: .3s;
  -o-transition: .3s;
  -ms-transition: .3s;
  transition: .3s;
}

擬似要素を使って右側にアイコンを表示します。

さいごに

ということでCSSだけで作ったアコーディオンメニューを紹介しました。

ただ、今回のような使い方が正しい使い方かどうかは分かりません。しかし、ラジオボタンを使う以外にCSSだけでクリックするタイプのアコーディオンメニューを作る方法が思い付きませんでした。

ラジオボタンがありならタブメニューなんかも簡単に作れそうです。

強引な気もしますが、こんな方法もあるのかと思っていただければうれしいです。

フィードやTwitterで最新情報をチェック
follow us in feedly
この記事に付いているタグの最新記事一覧
loading...
コメント
有益な情報、いつもありがとうございます。WebParkさん天才かもね。。。
羨ましいですよ。WebParkさんのそのCSSとHtmlそしてJQueryの応用力!!!
毎日、私も勉強していますけど、WebParkさんほどできないんですね。
次の御記事楽しみに待ちます。
あ〜すみませんが、ひょっとして”WordPress”のことご存知ですか。いろいろ
調べていますけど、ここ韓国では互換性問題とかIEのActive-Xのため機能上
も問題があって外国のように活発ではないそうですけど、よいProgramだと
思います。必ず学びたいんです。日本語の”〜させてもらう”とか”〜してもらう”
とかの表現が韓国語にはない故、私の日本語がおかしいかもしれません。
まあ〜よくなると思います。では。。byebye~
【2013/04/23 18:03】 | JiWon #ofxKis3k | [edit]
JiWon さん

コメントありがとうございます。
私もまだまだですがそう言っていただけると嬉しいです。

WordPressはもちろん知っていますよ。
WordPressを使っていくつかブログを作成したこともあります。
プラグインもたくさんあって便利ですね。

またお立ち寄りくださいね~
【2013/04/26 18:07】 | 管理人 #E2ywrYdA | [edit]
サブカテゴリーを追加したのですが、追加したサブカテゴリーの下に余計な空白ができてしまいます。

対処法をご教示いただけないでしょうか。
宜しくお願いいたします。
【2013/12/04 15:27】 | help! #ECGAVm2k | [edit]
help! さん

実際に見てみないと原因は分かりませんが
「margin:0;」や「padding:0」を追加すると
解決するかもしれません。

1つずつ地道に確認することが大切だと思います。

うまくいくことを願っています。
【2013/12/05 06:37】 | 管理人 #E2ywrYdA | [edit]
とても分かりやすいサンプルおよびコードをありがとうございます。
大変参考になりました。

一方で、実際に使って試したところ、html5 のバリデーションで label の中の div が許されないという警告が出ました。
何か解決策はあれば、ご教授いただければと思います。
【2014/02/02 18:30】 | MasaYan #- | [edit]
すみません、試行錯誤の末、自己解決しました。

以下はちゃんと書いていませんが、参考になると思いますので、載せます。
<div><label for="hoge">カテゴリー1</label></div>
<input class="accordion" type="radio" name="btn" id="hoge" checked />
<div>
<ul>
<li><a href="#">サブカテゴリー1</a></li>
<li><a href="#">サブカテゴリー2</a></li>
<li><a href="#">サブカテゴリー3</a></li>
</ul>
</div>

などとして、css で、
input.accordion + div {
// 何かしら
}
input.accordion:checked + div {
// 何かしら
}
等の隣接セレクタを使えばなんとかなると思います。

私は、メニューは作らなかったのですが、html の一部をクリックするまで隠したい要望があり、応用させていただきました。ありがとうございました。
【2014/02/02 19:04】 | MasaYan #AcMhDJQE | [edit]
MasaYan さん

コメントありがとうございます。
そしてお返事遅くなりすみませんでした。

label の中の div ってダメなんですね。
恥ずかしながら勉強不足でした。。

確かに隣接セレクタで解決できそうですね。
jQueryを使えばいい気もしますが、
こうやって考えるのは面白いです。
勉強になります。
【2014/02/04 18:09】 | 管理人 #E2ywrYdA | [edit]
IE7,8で動きませんね。
仕事では使えないみたいです。
【2014/09/29 10:58】 | iga #- | [edit]
iga さん

コメントありがとうございます。

記事にありますが、IE8以下の場合「:checked」が非対応なのでうまく表示されません。
ただ、Selectivizrを使えば簡単に対応できることもあり記事にさせていただきました。
【2014/09/29 20:29】 | 管理人 #E2ywrYdA | [edit]
こんにちは。
アコーディオンメニューを試してみて、とても役立ちました!
有益な情報ありがとうございます。
ひとつ質問なのですが、アコーディオンメニューをクリックでオープンさせることはできますが
閉じることはできますか?
できれば <div>カテゴリー1</div>部分をクリックするとオープン、
もう一度クリックすると閉じる、というように動かせたいと思っています。

今、htmlを下記のように記述して、
×を押すと閉じる、という仕様にしているのですが、
×の部分の幅が気になります。
開いた際に閉じるマークが出てくる仕様にする場合はどのようにすればいいか
解決策や代案があれば教えて頂ければ嬉しいです。
よろしくお願い致します。

<div id="accordion">
<form>
<label>
<input type="radio" name="btn" />
<div>
<div>menu</div>
<ul>
<li><a href="#">サブカテゴリー1</a></li>
<li><a href="#">サブカテゴリー2</a></li>
<li><a href="#">サブカテゴリー3</a></li>
</ul>
</div>
</label>
<label>
<input type="radio" name="btn" />
<div>
<div>×</div>
</div>
</label>
</form>
</div>
【2015/07/28 12:26】 | no name #dOcone5o | [edit]
no name さん

ラジオボタンの性質上、2回クリックして閉じるというのはできません。
チェックボックスならできるかもしれませんが。

載せられているHTMLで仰られていることをするには
javascriptが必要になってくると思います。
【2015/07/28 23:43】 | 管理人 #E2ywrYdA | [edit]









※コメントはご意見ご感想や間違いのご指摘等にしていただけますようお願いいたします。コメントを確認する時間がなく、技術的なご質問をいただいても答えできません。申し訳ございませんがご理解のほどお願いいたします。

Recent Entry
Popular Entry
  • このエントリーをはてなブックマークに追加