タブ

<ul class="tab">
    <li><a href="#tab1" class="tab__item btn is-current">01</a></li>
    <li><a href="#tab2" class="tab__item btn">02</a></li>
    <li><a href="#tab3" class="tab__item btn">03</a></li>
    <li><a href="#tab4" class="tab__item btn">04</a></li>
</ul>
<div class="tab__content">
    <div class="tab__content-item is-enter" id="tab1">01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。01のテキストが入ります。</div>
    <div class="tab__content-item" id="tab2">02のテキストが入ります。02のテキストが入ります。02のテキストが入ります。02のテキストが入ります。</div>
    <div class="tab__content-item" id="tab3">03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。<br>03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。03のテキストが入ります。</div>
    <div class="tab__content-item" id="tab4">04のテキストが入ります。04のテキストが入ります。04のテキストが入ります。04のテキストが入ります。04のテキストが入ります。04のテキストが入ります。04のテキストが入ります。04のテキストが入ります。04のテキストが入ります。</div>
</div>
  • Content:
    .tab {
      display: flex;
    }
    
    .tab__item {
      display: block;
      margin-right: 1px;
    }
    
    .tab__item.is-current {
      background: #555;
      color: #fff;
    }
    
    .tab__content {
      position: relative;
      background: #555;
      color: #fff;
    }
    
    .tab__content.is-change-active {
      transition: height 0.3s;
      overflow: hidden;
    }
    
    .tab__content-item {
      display: none;
      padding: 16px;
    }
    
    .tab__content-item.is-enter {
      display: block;
    }
    
    .tab__content-item.is-enter-active {
      position: absolute;
      opacity: 0;
      transition: opacity 0.3s;
    }
    
    .tab__content-item.is-enter-to {
      opacity: 1;
    }
    
    .tab__content-item.is-leave-active {
      position: absolute;
      opacity: 1;
      transition: opacity 0.3s;
    }
    
    .tab__content-item.is-leave-to {
      opacity: 0;
    }
    
  • URL: /components/raw/tab/tab.css
  • Filesystem Path: src\components\04-tab\tab.css
  • Size: 772 Bytes
  • Content:
    .tab {
      display: flex;
      &__item {
        display: block;
        margin-right: 1px;
        &.is-current {
          background: $color_sub;
          color: $color_opposite;
        }
      }
      &__content {
        position: relative;
        background: $color_sub;
        color: $color_opposite;
        &.is-change-active {
          transition: height $speed_fast;
          overflow: hidden;
        }
        &-item {
          display: none;
          padding: $space_lg;
          &.is-enter {
            display: block;
          }
          &.is-enter-active {
            position: absolute;
            opacity: 0;
            transition: opacity $speed_fast;
          }
          &.is-enter-to {
            opacity: 1;
          }
          &.is-leave-active {
            position: absolute;
            opacity: 1;
            transition: opacity $speed_fast;
          }
          &.is-leave-to {
            opacity: 0;
          }
        }
      }
    }
    
  • URL: /components/raw/tab/tab.scss
  • Filesystem Path: src\components\04-tab\tab.scss
  • Size: 868 Bytes
  • Content:
    (function() {
      const tabItems = document.querySelectorAll('.tab__item');
      const tabContentEl = document.querySelector('.tab__content');
      const tabContentItems = document.querySelectorAll('.tab__content-item');
    
      if(!tabContentEl) {return;}
      let changeFlag = false;
    
      transitionSet(tabContentItems);
      tabItems.forEach(item => {
        item.addEventListener('click', (e) => {
          e.preventDefault();
          // 切り替え時にクリックした場合、もしくは現在表示されているタブをクリックした場合は処理しない
          if(changeFlag || item.classList.contains('is-current')) {return;}
          changeFlag = true;
          changeTab(item);
          changeTabContent(item);
        });
      });
    
      function changeTab(item) {
        tabItems.forEach(item => {
          item.classList.remove('is-current');
        });
        item.classList.add('is-current');
      }
    
      function changeTabContent(item) {
        let currentTab = document.querySelector('.tab__content-item.is-enter');
        let nextTab = document.querySelector(item.getAttribute('href'));
        // position:absolute時にレイアウトが崩れないよう、切り替え時のみwidth・heightを固定
        tabContentEl.style.width = `${tabContentEl.clientWidth}px`;
        tabContentEl.style.height = `${tabContentEl.clientHeight}px`;
    
        // 切り替え時のクラスを付与
        tabContentEl.classList.add('is-change-active');
        currentTab.classList.add('is-leave-active');
        nextTab.classList.add('is-enter', 'is-enter-active');
        let nextTabHeight = nextTab.scrollHeight;
        setTimeout(() => {
          tabContentEl.style.height = `${nextTabHeight}px`;
          currentTab.classList.add('is-leave-to');
          nextTab.classList.add('is-enter-to');
        });
      }
    
      function transitionSet(items) {
        tabContentEl.addEventListener('transitionend', () => {
          // 切り替え時のwidth・height固定を解除
          tabContentEl.style.width = '';
          tabContentEl.style.height = '';
          tabContentEl.classList.remove('is-change-active');
          changeFlag = false;
        });
        items.forEach(item => {
          item.addEventListener('transitionend', () => {
            if(item.classList.contains('is-leave-active')) {
              item.classList.remove('is-enter', 'is-leave-active', 'is-leave-to');
            }
            if(item.classList.contains('is-enter-active')) {
              item.classList.remove('is-enter-active', 'is-enter-to');
            }
          });
        });
      }
    }());
    
  • URL: /components/raw/tab/tab.js
  • Filesystem Path: src\components\04-tab\tab.js
  • Size: 2.5 KB