3D回転するユニークなヘッダー! かつ多階層メニュー 第2階層はスライドダウンで開閉、第3階層はアコーディオン開閉

先日の多階層メニュー作成の記事を投稿しました。

その応用でメニューそれぞれを立体的な面(四角柱の一面)ととらえ、かつ四角柱をY軸を軸として回転させるアニメーションを作成しました(CSSで回転を実現しています)。
必ずしもヘッダーメニューが上部横一列に並んでいる必要がないとき、若しくはサイドに配置できるため省スペースとなります。
2つのパターン(ノーマルと少し歪ませたもの)がありますので、ご参考になれば幸いです。

使用するファイルは事前準備等は、多階層メニュー作成の記事と同様ですので、割愛させていただきます。

ノーマルパターン

slidedown_3

CODEPENで実装と確認

「Run Pen」をクリックしてください。

See the Pen dropdown&accordion_3 by blue moon (@blue-moon) on CodePen.

HTMLファイル

<body>
  <header>
    <nav>
      <!-- 第1階層のグローバルメニュー -->
      <ul class="main-menu-list">
        <li class="main-menu">
          <p>menu1<i class="fas fa-angle-down"></i></p>
          <!-- 第2階層メニュー -->
          <ul class="category">
            <li>
              <a href="#">category1</a>
              <!-- 第3階層メニュー開閉のためのクリック用アイコン -->
              <span><i class="fas fa-minus"></i></span>
              <!-- 第3階層メニュー -->
              <ul class="item-list">
                <li><a href="#">item1</a></li>
                <li><a href="#">item2</a></li>
                <li><a href="#">item3</a></li>
              </ul>
            </li>
            <li>
              <a href="#">category2</a>
              <span><i class="fas fa-minus"></i></span>
              <ul class="item-list">
                <li><a href="#">item1</a></li>
                <li><a href="#">item2</a></li>
                <li><a href="#">item3</a></li>
              </ul>
            </li>
          </ul>
        </li>  
        <li class="main-menu">
          <p>menu2<i class="fas fa-angle-down"></i></p>
          <ul class="category">
            <li>
              <a href="#">category1</a>
              <span><i class="fas fa-minus"></i></span>
              <ul class="item-list">
                <li><a href="#">item1</a></li>
                <li><a href="#">item2</a></li>
                <li><a href="#">item3</a></li>
              </ul>
            </li>
            <li>
              <a href="#">category2</a>
              <span><i class="fas fa-minus"></i></span>
              <ul class="item-list">
                <li><a href="#">item1</a></li>
                <li><a href="#">item2</a></li>
                <li><a href="#">item3</a></li>
              </ul>
            </li>
          </ul>
        </li>
        <li class="main-menu">
          <p>menu3<i class="fas fa-angle-down"></i></p>
          <ul class="category">
            <li>
              <a href="#">category1</a>
              <span><i class="fas fa-minus"></i></span>
              <ul class="item-list">
                <li><a href="#">item1</a></li>
                <li><a href="#">item2</a></li>
                <li><a href="#">item3</a></li>
              </ul>
            </li>
            <li>
              <a href="#">category2</a>
              <span><i class="fas fa-minus"></i></span>
              <ul class="item-list">
                <li><a href="#">item1</a></li>
                <li><a href="#">item2</a></li>
                <li><a href="#">item3</a></li>
              </ul>
            </li>
          </ul>
        </li>
        <li class="main-menu">
          <p>menu4<i class="fas fa-angle-down"></i></p>
          <ul class="category">
            <li>
              <a href="#">category1</a>
              <span><i class="fas fa-minus"></i></span>
              <ul class="item-list">
                <li><a href="#">item1</a></li>
                <li><a href="#">item2</a></li>
                <li><a href="#">item3</a></li>
              </ul>
            </li>
            <li>
              <a href="#">category2</a>
              <span><i class="fas fa-minus"></i></span>
              <ul class="item-list">
                <li><a href="#">item1</a></li>
                <li><a href="#">item2</a></li>
                <li><a href="#">item3</a></li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </nav>
  </header>
</body>

CSSファイル

