重溫 Flex 佈局

shanyuhai123發表於2019-04-03

介紹

這是關於 Flex 佈局的實踐,原想還水一點字數來介紹 Flex 相關屬性,想想還是算了,阮一峰大佬的兩篇文章推上:

  1. Flex 佈局教程:語法篇
  2. Flex 佈局教程:例項篇

如何用 CSS 來增進對 Flex 的理解:

  1. CSS 搞事技巧:checkbox+label+selector
  2. CSS 搞事技巧:hover+active

常規佈局

1. 兩欄佈局

左側定寬,右側自適應:

重溫 Flex 佈局

原始碼線上檢視

<Layout-Layout
  :background-color="bgColor"
  class="flex-layout"
>
  <div class="flex__item">left</div>
  <div class="flex__item">right</div>
</Layout-Layout>
複製程式碼
.flex-layout
  display flex
.flex__item
  &:nth-child(1)
    background-color #c04851 // 玉紅
    flex 0 0 200px
  &:nth-child(2)
    background-color #440e25 // 古銅紫
    flex 1 1 auto 
複製程式碼

原因解釋:

flex 是一個簡寫屬性,用來設定 flex-growflex-shrinkflex-basis。一般來說讓元素等高需要額外設定,而 flex 容器的存在一個預設屬性值:align-items:stretch,它會幫助你,當然也會給你帶來糟糕的體驗。

2. 三欄佈局

聖盃佈局與雙飛翼佈局都是三欄佈局,稍微介紹一下:聖盃佈局關鍵是父元素設定 padding,接著子元素通過 margin 負值以及定位;雙飛翼佈局關鍵是中間一欄多了子元素並設定 margin,然後側邊欄使用 margin 負值。而通過 flex 實現則簡單多了:

重溫 Flex 佈局

原始碼線上檢視

<Layout-Layout
  :background-color="bgColor"
  class="holy-grail"
>
  <div class="flex__content">content</div>
  <div class="flex__nav">nav</div>
  <div class="flex__side">side</div>
</Layout-Layout>
複製程式碼
.holy-grail
  display flex
  .flex__content
    flex 1 1 auto
    background-color #009999
  .flex__nav, .flex__side
    flex 0 0 120px
  .flex__nav
    order -1
    background-color #1D7373
  .flex__side
    background-color #33CCCC
複製程式碼

原因解釋:

中間一欄為核心,所以需要優先渲染,DOM 結構也就放在了前面,主要是使用 order 屬性將 nav 放置到前方。

常見佈局

除了整體結構用到這些佈局以外,對於一些元件也常常需要一些簡單的佈局。

1. 導航欄

模仿示例

重溫 Flex 佈局

實現效果圖:

重溫 Flex 佈局

原始碼線上檢視

<header class="header">
  <div class="header__avatar"></div>
  <div class="header__title">Title</div>
  <div class="header__more"></div>
</header>
複製程式碼
.header
  height 100px
  width 100%
  background-color #f9f1db // 蚌肉白
  display flex
  align-items center
  > *
    margin 0 10px
  &__avatar, &__more
    flex 0 0 80px
    height 80px
    border-radius 50%
  &__avatar
    background-color #FFAC40
  &__title
    color #FF9000
  &__more
    margin-left auto
    background-color #A65E00
複製程式碼

原因解釋:

此處主要是利用了 margin-auto 來佔據剩餘的空間,就與我們使用 margin: 0 auto 來獲取水平居中一樣。

2. 輸入框

模仿示例

重溫 Flex 佈局

實現效果圖:

重溫 Flex 佈局

原始碼線上檢視

<Layout-Layout
  align-center
  justify-center
  :background-color="bgColor"
>
  <div class="input-group">
    <span class="title" @click="message = !message" v-if="message">Message</span>
    <input type="text" class="input-text">
    <span class="icon"  @click="icon = !icon" v-if="icon"></span>
  </div>
