前端特效

-

如何用 CSS 做 Accordion 手風琴?不再需要用 JS 計算高度

this.web

accordion 是前端非常常見的組件,他長這個樣子 👇

點擊時候展開顯示內容,再次點擊就關閉。

因為 css height 屬性如果從 0 到 auto 是吃不到 transition 效果的,所以早期我們只能利用 JS 算出內容的高度,比如 500px,點擊時再用 js 調整 css hiehgt 為 500px,這樣才能吃到 transition 屬性的效果。

但現在可以利用 grid-template-row 來快速做到一樣的事情並且簡單很多,讓我們看看怎麼做吧!

基本 HTML & CSS

先設定基本的 HTML & CSS。

<div class="accordion">
  <h4 class="accordion__title">TITLE 1
    <div class="accordion__icons">
      <span class="accordion__icon--plus">+</span>
      <span class="accordion__icon--minus"></span>
    </div>
  </h4>
  <div class="accordion__content">
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Libero maiores obcaecati rerum repudiandae quo ratione
      deleniti facere autem! Unde in quibusdam eligendi eaque vero accusamus soluta facilis enim dicta obcaecati.</p>
  </div>
</div>

HTML 架構分為 title、icons、content 沒有很複雜就不說太多。

.accordion {
  width: 300px;
  padding: 16px;
  border-bottom: 2px solid;
}
.accordion__title {
  display: flex;
  justify-content: space-between;
  cursor: pointer;
  font-size: 2rem;
}
.accordion__icons {
  border: 3px solid;
  border-color: transparent;
  border-radius: 50%;
  width: 2rem; height: 2rem;
  display: grid; place-content: center;
  transition: 0.4s;
}
.accordion__icon--plus, .accordion__icon--minus {
  grid-area: 1/1/2/2;
  transition: 0.4s ease-in-out;
  font-size: 1.2rem;
}
.accordion__icon--minus {
  opacity: 0;
  transform: rotate(-2turn);
}

CSS 的部分,icons 的我利用 grid 以及 grid-area: 1/1/2/2 來將 icon 疊在一起。其他沒有太特別的地方。

accordion-basic-style

CSS Accordion Style

接下來是重頭戲,要來製作 Accordion 的功能了

.accordion__content {
  display: grid;
  grid-template-rows: 0fr;
  transition: .4s ease-in-out;
}

.accordion__content>* {
  overflow: hidden;
}

我們在 content 設定 display: gridgrid-template-row: 0fr,這個意思是 row 的高度為 0。

並且在 content 的子元素設定 overflow: hidden,這樣他才可以被壓縮。

當這兩件事情加在一起後,你就會發現 content 消失了!他已經被縮起來了。

accordion-content 壓縮

如果要打開,只要設定 content grid-template-row: 1fr 即可!並且他也能吃到 transition 的效果。

所以讓我們完善 CSS。

/* active */
.accordion.is-active .accordion__content {
  grid-template-rows: 1fr;
} 

.accordion.accordion.is-active .accordion__icons {
  border-color: var(--white);
}
.accordion.is-active .accordion__icon--plus {
  opacity: 0;
  transform: rotate(2turn);
}
.accordion.is-active .accordion__icon--minus {
  opacity: 1;
  transform: rotate(0turn);
}

因為 active 時,除了 content 要展開,icon 也要變化,所以我直接在 .accordion 加 .is-active 的效果讓所有子元素都能吃到。

最後,只要加一點點的 JS 就完成全部的功能了~

JS Accordion 功能

const accordionsTriggers = document.querySelectorAll('.accordion__title');

accordionsTriggers.forEach((trigger) => {
  trigger.addEventListener('click', (e) => {
    const target = trigger.closest('.accordion');
    target.classList.toggle('is-active');
  })
})

整體內容非常簡單,就是找到所有的 accordion__title 並添加事件,點擊後在父元素 .accordion 添加 is-active 即可。

到這邊就完成了!附上 codepen 當作參考~

補充

前陣子我遇到 accordion 裡面還要有 tooltip 的需求,但 tooltip 會因為 content 的子元素添加了 overflow: hidden 的關係而被截掉

如果你不希望展開時仍有 overflow: hidden 的話,可以利用 animation 來控制 overflow,算是非常實用的小技巧~

.accordion.is-active .accordion__content>* {
  animation: overflowModify .5s ease-in-out forwards;
}
@keyframes overflowModify {
  0%,
  99.9% {
    overflow: hidden;
  }

  100% {
    overflow: visible;
  }
}

這樣在 is-active 後,就不會 overflow: hidden 了~

小結

今天用 grid-template-row 來製作前端 accordion 手風琴效果,是非常常用的組件,使用率很高。

那這篇就這樣,希望能幫助到你學 CSS 的應用,下篇貼文見~!

相關系列文章