Flexbox 實作


預期結果

每一塊Panel為直向排列,由左往右。Panel中共有三段文字,點擊後會各自從上下彈入!


功能拆解

  • flexbox

Flexbox

講師的另一套flexbox課程

排版目前的大宗屬Flex莫屬,像是box model的進階版,有外容器和內元件之分。

CSS Flexible Box Layout is a module of CSS that defines a CSS box model optimized for user interface design, and the layout of items in one dimension.

摘自MDN Web Docs

簡單來說:

利用display屬性,將父元素設定成flex or inline-flex來建立一個flex container,同時子元素會成為flex items。

  • Flex container

    • flex-direction (改變影響排列的軸線)
      • row/ row-reverse
      • column/ column-reverse
      • row為default
    • flex-wrap (超出範圍時,是否換行)
      • nowrap為default
      • wrap
    • flex-flow (flex-direction和flex-wrap縮寫)
      • ex: flex-flow: row wrap;


遙想…..以前”被搞弄昏”左右上下置中 bla bla

對齊系列 (一樣也是設定在flex container上,根據軸線方向會不同)

  • justify-content (水平方向的對齊)
    • flex-start
    • flex-end
    • center
    • space-between (左右不留白)
    • space-around( 左右會留白)
  • align-items (垂直方向的對齊)
    • flex-start
    • flex-end置底
    • center置中
    • stretch撐滿
    • baseline
  • align-content (多行版本)
    • flex-start
    • flex-end
    • center
    • space-between
    • space-around
    • stretch

以上是flex container相關屬性的設定,接下來是關於flex item的屬性

  • flex
    • flex-grow, flex-shrink, flex-basis的縮寫
    • flex-grow
      • 為item的伸展性,預設值為0,即不縮放!
      • 當還有剩餘空間時,item放大比例
    • flex-shrink
      • 為item的收縮性,預設值為1
      • 當空間不足時,item縮小比例
    • flex-basis
      • 設定item的初始長度/寬度


p.s.跟著青蛙學flexbox的遊戲 & 砲台遊戲,可以慢慢練一點感覺


回到主題….

還沒改之前練習長這樣

before

block會照預設的flow由上至下排列很正常

Step1

觀察html結構

  <div class="panels">
    <div class="panel panel1">
      <p>Hey</p>
      <p>Let's</p>
      <p>Dance</p>
    </div>
    <div class="panel panel2">
      <p>Give</p>
      <p>Take</p>
      <p>Receive</p>
    </div>
    <div class="panel panel3">
      <p>Experience</p>
      <p>It</p>
      <p>Today</p>
    </div>
    <div class="panel panel4">
      <p>Give</p>
      <p>All</p>
      <p>You can</p>
    </div>
    <div class="panel panel5">
      <p>Life</p>
      <p>In</p>
      <p>Motion</p>
    </div>
  </div>

**panels 包含5個panel,每個panel包含3個p tag **

在panels設定display:flex,因預設為row,panel變成縱向由左往右排列

在panel設定flex:1,排完item還有剩餘空間時,item的伸展比

panels apply flex


Step2

接下來目標是處理每個panel中的文字排列

panel在這個步驟成為了flex container,要控制子元素p的排列

在panel設定dispaly:flex,且設定項目水平&垂直方向都置中,justify-content:center&align-items:center以及用列方式垂直排列flex-direction:column

panel result


Step3

現在每個panel中的p tag,都集中在中間。要讓他可以充分利用剩餘的空間。

panel 下所有的p tag使用flex:1 0 auto,等於…..

  • flex-grow:1 ,item p空間有剩時,要撐滿空間,大家很公平1:1:1
  • flex-shrink:0 ,空間不足時,不縮小
  • flex-basis:auto,預設分配的空間
/* Flex Items */
    .panel > * {
      /* 省略 */
      flex: 1 0 auto;
      display: flex;
      justify-content: center;
      align-items: center;
    }

step3 result

p.s.怎麼有點混亂…..發現把panel設定justify-content:space-around好像也可以達到一樣效果(?)

other solution

發現排列對齊方式,會影響Step 4計算文字translate的%不同


Step4

處理點擊發生時,上下行文字的彈入動畫&panel的占比伸展

  .panel>*:first-child {
      transform: translateY(-100%);
    }

    .panel.open-active>*:first-child {
      transform: translateY(0);
    }

    .panel>*:last-child {
      transform: translateY(100%);
    }

    .panel.open-active>*:last-child {
      transform: translateY(0);
    }


寫一個class,供panel被打開時套用,佔比變大外也同時改變font-size

 .panel.open {
      flex: 5;
      font-size: 40px;
    }


測試套用class,預覽效果~

step4 result


Step5

進入到script的部分

又可以再細分成:

  1. 點擊圖片時,觸發panel打開的transition (add class “open”)
  2. transition結束時,再觸發文字動畫 (add class “open-active”)

注:transition end時會有兩個transition event

transition end

script result:

 const panels = document.querySelectorAll('.panel');

    function toggleOpen() {
      this.classList.toggle('open');
    }

    function toggleActive(e) {
      if (e.propertyName.includes('flex')) {
        this.classList.toggle('open-active');
      }
    }
    panels.forEach(panel => panel.addEventListener('click', toggleOpen));
    panels.forEach(panel => panel.addEventListener('transitionend', toggleActive))

參考來源

圖解:CSS Flex 屬性一點也不難