iT邦幫忙

2021 iThome 鐵人賽

DAY 20
0
Modern Web

初階 Rails 工程師的養成系列 第 20

Day20. 懂Bootstrap,並讓Bootstrap帶你上天堂

工程師都有google的習慣,但是 bootstrap 的使用方式不用特別去估狗,基本的用法只要看官網的介紹就可以了。若發現自己看不懂文件,多半都是自己還沒有補足樣式相關的知識,建議相關的常識記得先補齊,也可以參考Day19的文章。

Spacing: margin & padding

Bootstrap 的空間使用方式為距離、方向、量級的排列組合

  • 內距p、外距m

  • 方向:上下左右、x軸、y軸、全方位

  • 量級:0~5, auto

基本概念可以查看Day19,而如何使用可以查看 官方

flex

我們以下列條件為前提做討論:

element.style {
  display: flex;
  flex-direction: row;
}

⭐️ 以flex-direction: row; 的前提下,水平相關的用法

<div class="d-flex justify-content-start">...</div>
<div class="d-flex justify-content-end">...</div>
<div class="d-flex justify-content-center">...</div>
<div class="d-flex justify-content-between">...</div>
<div class="d-flex justify-content-around">...</div>

⭐️ 以flex-direction: row; 的前提下,垂直相關的用法

<div class="d-flex align-items-start">...</div>
<div class="d-flex align-items-end">...</div>
<div class="d-flex align-items-center">...</div>
<div class="d-flex align-items-baseline">...</div>
<div class="d-flex align-items-stretch">...</div>

更多的 flex 用法可以參考官方

container

相信大家一定都知道 container,但大家知道 container 代表什麼意思嗎?我們來看誠品的網站,框起來的內容

https://ithelp.ithome.com.tw/upload/images/20210916/20115854J5xVLHns5u.png

container 指的是網頁的內容要被多少寬包覆,舉例來說當我們使用 <div class="container"><div>

  • 瀏覽器寬度大於等於1400px ➡️ 1320px
  • 瀏覽器寬度大於等於1200px ➡️ 1140px
  • 瀏覽器寬度大於等於992px ➡️ 960px
  • 瀏覽器寬度大於等於768px ➡️ 720px
  • 瀏覽器寬度大於等於576px ➡️ 540px
  • 瀏覽器寬度小於576px ➡️ 滿版。

以下 container 定義不一樣,但由於我們不需要做精細的響應式,會不會使用container對後端工程師來說,差別可能不大。

<div class="container-sm">100% wide until small breakpoint</div>
<div class="container-md">100% wide until medium breakpoint</div>
<div class="container-lg">100% wide until large breakpoint</div>
<div class="container-xl">100% wide until extra large breakpoint</div>
<div class="container-xxl">100% wide until extra extra large breakpoint</div>

grid

這是bootstrap的網格系統,和Day19提到的 grid 用法差不多。

<div class="container">
  <div class="row">
    <div class="col-6">
      內容
    </div>
    <div class="col-6">
      內容
    </div>
    <div class="col-6">
      內容
    </div>
    <div class="col-6">
      內容
    </div>
  </div>
</div>

想必後端的朋友們,上述的排版方式應該再熟悉這個不過。對大部分後端來說,上述的排法就是前端實力的天花板 ? 。不過讀者們知道 grid 還可以做響應式嗎?只要搭配lg, md,就可以作出響應

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>

    <!-- CSS only -->
    <!-- https://getbootstrap.com/ -->
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-12 col-lg-6 border">內容</div>
        <div class="col-12 col-lg-6 border">內容</div>
        <div class="col-12 col-lg-8 border">內容</div>
        <div class="col-12 col-lg-4 border">內容</div>
      </div>
    </div>
  </body>
</html>

關於lg, md, xl 等尺寸表可以參考下方官網的表格。

Extra small <576px Small ≥576px Medium ≥768px Large ≥992px Extra large ≥1200px
Max container width None (auto) 540px 720px 960px 1140px
Class prefix .col- .col-sm- .col-md- .col-lg- .col-xl-
# of columns 12
Gutter width 30px (15px on each side of a column)
Nestable Yes
Column ordering Yes