</Layout-Layout>
複製程式碼
.input-group
  flex 0 0 75%
  height 40px
  border 2px solid red
  border-radius 4px
  display flex
  align-items center
  > *
    box-sizing border-box
  .input-text
    font-size 20px
    padding-left 10px
    height 100%
    flex 1
    outline none 
    border none 
  .icon
    flex 0 0 24px
    height 24px
    border-radius 50%
    background-color #648e93 // 晚波藍
複製程式碼

原因解釋:

這也是一個常規的三欄佈局,關鍵是 .input-textflex: 1 屬性可以佔據剩餘空間,當其餘配件不存在時也可以相應的擴張。

3. 卡片

實現效果圖:

重溫 Flex 佈局

原始碼線上檢視

<Layout-Layout
  :background-color="bgColor"
  class="flex-card"
>
  <header class="header"></header>
  <article class="article">
    <div class="article__item">1</div>
    <div class="article__item">2</div>
    <div class="article__item">3</div>
    <div class="article__item">4</div>
    <div class="article__item">5</div>
    <div class="article__item">6</div>
  </article>
  <footer class="footer"></footer>
</Layout-Layout>
複製程式碼
.flex-card
  display flex
  flex-flow column nowrap
  .header
    flex-basis 80px
    background-color #4E51D8
  .footer
    flex-basis 50px
    background-color #00B060
  .article
    flex auto 
    background-color #FF9000
    display flex
    flex-flow row wrap
    align-content center
    justify-content space-around
    &__item
      width 28%
      height 50px
      box-shadow 0 2px 4px rgba(255, 255, 255, .4), 3px 0 5px rgba(0, 0, 0, .6)
複製程式碼

原因解釋:

將主軸修改為垂直方向,headerfooter 因為 articleflex:auto 屬性被分別頂至上方和下方,可以避免 absolute 的濫用。在中間使用 align-content 區別於 align-items ,可以將多行元素視為一個整體。

4. 瀑布流

實體效果:

在編譯時會賦予 CSS 顏色,所以直接重新整理頁面是不可行的,只有重新儲存程式碼進行編譯可以變更顏色。

重溫 Flex 佈局

原始碼線上檢視

<Layout-Layout
  :background-color="bgColor"
  class="flex-flow"
>
  <div
    class="flow-column"
    v-for="m in 5"
    :key="m"
  >
    <div
      class="flow-item"
      v-for="n in 8"
      :key="n"
    ></div>
  </div>
</Layout-Layout>
複製程式碼
$flow-columns = 5; // flow 的列數
$flow-items = 8; // flow 每列的個數

// 函式
randomColor(min, max) {
  return floor(math(0, 'random') * (max - min + 1) + min);
}

randomPx(min, max) {
  return floor(math(0, 'random') * (max - min + 1) + min) px;
}

.flex-flow {
  display: flex;
  justify-content: space-between;
  overflow: hidden;

  .flow-column {
    display: flex;
    flex-direction: column;
    flex: 0 0 18.6%;

    .flow-item {
      width: 100%;
      margin: .1rem 0;
    }
  }
}

for column in (1 .. $flow-columns) {
  .flow-column:nth-child({column}) {

    for item in (1 .. $flow-items) {
      .flow-item:nth-child({item}) {
        flex: 0 0 randomPx(30, 100);
        background-color: rgb(
          randomColor(0, 255),
          randomColor(0, 255),
          randomColor(0, 255)
        );
      }
    }
  }
}
複製程式碼

原因解釋:

flex 實現瀑布流還是比較簡單的。友情提示:當使用 stylus 時還是加上標點符號吧,找編譯錯誤花了我近二十分鐘。

最後

合併多個 commit

在 push 前需要合併 commit:

git log --oneline
git rebase -i xxxxxxx
git log --oneline
git status 
git push
複製程式碼

初步地把 CSS 稍微過了一遍,下一步繼續完善那個簡陋的 簡歷 了…

參考資料

  1. VSCode 的友情提示
  2. Vuetify