LoginSignup
1
1

【コンポーネント】コンテンツを開閉させるもっと見るボタン

Last updated at Posted at 2022-04-11

長いコンテンツを省略して表示し、ボタンを押すとすべて表示させるアノUI。

スマホでは省略表示、それ以外は全表示という実装が多いのですが、これが毎回地味に大変…:sweat:

というわけで、汎用的に利用できるコンポーネントを作成しました。

仕様

  • 表示・非表示
    • <input type="checkbox"> のチェックの有無で管理
  • 省略時のコンテンツの高さ
    • CSS変数(Custom Properties)で管理
  • スライドアニメーション
    • CSS の transitionmax-height をアニメーション
    • max-height の値は JavaScript で要素の高さを取得し、CSS変数に設定

HTML

親要素の div に設定している class="js-showMore" は JavaScript のトリガーです。
アニメーションさせない場合は不要です。

HTML
<div class="showMore js-showMore">
  <input class="showMore_trigger" id="showMore" type="checkbox">
  <label class="showMore_btn" for="showMore"></label>
  <div class="showMore_contentWrapper">
    <div class="showMore_content">
      <!-- ここにコンテンツを挿入 -->
    </div>
  </div>
</div>

Sass

アニメーションさせない場合は、73行目の --mask-height: auto; のコメントアウトを解除してください。

SCSS
.showMore {
  --mask-height: 500px;
  --mask-color: 40 42 54;
  --transition-easing: cubic-bezier(0.075, 0.82, 0.165, 1);
  --transition-duration: 0.5s;
  display: flex;
  flex-direction: column;
}
.showMore_btn {
  position: relative;
  display: block;
  order: 2;
  width: 50px;
  height: 50px;
  margin: 20px auto 0;
  font-size: 2rem;
  color: #fff;
  cursor: pointer;
  background-color: #000;
  border-radius: 50%;
  &::before,
  &::after {
    position: absolute;
    top: 50%;
    left: 50%;
    content: "";
    background-color: #fff;
    transform: translate(-50%, -50%);
  }
  &::before {
    width: 20px;
    height: 2px;
  }
  &::after {
    width: 2px;
    height: 20px;
  }
}
.showMore_contentWrapper {
  position: relative;
  order: 1;
  max-height: var(--mask-height);
  overflow: hidden;
  transition: max-height var(--transition-duration) var(--transition-easing);
  &::before {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 50px;
    content: "";
    background: linear-gradient(
      0deg,
      rgb(var(--mask-color) / 1) 0%,
      rgb(var(--mask-color) / 0) 100%
    );
  }
}
.showMore_trigger {
  // チェックボックスは常に非表示
  display: none;
  &:checked {
    // ボタンをマイナス表示
    + .showMore_btn {
      &::after {
        display: none;
      }
    }

    // コンテンツをすべて表示
    ~ .showMore_contentWrapper {
      // アニメーションさせない場合はコメント解除
      // --mask-height: auto;

      // マスク要素を非表示
      &::before {
        display: none;
      }
    }
  }
}

JavaScript

アニメーションさせない場合は JavaScript は不要です。

JS
class ShowMoreShowLessButton {
  #defaults = {
    selector: '.js-showMore',
    customPropertyName: '--mask-height'
  }

  #options
  #showMoreList
  constructor(config) {
    this.#options = { ...this.#defaults, ...config }
    this.#showMoreList = document.querySelectorAll(this.#options.selector)
    this.#init()
  }

  #init() {
    for (const el of this.#showMoreList) {
      const trigger = el.querySelector('input[type="checkbox"]')
      const contentWrapper = el.querySelector('div')
      const content = contentWrapper.querySelector('div')
      const contentHeight = content.getBoundingClientRect().height
      trigger.addEventListener('change', () => {
        if (trigger.checked) {
          contentWrapper.style.setProperty(
            this.#options.customPropertyName,
            contentHeight + 'px'
          )
        } else {
          contentWrapper.removeAttribute('style')
        }
      })
    }
  }
}
const showMoreShowLessButton = new ShowMoreShowLessButton()

DEMO

See the Pen Show More / Less Content Button by Takuya Mori (@taqumo) on CodePen.

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1