d-none

d-nonedisplay: none; ,但它絕對不是只有這麼簡單而已。當我們使用了這個屬性,我們可以玩很多響應式的東西,沿用上面的例子,我們來新增更多樣式

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>

    <!-- CSS only -->
    <!-- https://getbootstrap.com/ -->
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-12 col-lg-6 border">
          <div class="d-none d-lg-block">
            <a class="btn btn-primary" href="#" role="button">母訂單列表</a>
            <a class="btn btn-primary" href="#" role="button">母訂單列表</a>
          </div>

          <div class="d-lg-none">
            <a class="btn btn-primary" href="#" role="button">母湯</a>
            <a class="btn btn-primary" href="#" role="button">母湯</a>
          </div>
        </div>
        <div class="col-12 col-lg-6 border">
          <div class="d-none d-lg-block">
            <a class="btn btn btn-outline-secondary" href="#" role="button">母訂單列表</a>
            <a class="btn btn btn-outline-secondary" href="#" role="button">母訂單列表</a>
          </div>

          <div class="d-lg-none">
            <a class="btn btn btn-outline-secondary" href="#" role="button">母湯</a>
            <a class="btn btn btn-outline-secondary" href="#" role="button">母湯</a>
          </div>
        </div>
        <div class="col-12 col-lg-8 border">
          <div class="col-12 col-lg-6 border">
            <div class="d-none d-lg-block">
              <a class="btn btn btn-outline-success" href="#" role="button">母訂單列表</a>
              <a class="btn btn btn-outline-success" href="#" role="button">母訂單列表</a>
            </div>

            <div class="d-lg-none">
              <a class="btn btn btn-outline-success" href="#" role="button">母湯</a>
              <a class="btn btn btn-outline-success" href="#" role="button">母湯</a>
            </div>
          </div>
        </div>
        <div class="col-12 col-lg-4 border">
          <div class="d-none d-lg-block">
            <a class="btn btn btn-secondary" href="#" role="button">母訂單列表</a>
            <a class="btn btn btn-secondary" href="#" role="button">母訂單列表</a>
          </div>

          <div class="d-lg-none">
            <a class="btn btn btn-secondary" href="#" role="button">母湯</a>
            <a class="btn btn btn-secondary" href="#" role="button">母湯</a>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

我們可以利用d-none 搭配尺寸來去做響應式畫面,很好用 ?

table

bootstraptable 的支援相當高,光一個 table 就可以有好幾種變化型,官網就有很多用法可以參考,不過這篇想發想,如何讓table按照自己的比例分配,可以使用網格系統的col 做搭配,理由如下:

  • 由於table排列屬性不為flex,只用看得懂max-width
  • 事實上,如果table再過小尺寸時,讓它順其自然的發展也會比較好。
table
  thead  
    tr   
      th.col-2 商品品號
      th.col-4 商品名稱
      th.col-1 定價
      th.col-1 售價
      th.col-1 顏色
      th.col-1 尺寸
      th.col-1 數量
      th.col-1
.col-2 {
    flex: 0 0 16.66667%;
    max-width: 16.66667%;
}

/* 對於table來說 */
.col-2 {
    /* flex: 0 0 16.66667%; */
    max-width: 16.66667%;
}

button

在講d-none的時候已經講過了,此外官網也有專門講 button 的文章。以下為按鈕樣式的各種形式,而官網還特別介紹了顏色、屬性等一些很實用的技巧

<a class="btn btn-primary" href="#" role="button">Link</a>
<button class="btn btn-primary" type="submit">Button</button>
<input class="btn btn-primary" type="button" value="Input">
<input class="btn btn-primary" type="submit" value="Submit">
<input class="btn btn-primary" type="reset" value="Reset">

Tab

官網上的範例貼一貼,就有如上基本的頁籤樣式。曾經在前端客製化過頁籤,所以知道要打造好的頁籤不容易,但使用bootstrap就不用擔心樣式的問題