/* reset&base */
body {
  font-size: 12px;
  color: #666;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

li {
  line-height: 1.8;
  opacity: 0.8;
}

p {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

nav {
  margin: 30px auto;
  width: 100px;
  perspective: 1000; /* 要素に遠近感を与える */
  -webkit-perspective: 1000;
}

/* 第1階層 */
.main-menu-list {
  transform-style: preserve-3d; /* 子要素を 3D 空間に配置 */
  transform: rotateX(-10deg) rotateY(-20deg);
  animation: rotate 20s linear infinite;
}

@keyframes rotate {
  from {
    transform: rotateX(-10deg) rotateY(20deg);
  }
  to {
    transform: rotateX(-10deg) rotateY(-340deg);
  }
}

.main-menu-list:hover{
  animation-play-state: paused; /* 回転一時停止 */
}
  
.main-menu {
  position: absolute; /* 横並び */
  margin: 0 1px;
  width: 100px;
  height: min-content;
  text-align: center;
  cursor: pointer;
  box-sizing: border-box;
  border: 1px solid #fff;
}

.main-menu:first-child {
  transform: translateZ(50px);
  background-color: #48feff;
}

.main-menu:nth-child(2) {
  transform: rotateY(90deg) translateZ(50px);
  background-color: #fa6099;
}

.main-menu:nth-child(3) {
  transform: rotateY(180deg) translateZ(50px);
  background-color: #fced5c;
}

.main-menu:last-child {
  transform: rotateY(-90deg) translateZ(50px);
  background-color: #94ff5f;
}

.fa-angle-down {
  padding-left: 5px;
  cursor: pointer;
}

/* 第2階層 */
.category {
  padding: 0;
}

.category > li {
  font-size: 0.8em;
}

.main-menu:first-child .category li {
  background-color: #87fdff;
}

.main-menu:nth-child(2) .category li {
  background-color: #fe7dad;
}

.main-menu:nth-child(3) .category li {
  background-color: #fff190;
}

.main-menu:last-child .category li {
  background-color: #b2ff8d;
}

.category li span {
  position: relative;
  cursor: pointer;
}

.fa-minus {
  padding-left: 0;
}

.category li span::after {
  position: absolute;
  top: calc(0.25em * 1.1);
  left: calc(50% - 0.1em);
  width: 0.2em;
  height: 0.875em;
  content: "";
  background-color: #666;
  transition: 0.3s ease-in-out;
  border-radius: 0.1em;
}

.close::after {
  transform: rotate(90deg);
}

/* 第3階層 */
.main-menu:first-child .category li .item-list li {
  background-color: #b7fdff;
}

.main-menu:nth-child(2) .category li .item-list li {
  background-color: #fcabc9;
}

.main-menu:nth-child(3) .category li .item-list li {
  background-color: #fef2b5;
}

.main-menu:last-child .category li .item-list li {
  background-color: #c9fcb2;
}

補足説明

マウスオーバーした時に、アニメーションをストップするため、jQueryのcssメソッドで .css(‘animation’, ”)したり、CSSで :hover {animation: unset} 等すると、マウスが離れた時にまた最初から回転アニメーションが始まってしまいます。
それを解決してくれるのがアニメーションを一時停止する、:hover{animation-play-state: paused; }で、停止したところから再開してくれます。

.main-menu {position: absolute;} がないと、それぞれのメニューが同じ行(回転台?)に配置できません。top やleftの位置は省略していますが、必要に応じて調整してください。
親要素に {display: flex;}としても、同じ行(回転台?)に配置されません。

JSファイル

$(window).on('load resize', function() {
  const cateList = $('header .category');
  const itemList = $('header .item-list');
  const moreIcon = $('.category li span');
  cateList.hide();
  itemList.hide(); 
  
  //第1階層メニューをマウスオーバーで第2階層メニューをスライドダウン
  $('nav .main-menu').hover(function() {
    $(this).children(cateList).not(':animated').slideDown(300);

  },function() {
    moreIcon.removeClass('close');
    $(itemList).slideUp(300);
    $(cateList).slideUp(300);  
  });
  
  //第2階層メニューのアイコンクリックで第3階層メニューをアコーディオン開閉
  $(moreIcon).click(function() {
    $(this).next(itemList).not(':animated').slideToggle(300);
    
    if ($(this).hasClass('close')) {
      moreIcon.removeClass('close');
    }else{  
      $(this).addClass('close');
    }
    
    moreIcon.not($(this)).removeClass('close');
    moreIcon.not($(this)).next(itemList).slideUp(300);
  });
}); 

少しだけ傾いているパターン

HTMLとJSは前述のものを流用しています。

slidedown_4

CODEPEN で実装と確認

See the Pen dropdown&accordion_4 by blue moon (@blue-moon) on CodePen.

CSSファイル

/* reset&base */
body {
  font-size: 12px;
  color: #666;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

li {
  line-height: 1.8;
  opacity: 0.8;
}

p {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

nav {
  margin: 30px auto;
  width: 100px;
  perspective: 1000; /* 要素に遠近感を与える */
  -webkit-perspective: 1000;
}

/* 第1階層 */
.main-menu-list {
  transform-style: preserve-3d; /* 子要素を 3D 空間に配置 */
  transform: rotateX(-10deg) rotateY(-20deg);
  animation: rotate 20s linear infinite;
}

@keyframes rotate {
  from {
    transform: rotateX(-10deg) rotateY(20deg);
  }
  to {
    transform: rotateX(-10deg) rotateY(-340deg);
  }
}

.main-menu-list:hover{
  animation-play-state: paused; /* 回転一時停止 */
}
  
.main-menu {
  position: absolute; /* 横並び */
  margin: 0 1px;
  width: 100px;
  height: min-content;
  text-align: center;
  cursor: pointer;
  box-sizing: border-box;
  border: 1px solid #fff;
}

.main-menu:first-child {
  background-color: #48feff;
  transform: translateZ(50px) skewY(10deg);  
}

.main-menu:nth-child(2) {
  background-color: #fa6099;
  transform: rotateY(90deg) translateZ(50px) translateY(17px) skewY(10deg);  
}

.main-menu:nth-child(3) {
  background-color: #fced5c;
  transform: rotateY(180deg) translateZ(50px)  translateY(17px) skewY(-10deg);
}

.main-menu:last-child {
  background-color: #94ff5f;
  transform: rotateY(-90deg) translateZ(50px) skewY(-10deg);  
}

.fa-angle-down {
  padding-left: 5px;
  cursor: pointer;
}

/* 第2階層 */
.category {
  padding: 0;
}

.category > li {
  font-size: 0.8em;
}

.main-menu:first-child .category li {
  background-color: #87fdff;
}

.main-menu:nth-child(2) .category li {
  background-color: #fe7dad;
}

.main-menu:nth-child(3) .category li {
  background-color: #fff190;
}

.main-menu:last-child .category li {
  background-color: #b2ff8d;
}

.category li span {
  position: relative;
  cursor: pointer;
}

.fa-minus {
  padding-left: 0;
}

.category li span::after {
  position: absolute;
  top: calc(0.25em * 1.1);
  left: calc(50% - 0.1em);
  width: 0.2em;
  height: 0.875em;
  content: "";
  background-color: #666;
  transition: 0.3s ease-in-out;
  border-radius: 0.1em;
}

.close::after {
  transform: rotate(90deg);
}

/* 第3階層 */
.main-menu:first-child .category li .item-list li {
  background-color: #b7fdff;
}

.main-menu:nth-child(2) .category li .item-list li {
  background-color: #fcabc9;
}

.main-menu:nth-child(3) .category li .item-list li {
  background-color: #fef2b5;
}

.main-menu:last-child .category li .item-list li {
  background-color: #c9fcb2;
}

補足説明

傾きを持たせるtransformプロパティの値にskew(●●deg)を設定しており、これは子要素(文字)にも引き継がれます。
もし、文字は傾かせたくないということであれば、子要素には親要素とは同じ整数を反対の正負として、skewに設定してください。
例えば、親要素が{transform: skewY(10deg);}となっている場合、子要素の文字に{transform: skewY(-10deg);}とすれば相殺され文字はブラウザに対しては平行となります。但し、ボックス内ではボックスの辺との平行は維持されません。
また、transformプロパティは、aタグや、spanタグのインライン要素には効きませんので、ブロック要素もしくは、インラインブロック要素へ変換するのをお忘れなく。

変形可能な要素のみが transform の対象になります。つまり、レイアウトが CSS ボックスモデルによって管理される、非置換インラインボックス、表の列ボックス、表の列グループボックスを除くすべての要素です。

MDN CSSカスケーディングスタイルシートより引用

実際、menu1,menu2とmenu3,menu4は、文字の傾き方向が違いますが、傾きの調整は省略しております。
エッシャーの『上昇と下降』の中で描かれているペンローズの階段ではありませんが、前者グループと後者グループで傾きを逆方向にしなければ、最初のmenu1とmenu4がくっつきません。

タイトルとURLをコピーしました