badge

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>

    <!-- CSS only -->
    <!-- https://getbootstrap.com/ -->
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
      integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <div class="container">
      <button type="button" class="btn btn-primary my-2">
        未出貨訂單 <span class="badge badge-light">4</span>
      </button>
      <button type="button" class="btn btn-primary my-2">
        刷退失敗訂單 <span class="badge badge-light">5</span>
      </button>
      <button type="button" class="btn btn-primary my-2">
        推播 <span class="badge badge-light">8</span>
      </button>
    </div>
  </body>
</html>

https://ithelp.ithome.com.tw/upload/images/20210916/20115854spCMrrLies.png

後台介面,一定碰得到顯示數字的UI畫面,此時就可以使用badge

另外button 為行內元素,所以不能用區塊的概念控制,意即為使用margin, padding, flex 等等全部都會失效。

Input group

當我們要把多個輸入框併成群組時,可以使用input group

⭐️ 舉個例子

.form-group
  label.col-md-2.control-label
    | 選擇匯出日期
  .col-md-10.col-lg-9
    .input-daterange.input-group
      input.input-md.form-control type="date" min="#{180.days.ago.to_date}" max="#{Date.today}" name="start_date" required="required" autocomplete="off"
      span.input-group-addon 到
      input.input-md.form-control type="date" max="#{Date.today}" name="end_date" required="required" autocomplete="off"

https://ithelp.ithome.com.tw/upload/images/20210913/20115854Gt0YqQ8tNE.png

⭐️ 再舉一個例子

# 開始時間、結束時間模板
def search_interval(controller: nil, form: nil)
  tag.div class: 'input-group mb-3' do
    datatable_date_tag(controller: controller, target: 'startedAt', value: Date.today - 1.year, form: form) +
      tag.div(class: 'input-group-append') { tag.label '至', class: 'input-group-text' } +
      datatable_date_tag(controller: controller, target: 'endedAt', value: Date.today + 1.day, form: form)
  end
end

⭐️ input_groupappend, prepend兩個屬性可以調用

<!-- prepend -->
<div class="input-group mb-3">
  <div class="input-group-prepend">
    <span class="input-group-text" id="basic-addon1">@</span>
  </div>
  <input type="text" class="form-control" placeholder="Username" aria-label="Username" aria-describedby="basic-addon1">
</div>

<!-- append -->
<div class="input-group mb-3">
  <input type="text" class="form-control" placeholder="Recipient's username" aria-label="Recipient's username" aria-describedby="basic-addon2">
  <div class="input-group-append">
    <span class="input-group-text" id="basic-addon2">@example.com</span>
  </div>
</div>

⭐️ 搜尋輸入框,後面append放大鏡

def datatable_search_field(options = {})
  tag.div class: 'input-group mb-2', style: 'max-width: 300px' do
    search_field_tag(options[:name], options[:placeholder], class: 'form-control', data: options[:data]) +
    tag.div(class: 'input-group-append') do 
      tag.i class: 'fas fa-search input-group-text', style: 'padding-top: 10px'
    end  
  end
end

至於如何用helper使用,會在Day22 和大家交代清楚。請大家拭目以待

其他

以下這些主題也很常被提及,讀者們當有機會從頭刻畫後台介面時,不妨可以看看

結語

Day19粗略地提到了樣式的概念;今天粗略地提及了bootstrap的使用方式。

各個公司可能會為了後台的美觀性,會購買市面上的主題,或者使用免費的sb-admin2的主題製作。總之別人寫好的東西我們善加利用,基本的樣式技巧學好,便可以更融會貫通的應用!

覺得只用兩天的篇幅就講完樣式有點太少。日後在IT鐵人賽結束以前,如果有其他要補充的內容會另外修改文章,若讀者有什麼建議的也歡迎留言在下方。

下一篇會開始講Rails 附贈的helper


上一篇
Day19. 後端工程師需要具備的前端常識
下一篇
Day21. 用 Rails helper 省去更多開發時間
系列文
初階 Rails 工程師的養成34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言