[基礎課程] Bootstrap5 教學(三):元件


本章節的 Components 元件算是資訊量很大且結構複雜的單元,但也不用特別去背,只要知道有哪些功能可以選(複製貼上大法)加以利用去點綴網頁即可。


元件 Components

Bootstrap 許多具備操作互動的大型元素組合稱呼為元件,在結構有固定的 calss 公式與多層級元素。若有動態互動將使用到 Bootstrap.js(少部分需要 popper.js 協助)。

<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>

手風琴 Accordion

為 Collapse 元件(稍後介紹)延伸過來的設計,利用屬性 data-bs-toggle="collapse" 加以組合提供新的元素組並根據資料屬性控制單切效果。

容器部分:

  • 創造父容器 (.accordion 名稱無作用可省略),可指定 #id 方便被找到。
  • 子項目完整結構為 accordion-item > .accordion-header + .accordion-collapse
  • 可添加 .accordion-flush 為無邊框效果。

.accordion-header 部分:

  • 為標題區塊之元素,可使用任何元素標籤,建議使用 h2 這類型的粗體標題效果。
  • 區塊內之互動子元素,使用 button 類型 (a:link 亦可),公式為 button.accordion-button 並指定屬性 data-bs-toggle="collapse".
  • 同上,指定屬性 data-bs-target="#id" 設定欲呼叫之區塊對象 .accordion-collapse
  • 可省略子元素 button 之親和性說明,屬性 aria-controls=* 為控制項名。
  • 可省略子元素 button 之親和性說明,屬性 aria-expanded={true|false} 為展開 (true) 或關閉 (false) 之收合狀態。

.accordion-collapse 部分:

  • 為隱藏區塊元素範圍,公式為 div.accordion-collapse collapse,其下層才是 .accordion-body
  • 預設為展開時需添加 .show
  • 需指定屬性 [data-bs-target=*] 設定父容器為何者(通常為 #id 但 .class 也有效),否則無法順利單顯切換。
  • 必須綁定 #id 提供 .accordion-header>button 找到對象。
  • 下層 .accordion-body 提供內容使用,你可以放入各種元件排版整合。
  • 可省略子元素親和性說明,隱藏區塊之屬性 aria-labelledby=*,指向元素 #id 作為該描述標題替代。
<div class="container my-5 accordion-flush" id="lokiBox">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button" data-bs-toggle="collapse" data-bs-target="#loki1">Item #1</button>
<!-- <a class="accordion-button" href="#loki1" data-bs-toggle="collapse">Item #1</a> -->
</h2>
<div id="loki1" class="accordion-collapse collapse show" data-bs-parent="#lokiBox">
<div class="accordion-body">A Lorem ipsum dolor sit amet.</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#loki2">Item #2</button>
</h2>
<div id="loki2" class="accordion-collapse collapse" data-bs-parent="#lokiBox">
<div class="accordion-body">B Lorem ipsum dolor sit amet.</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingThree">
<button class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#loki3">Item #3</button>
</h2>
<div id="loki3" class="accordion-collapse collapse" data-bs-parent="#lokiBox">
<div class="accordion-body">C Lorem ipsum dolor sit amet.</div>
</div>
</div>
</div>

警報 Alert

alert 是設計一個具有滿寬的顏色區塊提供文字訊息。公式為:

.alert /* 產生一個滿寬的警報型文字框 */
.alert-{color} /* 填上粉系的背景色,你可以反向當作背景色公式通用在其他領域上 */
color: primary, secondary, success, danger, warning, info, light, dark

Alert 元件內可包覆各種元素,部分元素推薦以使用以下公式優化外觀:

a.alert-link /* 調整文字內的連結元素之顏色與粗體 */
h1~h6.alert-heading /* 設定 color: inherit (沒有意義) */
<div class="alert alert-primary" role="alert">
A simple primary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
</div>
<div class="alert alert-success" role="alert">
<h4 class="alert-heading">Well done!</h4>
<p>Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.</p>
<hr>
<p class="mb-0">Whenever you need to, be sure to use margin utilities to keep things nice and tidy.</p>
</div>

role="alert" 屬於 html5 的語意屬性(讓網頁受辨識與無障礙),代表這是一個向使用者傳遞警報的文字區塊,非必要可以不用填寫。

動態行為

Alert 還有動態 Javascript 效果,範例提供關閉按鈕觸發元素移除 DOM 消失,需自行添加 Close Button 元件(稍後介紹)並設定一些動作:

  • alert 元素添加 .alert-dismissible 控制關閉按鈕靠右且與文字不重疊
  • alert 元素添加 .fade.show 增添動態轉場為淡出且先顯示
  • button 使用 btn-close 元件 並綁定屬性 [data-bs-dismiss=alert]
  • button 的 [aria-label=close] 為親和性應用,可省略。
<div class="alert alert-warning alert-dismissible fade show">
<strong>Holy guacamole!</strong> You should check in on some of those fields below.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>

JS 事件操作

提供 JavaScript 的 alert 物件方便操作,範例為如何去觸發 alert 關閉事件:

<div class="alert alert-warning fade show">Lorem ipsum dolor sit amet.</div>
<script>
const myNode = document.querySelector('.alert');
const loki = new bootstrap.Alert(myNode); // 建構函式

/* try it in console*/
/*
console.log(loki); //該節點之整個 alert 物件
loki.close(); //移除 DOM
loki.dispose(); //銷毀 alert 不再保留可控制
*/
</script>

另一種為 alert 的關閉事件的處理:

<div class="alert alert-warning alert-dismissible fade show" role="alert">
Lorem ipsum dolor sit amet.
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<script>
const myNode = document.querySelector('.alert')
myNode.addEventListener('closed.bs.alert', function () {
console.log("已關閉");
})
myNode.addEventListener('close.bs.alert', function () {
console.log("正在關閉");
})
</script>

標籤 Badge

標籤指 inline-block 模式的文字含圓角,可添加 bg 通用類別之背景色。

.badge /* 變成 inline-block */
.bg-{color} /* 替換底色字色 */
color: primary, secondary, success, danger, warning, info, light, dark

.badge-pill /* 框線為膠囊形狀 */
<h1>Example heading <span class="badge bg-secondary">New</span></h1>
<h2>Example heading <span class="badge bg-secondary">New</span></h2>
<h3>Example heading <span class="badge bg-secondary">New</span></h3>
<h4>Example heading <span class="badge bg-secondary">New</span></h4>
<h5>Example heading <span class="badge bg-secondary">New</span></h5>
<h6>Example heading <span class="badge bg-secondary">New</span></h6>

<button type="button" class="btn btn-primary">
Notifications <span class="badge bg-secondary">4</span>
</button>

<a href="#" class="badge bg-danger">Danger</a>
<span class="badge bg-warning text-dark">Warning</span>
<span class="badge bg-info text-dark">Info</span>
<span class="badge bg-light text-dark">Light</span>
<span class="badge bg-dark">Dark</span>

麵包屑 Breadcrumb

做為網站的站點紀錄設計,會自動在 li 之間判斷塞入 / 分隔符號。

.breadcrumb /* 規劃滿寬灰底的區域 in parent */
.breadcrumb-item /* 麵包屑的子物件 in son */
.active /*標示為灰字*/

nav[style=--bs-breadcrumb-divider: '>';] /* 自訂分隔符號或不要(空字串) */
 <nav aria-label="breadcrumb">  <!--這層主要是網頁語意用,告知為麵包屑,可省略 -->
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item"><a href="#">Library</a></li>
<li class="breadcrumb-item active" aria-current="page">Data</li>
</ol>
</nav>

<nav style="--bs-breadcrumb-divider:'★'">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item"><a href="#">Library</a></li>
<li class="breadcrumb-item active" aria-current="page">Data</li>
</ol>
</nav>

aria-current="page"為親和性輔助,亦為告知當前所在頁面。

按鈕 Buttons

拿來美化 button 標籤的外觀,也能將任何非 input:button 元素包裝成按鈕外觀,且具有 hover 編程反應。

.btn /* 外觀變化為按鈕型態,主要 */

/*選增項目*/
.btn-{color} /* 填上底色 */
color: primary, secondary, success, danger, warning, info, light, dark, link

.btn-outline-{color} /* 另一種外框填色模式,背景為摟空 */
color: primary, secondary, success, danger, warning, info, light, dark

.btn-lg /* 大按鈕 */
.btn-sm /* 小按鈕 */

[disabled] /* 取消的效果,顏色暗且沒有 hover 反應 */
.disabled /* 同上,因 a 元素不支援 disabled 屬性改用 class 賦予 */

.active /* 點選中的效果,顏色深 */

動態行為

增加點擊事件產生 .active 反應(顏色變化),你可以拿來設計在需要切換 ON/OFF 效果。

  • 添加屬性 data-bs-toggle="button" 就能進行切換效果
  • 若初始化為作用中效果,你需要先增加 .active 與親合性屬性 aria-pressed="true"
https://getbootstrap.com/docs/4.4/components/buttons/#toggle-states
<button type="button" class="btn btn-primary active" data-toggle="button" aria-pressed="true">Single toggle</button>

JS 事件操作

透過建構函式觸發按鈕切換 active 效果。

<button type="button" class="btn btn-secondary">Secondary</button>
<script>
const myNode=document.querySelector(".btn");
const loki=new bootstrap.Button(myNode);

/* try it in console*/
/*
loki.toggle(); //切換 active 狀態
loki.dispose(); //銷毀不再保留可控制
*/
</script>

按鈕群組 Button Grounp

透過一個父容器將多個按鈕組合起來,使得畫面為一個排列的按鈕群組。

  • 父容器為 div.btn-grounp,以 d-inline-flex 設計
  • 放入任何已套入各種 btn 元件或樣式的子元素,例如 button.btn, a.btn, input.btn 皆可。
.btn-group /* 將子元素的 btn 項目都群組化 */
.btn-group-lg /*將群組按鈕放大*/
.btn-group-sm /*將群組按鈕縮小*/

.btn-group-vertical /*將群組按鈕以縱向呈現,透過 flex-direction-column 實現*/
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-secondary">Left</button>
<a href="#" class="btn btn-warning">Link</a>
<button type="button" class="btn btn-secondary">Right</button>
</div>

屬性role, aria-label, aria-labelledby都是親和性與語意的輔助設計。

整合 checkbox 與 radio 按鈕(參考表單之單元)的效果。

<div class="btn-group">
<input type="checkbox" class="btn-check" id="check1" autocomplete="off">
<label class="btn btn-outline-primary" for="check1">Checkbox 1</label>

<input type="checkbox" class="btn-check" id="check2" autocomplete="off">
<label class="btn btn-outline-primary" for="check2">Checkbox 2</label>

<input type="checkbox" class="btn-check" id="check3" autocomplete="off">
<label class="btn btn-outline-primary" for="check3">Checkbox 3</label>
</div>

<div class="btn-group">
<input type="radio" class="btn-check" name="demo" id="radio1" autocomplete="off" checked>
<label class="btn btn-outline-primary" for="radio1">Radio 1</label>

<input type="radio" class="btn-check" name="demo" id="radio2" autocomplete="off">
<label class="btn btn-outline-primary" for="radio2">Radio 2</label>

<input type="radio" class="btn-check" name="demo" id="radio3" autocomplete="off">
<label class="btn btn-outline-primary" for="radio3">Radio 3</label>
</div>

工具列排列用途,可再多一個容器 div.btn-toolbar 來包覆多個 div.btn-group,可多利用 flex 特性指定排版。

<div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
<div class="btn-group me-2" role="group" aria-label="First group">
<button type="button" class="btn btn-primary">1</button>
<button type="button" class="btn btn-primary">2</button>
<button type="button" class="btn btn-primary">3</button>
<button type="button" class="btn btn-primary">4</button>
</div>
<div class="btn-group me-2" role="group" aria-label="Second group">
<button type="button" class="btn btn-secondary">5</button>
<button type="button" class="btn btn-secondary">6</button>
<button type="button" class="btn btn-secondary">7</button>
</div>
</div>

若想放入 dropdown 元件(稍後介紹) 會因為該元件有使用到 btn 效果無法順利被大容器包覆,解決方式為再使用一個 .btn-group 給 dropdown 當容器。

<div class="btn-group" role="group" aria-label="Button group with nested dropdown">
<button type="button" class="btn btn-primary">1</button>
<button type="button" class="btn btn-primary">2</button>

<div class="btn-group">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
</ul>
</div>

<div class="lokiDropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown">Fail Dropdown</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
</ul>
</div>
</div>

卡片 Card

卡片是一個廣泛使用的常態容器,擁有良好的適應性到任何用途上,並可與其他元件或通用類別組合。

  • 使用 .card 為主容器,內含 .card-body 跟其他(非必要)像是 .card-head, .card-footer 或任何元素。
  • 容器最好持有固定寬度,否則 blcok 特性形成滿寬。
  • 主容器與三個公式子元素之區域:
    .card /*宣告在一個父元素上,能產生一個含框線之卡片容器*/

    .card-body /*為主區域,必要*/
    .card-header /*頁首區域,灰底*/
    .card-footer /*頁尾區域,灰底*/
  • 不論是 body, header, footer 哪個子區域,任何元素都能放入,同時提供一些適合這些元素使用的公式:
    .card-title /*標題美化,適合 h1~h6*/
    .card-subtitle /*次標題美化*/
    .card-link /*連結美化*/
    .card-text /*文字美化,消除 p 的 margin*/
    <div class="card w-25">
    <div class="card-body">
    <h5 class="card-title">Card title</h5>
    <h6 class="card-subtitle text-muted">Card subtitle</h6>
    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
    <a href="#" class="card-link">Card link</a>
    <a href="#" class="card-link">Another link</a>
    </div>
    </div>

圖片整合

card-img 為卡片專用圖片元素,與 header,body,footer 同層級。

/* 圖片元素跟子項目並排 */
img.card-img-top /*修正圖片上方圓角,通常在 .card 容器內第一組元素*/
img.card-img-bottom /*修正圖片下方圓角,通常在 .card 容器內最後組元素*/

img.card-img /*修正圖片四邊皆為圓角*/
div.card-img-overlay /* 是對內容(不是設定在圖片上)設定,透過 position: absolute 產生浮力涵蓋整個 card 版面,讓圖片位於後面 */

card 內部透過 row 跟 col 觀念整合,你可以玩出圖片區域在左,文字在右的垂直效果。

<div class="container my-5">
<div class="row row-cols-3">
<div class="col mb-3">
<div class="card">
<img src="https://fakeimg.pl/400x300" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card Img Top</h5>
</div>
</div>
</div>
<div class="col mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title">Card Img Bottom</h5>
</div>
<img src="https://fakeimg.pl/400x300" class="card-img-bottom">
</div>
</div>
<div class="col mb-3">
<div class="card">
<img src="https://fakeimg.pl/400x300" class="card-img">
<div class="card-img-overlay">
<h5 class="card-title">Card Img Overlay</h5>
</div>
</div>
</div>
<div class="col mb-3">
<div class="card">
<div class="row g-0">
<div class="col-4">
<img src="https://fakeimg.pl/400x400" class="w-100">
</div>
<div class="col-8">
<div class="card-body">
<h5 class="card-title">Row Col Image</h5>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

其他整合技巧

  • 如果只使用 .card 當容器而不使用任何公式下的子元素,可充當為圓角邊框容器之應用。
    <div class="card" style="width: 18rem;">
    <p class="p-3 m-0">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Possimus, nobis.</p>
    </div>
  • 在 .card 位置使用文字之通用類別,例如 .text-{center|right} 因繼承與 block 特性可做文字對齊。
  • 將 Navs 元件(稍後介紹)放入至 .card-header 內,只要 ul.nav+navtabs 處多添加 .card-header-tabs 即可融合一起。另一種效果則是添加 .card-header-pills
  • 在 .card 位置使用文字、背景色、邊框之通用類別,例如 .bg-{color|transparent}, .text-{color}, .border-{color} 能輕鬆玩色。

排版方式

多張卡片的排列方式,這裡提供三種作法,分別是 Card Group、Grid、Masonry 三種好看方式。

Card Group

使用容器 div.card-group 將多筆 .card 元素組進行一排之組合。其原理為 flex 特性將所有高度拉齊(膨脹 card-body,card-header 與 card-footer 保持水平齊高)。

<div class="card-group container mt-5">
<div class="card">
<img src="https://fakeimg.pl/400x400" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content.
This content is a little bit longer.</p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
</div>
<div class="card">
<img src="https://fakeimg.pl/400x400" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This card has supporting text below as a natural lead-in to additional content.</p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
</div>
<div class="card">
<img src="https://fakeimg.pl/400x400" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content.
This card has even longer content than the first to show that equal height action.</p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
</div>
</div>

Grid

透過熟悉的 Grid (row>col) 來完成排版設計,如果需要控制欄位數可多利用 row 的 .row-cols-* 屬性與該響應斷點。若需要 card 同高可自行添加 h-100

<div class="container mt-5">
<div class="row row-cols-1 row-cols-md-3 g-4">
<div class="col">
<div class="card h-100">
<img src="https://fakeimg.pl/300x300" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content. This content is a little bit longer.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<img src="https://fakeimg.pl/300x300" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a short card.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<img src="https://fakeimg.pl/300x300" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<img src="https://fakeimg.pl/300x300" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content. This content is a little bit longer.</p>
</div>
</div>
</div>
</div>
</div>

Masonry

瀑布流效果設計,原先在舊版本 v4 上有提供但不支援響應式處理。因此此版本開始官方建議使用第三方套件來協助設計 card 排版。使用前先宣告 Masonry 插件,排列數同樣使用 Grid 方式設計並對 .row 添加屬性 data-masonry='{"percentPosition": true } 或透過第三官方教學使用 JS 建構式觸發。

<div class="container mt-5">
<!-- <div class="row row-cols-1 row-cols-md-4 g-4" data-masonry="{&quot;percentPosition&quot;: true }"> -->
<div class="row row-cols-1 row-cols-md-4 g-4">
<div class="col">
<div class="card">
<img src="https://fakeimg.pl/300x300" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content. This content is a little bit longer.</p>
</div>
</div>
</div>
<div class="col">
<div class="card">
<img src="https://fakeimg.pl/300x200" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a short card.</p>
</div>
</div>
</div>
<div class="col">
<div class="card">
<img src="https://fakeimg.pl/300x100" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content.</p>
</div>
</div>
</div>
<div class="col">
<div class="card">
<img src="https://fakeimg.pl/300x400" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content. This content is a little bit longer.</p>
</div>
</div>
</div>
<div class="col">
<div class="card">
<img src="https://fakeimg.pl/300x300" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content. This content is a little bit longer.</p>
</div>
</div>
</div>
<div class="col">
<div class="card">
<img src="https://fakeimg.pl/300x200" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content. This content is a little bit longer.</p>
</div>
</div>
</div>
<div class="col">
<div class="card">
<img src="https://fakeimg.pl/300x100" class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional
content. This content is a little bit longer.</p>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/masonry-layout@4.2.2/dist/masonry.pkgd.min.js"></script>
<script>
new Masonry('.row', { percentPosition: true });
</script>

輪播常用於網站作為主區廣告幻燈片輪播切換,Boostrap 會使用到 CSS 3D 轉場與 JS 控制替換。基本呈現的注意以下狀況:

  • 預設情況下是 5 秒轉場以及 focus(滑鼠懸停)時會暫停轉場動作。
  • 一定要對子項目 .carousel-item 的某設定一筆 .active 否則找不到對象進行初始化呈現,導致整個呈現失敗。
  • 輪播的是整個 div.carousel-item 元素而不是圖檔,理所當然輪播也能對文字有效。
  • img 本身最好是適應寬度為 w-100 使得與父 div 同寬,否則圖片會顯示不完整 (overflow) 導致轉場會出現問題。
  • 屬性 data-bs-ride="carousel" 做為提供 Bootstrap.js 進行初始第一次進行轉場之行為,若省略將無法初始自動轉場(若透過手動觸發仍可繼續轉場)。
<div class="container w-50">
<!-- 這裡圖片因為沒有 w-100 導致最後一張圖片左移退場時還看的到產生了錯誤視覺感 -->
<div class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://picsum.photos/1920/300/?random=1">
</div>
<div class="carousel-item">
<img src="https://picsum.photos/1920/300/?random=2">
</div>
</div>
</div>
<hr>
<div class="carousel slide carousel-fade" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://picsum.photos/1920/300/?random=1" class="w-100">
<h1>111</h1>
</div>
<div class="carousel-item">
<img src="https://picsum.photos/1920/300/?random=2" class="w-100">
<h1>222</h1>
</div>
</div>
</div>
</div>

添加控制項

div.carousel.slide 的裡面添加固定兩組 a:link 的規格語法。

  • 父容器需要綁定 id 才能被導覽鍵的 a[href] 找到對象。
  • 屬性 [data-bs-slide="{prev|next}"] 提供 Bootstrap.js 進行觸發行為,不可省。
  • 屬性 [aria-hidden=true] 為親和性隱藏此閱讀,可省略。
  • 屬性 [role="button"] 為語意此為按鈕功能,可省略。
  • .sr-only 提供視障軟體閱讀,可省略。
<div class="container w-50">
<!-- 主容器 -->
<div id="lokiSlider" class="carousel slide" data-bs-ride="carousel">
<!-- 幻燈片區 -->
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://picsum.photos/1920/720/?random=1" class="w-100">
</div>
<div class="carousel-item">
<img src="https://picsum.photos/1920/720/?random=2" class="w-100">
</div>
</div>
<!-- 控制項 -->
<a class="carousel-control-prev" href="#lokiSlider" data-bs-slide="prev">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#lokiSlider" data-bs-slide="next">
<span class="carousel-control-next-icon"></span>
</a>
</div>
</div>

添加導覽列

在主容器裡面添加固定的 ol.carousel-indicators>li 的規格語法。

  • 父容器需要綁定 id 才能被 li 對象的 [data-target=*] 所對應控制(因為沒有 [href] 可改用這個屬性當錨點)。
  • 屬性 li[data-slide-to=*] 告知導覽到第幾項目,最小值為 0。
  • 初始狀態下,建議設定 active 顯示中的元素,其對應的 li 項目也該是 active,目的是做效果對應。
<div class="container w-50">
<!-- 主容器 -->
<div id="lokiSlider" class="carousel slide" data-bs-ride="carousel">
<!-- 幻燈片區 -->
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://picsum.photos/1920/720/?random=1" class="w-100">
</div>
<div class="carousel-item">
<img src="https://picsum.photos/1920/720/?random=2" class="w-100">
</div>
</div>
<!-- 控制項 -->
<a class="carousel-control-prev" href="#lokiSlider" data-bs-slide="prev">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#lokiSlider" data-bs-slide="next">
<span class="carousel-control-next-icon"></span>
</a>
<!-- 導覽列 -->
<ol class="carousel-indicators">
<li data-bs-target="#lokiSlider" data-bs-slide-to="0" class="active"></li>
<li data-bs-target="#lokiSlider" data-bs-slide-to="1"></li>
</ol>
</div>
</div>

添加字幕(圖片上層區)

  • 在幻燈片區添加 div.carousel-caption,該元素會浮貼在兄弟 img 之上層。
  • 如果不希望出現在手機模式上,可以添加 .d-none.d-md-block,這是因為手機可能沒空間可以塞這些字。
<div class="container w-50">
<!-- 主容器 -->
<div id="lokiSlider" class="carousel slide" data-bs-ride="carousel">
<!-- 幻燈片區 -->
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://picsum.photos/1920/720/?random=1" class="w-100">
<!-- 字幕 -->
<div class="carousel-caption d-none d-md-block">
<h5>First slide label</h5>
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
</div>
</div>
<div class="carousel-item">
<img src="https://picsum.photos/1920/720/?random=2" class="w-100">
<!-- 字幕 -->
<div class="carousel-caption d-none d-md-block">
<h5>Second slide label</h5>
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
</div>
</div>
</div>
<!-- 控制項 -->
<a class="carousel-control-prev" href="#lokiSlider" data-bs-slide="prev">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#lokiSlider" data-bs-slide="next">
<span class="carousel-control-next-icon"></span>
</a>
<!-- 導覽列 -->
<ol class="carousel-indicators">
<li data-bs-target="#lokiSlider" data-bs-slide-to="0" class="active"></li>
<li data-bs-target="#lokiSlider" data-bs-slide-to="1"></li>
</ol>
</div>
</div>

如果試著改放一組在上層元素之 div.carousel.slide,那麼他會永遠停留在主輪播區上不受輪播控制。

<div class="container w-50">
<!-- 主容器 -->
<div id="lokiSlider" class="carousel slide" data-bs-ride="carousel">
<!-- 幻燈片區 -->
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://picsum.photos/1920/720/?random=1" class="w-100">
</div>
<div class="carousel-item">
<img src="https://picsum.photos/1920/720/?random=2" class="w-100">
</div>
</div>
<!-- 控制項 -->
<a class="carousel-control-prev" href="#lokiSlider" data-bs-slide="prev">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#lokiSlider" data-bs-slide="next">
<span class="carousel-control-next-icon"></span>
</a>
<!-- 導覽列 -->
<ol class="carousel-indicators">
<li data-bs-target="#lokiSlider" data-bs-slide-to="0" class="active"></li>
<li data-bs-target="#lokiSlider" data-bs-slide-to="1"></li>
</ol>
<!-- 永久的字幕 -->
<div class="carousel-caption d-none d-md-block">
<h5>Always slide label</h5>
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
</div>
</div>
</div>

進階思考

善用你的 CSS 知識將輪播改為全版面(圖片皆為 1920*1080)。高度不變而調整寬度(響應式)時,圖片不變化尺寸自動保持水平置中進行多於裁切。

  • img 如果比容器小,當然只要利用 text-center 或 mx-auto 就能置中,結案?!
  • 但輪播圖片幾乎都超出或塞滿容器,前述對齊當然無法利用來解決。(mx-auto 本身填補時只有 0)
  • img 除非是 background 可以控制中心點,否則需要去計算 margin 反推多少,使定位點往容器外去推。

方案如下:

  1. 高度鎖定 vh-100 在 .carousel-item 容器上,img 也能繼承到,兩者都有固定高度為 100vh,圖片所綁定的 w-100 可取消。
  2. 將圖片的空間放大,利用 left 跟 right 負值的方式 (position-absolute),使這張圖片的內容左右位置比容器 left 跟 right 還遠大,圖片所綁定的 d-block 可取消 (absolute 已持有)。
  3. 再搭配 margin auto 填滿,使得圖片剛好致中到看的到的容器範圍內。這樣容器的寬度不會影響圖片的定位,兩者是分開的定位觀念。
  4. 轉場會卡卡的,是因為圖片太大的所以視覺上有問題,試著對。carousel-item 的 transition 秒數放面觀察。
  5. 我們對容器指定 overflow-hidden 使得圖片超過容器的部分看不到,這樣跑輪播的時候只有容器範圍被看見。
    <div id="mycontrol" class="carousel slide" data-bs-ride="carousel">
    <div class="carousel-inner">
    <div class="carousel-item active vh-100 overflow-hidden">
    <img src="https://picsum.photos/1920/1080/?random=1" style="left:-9999px;right:-9999px"
    class="mx-auto position-absolute" />
    </div>
    <div class="carousel-item vh-100 overflow-hidden">
    <img src="https://picsum.photos/1920/1080/?random=2" style="left:-9999px;right:-9999px"
    class="mx-auto position-absolute" />
    </div>
    </div>

    <a class="carousel-control-prev" href="#mycontrol" data-bs-slide="prev">
    <span class="carousel-control-prev-icon"></span>
    </a>
    <a class="carousel-control-next" href="#mycontrol" data-bs-slide="next">
    <span class="carousel-control-next-icon"></span>
    </a>

    <ol class="carousel-indicators">
    <li data-bs-target="#mycontrol" data-bs-slide-to="0" class="active"></li>
    <li data-bs-target="#mycontrol" data-bs-slide-to="1"></li>
    </ol>

    <div class="carousel-caption d-none d-sm-block">
    <h1>hello world</h1>
    <p>nice to meet you</p>
    </div>
    </div>

控制參數

  • 淡入淡出轉場效果,對大容器添加 .carousel-fade 能更改為 fade 轉場。
  • 對主容器 .carousel 添加 .carousel-dark 能適應淺底深字的配色。

透過 data 屬性控制

不會 JavaScript 的情況下,可直接透過 HTML 資料屬性來控制參數。

/* 停留秒數(毫秒) */
div.carousel-item[data-bs-interval="value"] /* 單項 */
div.carousel[data-bs-interval="value"] /* 全部 */
value=5000(default), any number, false(持續停留)

/* 透過鍵盤方向鍵控制 */
div.carousel[data-bs-keyboard="value"]
value=true(default), false

/* 觸發暫停播放:電腦滑鼠移入移出或手持觸碰時 */
div.carousel[data-bs-pause="value"]
value=hover(default), false(不暫停)

/* 點擊替換 */
a.carousel-control-prev[data-bs-slide="value"]
a.carousel-control-next[data-bs-slide="value"]
value=false(無動作),prev(往上張),next(往下張)

/* 重複循環播放 */
div.carousel[data-wrap="value"]
value=true(default), false

/* 觸控拖曳控制 */
div.carousel[data-touch="value"]
value=true(default), false

/* 自動播放 */
div.carousel[data-bs-ride="value"]
value=false(default), carousel

JS 事件操作

以自動播放舉例來說,透過偵測 [data-bs-ride="carousel"] 存在時作用,若不寫此屬性可自己按下任何 prev 或 next 來開始自動播放。或者透過 JS 的官方建構式來啟用。

const myNode = document.querySelector('.carousel');
const loki = new bootstrap.Carousel(myNode); // 建構式
loki.cycle(); // 開始循環

初始參數

換言之,透過該建構式能夠控制所有參數(同對應前面 HTML 資料屬性之名稱)。

const myNode = document.querySelector('.carousel');
const loki = new bootstrap.Carousel(myNode, {
interval: 500,
keyboard: true,
pause: "hover",
slide: false,
touch: true,
wrap: true
}); // 建構式
loki.cycle(); // 開始循環

可用函式動作

除了 cycle() 作為開始播放,還有一些函式提供使用。

const myNode = document.querySelector('.carousel');
const loki = new bootstrap.Carousel();

loki.cycle(); //由左至右循環播放
loki.pause(); //將物件的循環從輪播中停止。
loki.prev(); //將輪播指向前一個物件。 在前一個物件顯示前回傳給調用者 (e.g., 在 slid.bs.carousel 事件發生之前).
loki.next(); //將輪播指向下一個物件。 在後一個物件顯示前回傳給調用者 (e.g., 在 slid.bs.carousel 事件發生之前).
loki.nextWhenVisible(); //如果頁面或是其父層不可見,就停止將輪播循環到下一個。在目標項目顯示前回傳給調用者
loki.to(1); //將輪播指向特定的索引。(與陣列相同,從 0 開始)
loki.dispose(); //銷毀一個元素的輪播。 (移除 DOM 元素上儲存的資料)

const lokiInstance=new bootstrap.Carousel.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

輪播發生時可提供一些回應處理,並提供一些事件屬性:

const myNode = document.querySelector('.carousel');
myNode.addEventListener('slide.bs.carousel', function (e) {
console.log("正在轉場", e);
});
myNode.addEventListener('slid.bs.carousel', function (e) {
console.log("已轉場完畢", {
"方向": e.direction,
"元素對象": e.relatedTarget,
"當前索引": e.from,
"下個索引": e.to
});
});

關閉按鈕 Close Button

將 button 元素外觀調整為關閉按鈕使用,添加 .btn-close 即可。

button.btn-close /* 基本公式*/
button[disabled].btn-close /* 禁用效果 */
.btn-close-white /* 額外添加,適合深色背景使用*/

摺疊 Collapse

方式為隱藏區塊對象,透過觸發按鈕 button (a:link 亦可) 綁定屬性 data-bs-toggle="collapse" 呼叫區塊對象動畫顯示。

  • 任何觸發按鈕上需指定 [data-toggle="collapse"] 並套入 Bootstrap.js。
  • 其中如果是 a:link 只要 [href=目標] 即可,如果是其他標籤則需要 [data-target=目標] 屬性。
  • 目標可以寫 id 或 class,且指定公式 .collapse
  • 如果要控制多個的折疊對象,則利用對象持有共同之 class 名稱來指定。
  • 屬性 aria-controls 為親和性之意,為控制對象為何,可省略。
  • 屬性 aria-expanded=”false” 為親和性之意,表示目前是關閉收起來 (false) 狀態,可省略。
  • 屬性 role=”button” 為指定用途為按鈕,可省略。
<div class="container-fluid">
<p>
<a class="btn btn-primary" data-bs-toggle="collapse" href="#Content">Touch Me</a>
<button class="btn btn-primary" data-bs-toggle="collapse" data-bs-target="#Content" type="button">TouchMe</button>
</p>
<div class="collapse" id="Content">
<div class="card card-body">Lorem ipsum dolor sit amet.</div>
</div>
<!-- 1by1 -->
<hr>
<!-- 1byn -->
<p>
<a class="btn btn-primary" data-bs-toggle="collapse" href="#ContentA">ContentA</a>
<button class="btn btn-primary" type="button" data-bs-toggle="collapse"
data-bs-target="#ContentB">ContentB</button>
<button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target=".contentAB">ContentABA+B</button>
</p>
<div class="row">
<div class="col">
<div class="collapse contentAB" id="ContentA">
<div class="card card-body">A</div>
</div>
</div>
<div class="col">
<div class="collapse contentAB" id="ContentB">
<div class="card card-body">B</div>
</div>
</div>
</div>
</div>
  • 目標對象的靜態公式為 .collapse 收起(預設)與 .collapse.show 展開。
  • 目標對象的動態轉場過程時使用公式為 .collapsing

JS 事件操作

透過以下 JS 的 Bootstrap 建構式來啟用互動(縮展)效果。

document.querySelectorAll('.collapse').forEach(function(Nod){
new bootstrap.Collapse(Nod);
});

透過 data 屬性控制

不會 JavaScript 的情況下,可直接透過 HTML 資料屬性來控制參數。

/* 當切至 show 時,指定之父容器內所有的。collapse 除了自己進行收疊。*/
div[data-bs-parent="false"].collapse
/* 進行操作:切換可折疊元素*/
button[data-bs-toggle="collapse"]

可用函式動作

一些函式提供使用。包含了可規劃初始參數來控制該元素是顯示還是隱藏。或者透過函式來進行操作:

const myNode = document.querySelector('.collapse');

// 切換縮展的2種方法

/* method 1*/
const loki = new bootstrap.Collapse(myNode, {
toggle: true
});

/* method 2*/
const loki = new bootstrap.Collapse(myNode);
loki.toggle();

另外還有很多參數或函式可使用

loki.show() /*顯示*/
loki.hide() /*收起*/
loki.dispose() /*銷毀*/

const lokiInstance=new bootstrap.Carousel.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

可提供一些回應處理,並提供一些事件屬性:

const myNode = document.querySelector('.collapse');
myNode.addEventListener('show.bs.collapse', function (e) {
console.log("顯示中", e);
});
myNode.addEventListener('shown.bs.collapse', function (e) {
console.log("已顯示", e);
});
myNode.addEventListener('hide.bs.collapse', function (e) {
console.log("隱藏中", e);
});
myNode.addEventListener('hidden.bs.collapse', function (e) {
console.log("已隱藏", e);
});

下拉選單 Dropdowns

下拉選單是指隱藏一個 DIV 容器跟互動按鈕的組合,並透過按鈕觸發顯示。Bootstrap 使用第三方插件 popper.js 進行處理,因此你必須宣告此插件才能使用下拉選單的動態事件。

  • 主容器公式 .dropdown 目的確保為 position-relative 狀態。
  • 透過按鈕(可以是 button 或 a:link 但建議使用 .btn 外觀)上的屬性 data-bs-toggle="dropdown" 進行觸發事件,會對同層位置的 ul.dropdown-menu 控制顯現。
  • 按鈕加入 .dropdown-toggle 會透過 ::after 來呈現一個三角符號。
  • 可套入色系 btn-{color} 點綴。
  • ul.dropdown-menu>li 元素內,可以包 a.dropdown-item (button 亦可)做連結,也能
  • 親和性 aria-haspopup="true" , aria-expanded="false" , aria-labelledby 可省略。
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown">Dropdown button</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>

可以使用容器 .btn-group 包覆兩組 button:

  • 前者為基本文字按鈕,可添加文字。
  • 後者為空字串(不添加文字)的互動按鈕,除了原先的 div[data-bs-toggle="dropdown"].dropdown-toggle,建議增加 dropdown-toggle-split 使兩顆按鈕間格靠近。
  • .btn-group 可以拿來取代 .dropdown ,反正都有 relative 效果,有沒有組合其實沒差。
<div class="btn-group">
<button type="button" class="btn btn-danger">Action</button>
<button type="button" class="btn btn-danger dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown">
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>

整體外觀調整

  • 可利用 .btn-lg , .btn-sm 這類的按鈕元件的公式組合下去,設計不同尺寸。
  • ul.dropdown-menu 部分可更改深色底,再添加 .dropdown-menu-dark 即可。
  • 更改箭頭方向方式,對主容器 .btn-group.dropdown 處添加 .dropup , .dropstart, .dropend
  • a.dropdown-item 可添加 .active.disabled 來做為特殊示意。
  • 選單列表的向右對齊(至按鈕)方式,對 ul.dropdown-menu 添加 .dropdown-menu-end
  • 同上,可使用響應斷點 .dropdown-menu-{breakpoint}-{start|end} ,但因為 popper.js 影響需要先對按鈕 button.dropdown-toggle 添加屬性 [data-bs-display="static"] 改為靜態定位。
  • 選單列表 li 項目可放入各種元素(提供適合的外觀公式)或元件。
    <div class="dropdown">
    <a class="btn btn-secondary dropdown-toggle" href="#" data-bs-toggle="dropdown">Dropdown link</a>
    <ul class="dropdown-menu">
    <li><button class="dropdown-item" type="button">按鈕</button></li>
    <li><a class="dropdown-item" href="#">連結</a></li>
    <li><span class="dropdown-item-text">文字</span></li>
    <li><h1 class="dropdown-header">表頭</h1></li>
    <li><hr class="dropdown-divider"><!--分割線--></li>
    <p class="p-3">
    一般文字 Lorem ipsum dolor sit amet consectetur adipisicing elit. Alias, quaerat.
    </p>
    <form class="p-3">
    <div class="mb-3">
    <label for="form1" class="form-label">Email address</label>
    <input type="email" class="form-control" id="form1">
    </div>
    <div class="mb-3">
    <label for="form2" class="form-label">Password</label>
    <input type="password" class="form-control" id="form2">
    </div>
    <button type="submit" class="btn btn-primary">Sign in</button>
    </form>
    </ul>
    </div>
  • menu 區域起始定位自訂,可對 button 添加屬性舉例 button[data-bs-offset="10,20"] 代表 x=10,y=20 偏移。
  • 同上,或改添加屬性 button[data-reference="{parent|toggle}"],則直接對齊 parent 父容器 ( .btn-group ),或對齊 toggle 後元素 ( .data-toggle )。

JS 事件操作

互動事件為透過偵測 button[data-bs-toggle="dropdown"] 編寫點擊事件操作 .dropdown-menu.show 來切換隱藏。從官方手冊中此屬性不可省略,但你可以透過 JS 來操作事件。建構式使用方法:

const myNode = document.querySelector('.dropdown-toggle');
const loki = new bootstrap.Dropdown(myNode); // 建構式

透過 data 自訂屬性

不會 JavaScript 的情況下,可直接透過 HTML 資料屬性來控制參數。於 .dropdown-toggle 位置添加屬性 [data-bs-*],其中*的參數與用途如下:

{
flip: true, // boolean, 是否允許選單列表重疊至其他元素之上,細節參考 popper.js 手冊
boundary: "clippingParents", //選單列表的 overflow 參考邊界,細節參考 popper.js 手冊
reference: "toggle", //選單列表的對齊參考初始,可選 {toggle|parent}
display: "dynamic", // 使用動態定位 dynamic 或 靜態 static
popperConfig: null, // popper.js 額外參數
toggle: "dropdown",
offset: 0, // 定位點值
}

可用函式動作

const myNode = document.querySelector('.dropdown-toggle');
const loki = new bootstrap.Dropdown(myNode); // 建構式

loki.toggle(); // 選單列表切換
loki.show(); // 選單列表顯示
loki.hide(); // 選單列表隱藏
loki.update(); //重新偵測定位值
loki.dispose(); //銷毀

const lokiInstance=new bootstrap.Dropdown.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

const myNode = document.querySelector('.dropdown'); // 這裡需要指到大容器,而不是按鈕或選單

myNode.addEventListener('show.bs.dropdown', function (e) {
console.log("顯示中", e);
});
myNode.addEventListener('shown.bs.dropdown', function (e) {
console.log("已顯示", e);
});
myNode.addEventListener('hide.bs.dropdown', function (e) {
console.log("隱藏中", e);
});
myNode.addEventListener('hidden.bs.dropdown', function (e) {
console.log("已隱藏", e);
});

列表群組 List Group

呈現一種垂直或水平之連續排列的清單群組,可以是基礎型 ul>li 或是互動型 div>{a|btn},重新設計為提供邊框與組合圓角效果。

  • 父元素使用 ul.list-group ,子元素使用 li.list-group-item
  • 除了 ul>li 也能適用於 div>a|button 的元素組合。
  • 子元素支援 .active.disabled 作用效果 (button 可用 [disabled] 來替代)。
  • 使用 a 當子元素可添加 .list-group-item-action 加入 hover 特效。
<ul class="list-group">
<li class="list-group-item">Cras justo odio</li>
<li class="list-group-item active">Dapibus ac facilisis in</li>
<li class="list-group-item">Morbi leo risus</li>
</ul>
<div class="list-group">
<a href="#" class="list-group-item list-group-item-action active">Cras justo odio</a>
<a href="#" class="list-group-item list-group-item-action">Dapibus ac facilisis in</a>
<a href="#" class="list-group-item list-group-item-action">Morbi leo risus</a>
<a href="#" class="list-group-item list-group-item-action">Porta ac consectetur ac</a>
<a href="#" class="list-group-item list-group-item-action disabled">Vestibulum at eros</a>
</div>

外觀與元件整合

  • 父容器添加 .list-group-flush 可消除外框線。
  • 父容器添加 .list-group-horizontal 可調整為水平排列,也支援改用響應斷點 .list-group-horizontal-{breakpoint}}
  • 由於是 flex 原理,可對每個子元素添加 flex-fill 來膨脹填滿。
  • 子元素提供專用背景色 list-group-item-{color} 添加使用,若持有 .list-group-item-action 時也有對應之顏色。
  • 可放入 badge 元件並試著靠右(透過建立 li.d-flex 達到)。
    <ul class="list-group">
    <li class="list-group-item d-flex justify-content-between align-items-center">
    Cras justo odio
    <span class="badge bg-primary rounded-pill">14</span>
    </li>
    <li class="list-group-item d-flex justify-content-between align-items-center">
    Dapibus ac facilisis in
    <span class="badge bg-primary rounded-pill">2</span>
    </li>
    </ul>
  • 什麼 HTML 都能包,多利用 flex 來設計你的 list-group-item。
    <div class="list-group">
    <a href="#" class="list-group-item list-group-item-action active">
    <div class="d-flex w-100 justify-content-between">
    <h5 class="mb-1">List group item heading</h5>
    <small>3 days ago</small>
    </div>
    <p class="mb-1">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>
    <small>Donec id elit non mi porta.</small>
    </a>
    <a href="#" class="list-group-item list-group-item-action">
    <div class="d-flex w-100 justify-content-between">
    <h5 class="mb-1">List group item heading</h5>
    <small class="text-muted">3 days ago</small>
    </div>
    <p class="mb-1">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>
    <small class="text-muted">Donec id elit non mi porta.</small>
    </a>
    </div>
  • 利用 label 取代 a 角色的範例。
    <div class="list-group">
    <label class="list-group-item">
    <input class="form-check-input me-1" type="checkbox">Cras justo odio
    </label>
    <label class="list-group-item">
    <input class="form-check-input me-1" type="checkbox">Dapibus ac facilisis in
    </label>
    </div>

動態 tab

list-group 除了好看的清單設計,也能搭配 bootstrap.js 的 tab-pane 功能變成具備切換分頁內容的清單組合。

  • 主要為 list 區域 div.list-group>a.list-group-item*n 與內容區 div.tab-content>div.tab-pane*n

list 區域

  • a.list-group-item 屬性 [data-toggle=list] 綁定 list 行為啟用。
  • a.list-group-item 連結 [href=#id] 指定內容區目標對象 ID。
  • 初始下指定一筆 a.list-group-item.active,與內容區顯示邏輯正常。

content 區域

  • div.tab-pane 需綁定 ID 才能被對應到。
  • 初始下指定一筆 .tab-pane.active.show,與選單區顯示邏輯正常。
  • 對所有子項目添加 .fade 為淡出效果。
<div class="container mt-5">
<div class="row">
<!-- List group -->
<div class="col-4 list-group">
<a class="list-group-item list-group-item-action active" data-bs-toggle="list" href="#tab1">Home</a>
<a class="list-group-item list-group-item-action" data-bs-toggle="list" href="#tab2">Profile</a>
</div>
<!-- Tab panes -->
<div class="col-8 tab-content">
<div class="tab-pane fade show active" id="tab1">A</div>
<div class="tab-pane fade" id="tab2">B</div>
</div>
</div>
</div>

JS 事件操作

除了透過 [data-toggle=list] 要求 list 之子元素動作啟用,可改用 JS 來完成啟用。

document.querySelectorAll(".list-group-item").forEach(function (Nod) { //找到每個 link 按鈕
const listA = new bootstrap.Tab(Nod); //相關建構式
Nod.addEventListener('click', function (event) { //只要有人點該 lisk 按鈕
event.preventDefault();
listA.show(); // 控制顯示 show 相關動作
});
});

可用函式動作

const myNode = document.querySelector('.list-group-item:last-child');
const loki = new bootstrap.Tab(myNode); // 建構式

loki.show(); // 目標顯示
loki.dispose(); //銷毀
const lokiInstance=new bootstrap.Tab.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

以下為元素已持有 [data-bs-toggle="list"] 直接抓取。

const myNode = document.querySelector('.list-group-item:last-child');
myNode.addEventListener('show.bs.tab', function (e) {
console.log("顯示中", e);
});
myNode.addEventListener('shown.bs.tab', function (e) {
console.log("已顯示", e);
});
myNode.addEventListener('hide.bs.tab', function (e) {
console.log("隱藏中", e);
});
myNode.addEventListener('hidden.bs.tab', function (e) {
console.log("已隱藏", e);
});

互動視窗 Modal

透過觸發時動態呼叫另一組隱藏的浮動內容視窗顯示,使得網頁有一種彈跳視窗的效果。主要結構為觸發按鈕與內容元素組

  • 按鈕需要持有屬性 [data-bs-toggle="modal"] 為動態觸發,屬性 [data-bs-target=#id] 為目標對象內容。
  • 內容元素組 div.modal 需要持有 ID 提供找到,以及子元素 div.modal-dialog>div.modal-content。可添加 .fade 做淡入效果。
  • .modal-content內容區可以包 modal-{header|body|footer} 供位置選擇。
  • 內容元素組第一層 .modal:滿版的大容器,並占用整個所有頁面視野。
  • 內容元素組第二層 .modal-dialog:視窗本體容器,提供 modal 視窗之區塊外觀。
  • 內容元素組第三層 .modal-content:內容用容器有不同區域,分別是 div.modal-header , div.modal-body , div.modal-footer
    <!-- Button trigger modal -->
    <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#lokiModalBox">
    Launch demo modal
    </button>
    <!-- Modal -->
    <div class="modal fade" id="lokiModalBox">
    <div class="modal-dialog">
    <div class="modal-content">
    <div class="modal-header">
    HEADER
    </div>
    <div class="modal-body">
    BODY
    </div>
    <div class="modal-footer">
    FOOTER
    </div>
    </div>
    </div>
    </div>
  • .modal-header 建議置入 button.btn-close 並添加 [data-bs-dismiss="modal"](其他處亦可添加此按鈕)作為關閉鍵。
  • 燈箱觸發時,會在 body 底處產生 div.modal-backdrop 之半透黑背景作為背景。若被點選等同關閉效果。
  • 同上,若不希望此黑透背景有關閉功能,於第一層 .modal 添加屬性 [data-bs-backdrop="static"]

屬性參數與適當位置

.modal 的屬性參數:

  • 增添屬性 [tabindex] 作為 tab 鍵的導航順序控制 (非必要)。
  • 內容過長時,預設是 overflow-y: auto; 效果,高度不限定使滾輪行為於整體網頁。

.modal-dialog 的屬性參數:

  • 若想讓使滾輪行為於 modal 內,添加 .modal-dialog-scrollable 使發生於固定高的 .modal-body
  • 視窗位置預設垂直靠上,可添加 .modal-dialog-centered 改為垂直置中。
  • 視窗寬度預設 500px,可添加 .modal-{sm|lg|xl} 使互動視窗的尺寸調整更改為 300px, 800px, 1140px。
  • 同上,若需要版滿可改添加 .modal-fullscreen 並提供響應斷點 .modal-fullscreen-{breakpoint}-down

.modal-content 的屬性參數:

  • 子元素 div.midal-body 可自行整合任何 Boostrap 元件,例如 Tooltips, popovers 或 grid (.container-fluid>.row>.col) 觀念。
  • 標題結構使用 div.modal-header>div.modal-title 能提供良好的外觀。

JS 事件操作

除了對按鈕透過 data-bs-toggle="modal" 要求 modal 啟用,可改用 JS 來完成啟用。

const myNode = document.querySelector('.modal');
const loki = new bootstrap.Modal(myNode); // 建構式
loki.show();

初始參數

透過該建構式能夠控制所有參數(同樣可對應 HTML 資料屬性之名稱來控制,通常是 [data-bs-*=])。

const myNode = document.querySelector('.modal');
const loki = new bootstrap.Modal(myNode, {
backdrop: true, // 提供半透黑底互動關閉,若不需要互動可指定為 "static"
keyboard: true, // 當 modal 獲得 focus 狀態時,按下 ESC 可退出 modal
focus: true //當 modal 開啟時,自動 focuse 至 modal
}); // 建構式

可用函式動作

const myNode = document.querySelector('.modal');
const loki = new bootstrap.Modal(myNode);

loki.toggle(); //切換狀態
loki.show(); //開啟
loki.hide(); //關閉
loki.handleUpdate(); //當 Modal 有發生高度變化(產生非預期之滾軸),可重新計算 modal 位置。
loki.dispose(); //銷毀

const lokiInstance=new bootstrap.Modal.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

const myNode = document.querySelector('.modal');
myNode.addEventListener('show.bs.modal', function (e) {
console.log("顯示中", e);
});
myNode.addEventListener('shown.bs.modal', function (e) {
console.log("已顯示", e);
});
myNode.addEventListener('hide.bs.modal', function (e) {
console.log("隱藏中", e);
});
myNode.addEventListener('hidden.bs.modal', function (e) {
console.log("已隱藏", e);
});
myNode.addEventListener('hidePrevented.bs.modal', function (e) {
console.log("因 static 關係無法透過 backdrop 關閉", e);
});

導覽與頁籤 Navs & Tabs

水平導覽選單,不同於 list group 的垂直列表選單設計,Navs 通常適合 inline 型的網站選單或頁尾區使用。主體結構可以是 ul>li>anav>a 之元素組合使用。

  • 主容器為 .nav。而原理為 flex,因此水平對齊 .justify-content-{center|end} 與垂直選單 .flex-column 輕鬆控制。
  • 子元素之 a 元素指定 a.nav-link 得到良好的 hover 提示,並可添加 .disabled 應用。
  • 使用 ul>li>a 結構時,對應的 li 請綁上 li.nav-item
  • 使用 nav>a 結構時,可省略 a.nav-item
    <ul class="nav">
    <li class="nav-item">
    <a class="nav-link" aria-current="page" href="#">Active</a>
    </li>
    <li class="nav-item">
    <a class="nav-link" href="#">Link</a>
    </li>
    <li class="nav-item">
    <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
    </li>
    </ul>
    <nav class="nav flex-column">
    <a class="nav-link" aria-current="page" href="#">Active</a>
    <a class="nav-link" href="#">Link</a>
    <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
    </nav>
  • 想使用 a.active 效果之前,請先選擇主容器風格為 .nav-pills.nav-tabs 才能作用。
  • 因應 flex 設計,對容器添加 .nav-fill 能對子項目做膨脹填滿 (flex: 1 1 auto)。
  • 因應 flex 設計,對容器添加 .nav-justified 能對子項目做等寬填滿 (flex: 1 1 0)。
  • 因應 flex 設計,可輕鬆整合 flex 的響應斷點變化。
  • li.nav-item 可整合 dropdown 元件,將互動鈕跟 Dropdown 容器的組合放入。
    <li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">Dropdown</a>
    <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Action</a></li>
    <li><a class="dropdown-item" href="#">Separated link</a></li>
    </ul>
    </li>

動態 tab

這裡能發展出類似前面介紹的 list group 的應用但不同效果,同樣需要搭配 Bootstrap.js 發生腳本行為,共會有 nav 選單(頁籤)區域與 tab-content 內容區域。

nav 區域

  • 使用剛提到的 nav 結構,其中所有的互動 a 元素配合主容器的風格 (tab or pill) 需綁定屬性 [data-bs-toggle=tab][data-bs-toggle=pill] (其實兩者無差別,擇一)
  • 互動 a 元素需綁定目標對象 [href=#id]

tab-content 區域

  • 結構為 div.tab-content>div[id=*].tab-pane,子項目需綁定 ID 提供對應。
  • 對子項目 .tab-pane 添加 .fade 獲得淡出效果。
  • 作用中效果為,nav 區的 .active 對應 tab-contet 區的 .active.show
<!--nav tab-->
<ul class="nav nav-tabs" id="myTab">
<li class="nav-item">
<a class="nav-link active" data-bs-toggle="tab" href="#home">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#profile">Profile</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="tab" href="#contact">Contact</a>
</li>
</ul>
<!--content zone-->
<div class="tab-content">
<div class="tab-pane fade show active" id="home">Home Text</div>
<div class="tab-pane fade" id="profile">Profile Text</div>
<div class="tab-pane fade" id="contact">Contact Text</div>
</div>

另一種垂直效果多增加一個 flex 控制左右欄位,而 nav 本身做垂直主軸。

<div class="d-flex align-items-start">
<div class="nav flex-column nav-pills me-3">
<a class="nav-link active" data-bs-toggle="pill" href="#pillA">Home</a>
<a class="nav-link" data-bs-toggle="pill" href="#pillB">Profile</a>
</div>
<div class="tab-content" id="v-pills-tabContent">
<div class="tab-pane fade show active" id="pillA">A...</div>
<div class="tab-pane fade" id="pillB">B...</div>
</div>
</div>

JS 事件操作

除了透過 [data-toggle={tab|pill}] 要求動作啟用,可改用 JS 來完成啟用。

document.querySelectorAll(".nav-link").forEach(function (Nod) { //找到每個 link 按鈕
const listA = new bootstrap.Tab(Nod); //相關建構式
Nod.addEventListener('click', function (event) { //只要有人點該 lisk 按鈕
event.preventDefault();
listA.show(); // 控制顯示 show 相關動作
});
});

先前 list Group 已出現過,這裡的控制方法皆相同。

可用函式動作

const myNode = document.querySelector('.nav-link:last-child');
const loki = new bootstrap.Tab(myNode); // 建構式

loki.show(); // 目標顯示
loki.dispose(); //銷毀
const lokiInstance=new bootstrap.Tab.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

以下為元素已持有 [data-bs-toggle="tab"] 直接抓取。

const myNode = document.querySelector('.nav-link:last-child');
myNode.addEventListener('show.bs.tab', function (e) {
console.log("顯示中", e);
});
myNode.addEventListener('shown.bs.tab', function (e) {
console.log("已顯示", e);
});
myNode.addEventListener('hide.bs.tab', function (e) {
console.log("隱藏中", e);
});
myNode.addEventListener('hidden.bs.tab', function (e) {
console.log("已隱藏", e);
});

導覽列 Navbar

由 nav 再進化提供網站選單元件( nav 與 navbar 兩者不同元件)。navbar 除了會包入 nav 結構設計成選單,還能加入 LOGO 或表單等元件。大致結構為:

  • 主容器 nav.navbar建議多內層 .container{-fluid} 來獲得良好的排版與 flex 屬性。
  • 子元素:LOGO 區 a.navbar-brand
  • 子元素:選單區 div.nav-collapse,內部包了導覽清單 ul.navbar-nav>li.nav-item>a.nav-link (或 nav.navbar-nav>a.nav-link )。
  • 子元素:文字 span.navbar-text
  • 子元素:其他項目元件,例如 form 元件
<nav class="navbar navbar-expand navbar-light bg-light">
<div class="container">
<!--LOGO-->
<a class="navbar-brand" href="#">LOGO</a>
<!--主角 MENU-->
<div class="navbar-collapse" id="lokinav">
<ul class="navbar-nav me-auto">
<li class="nav-item active"><a class="nav-link" href="#">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#">Link</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">Dropdown</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
</ul>
<form class="d-flex">
<input class="form-control me-2" type="search" placeholder="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>

主容器 nav.navbar
透過 nav.navbar>.container{-fluid} 來包覆整格版面。容器用於裝載所有子元素或模組元件。

  • 預設情況下會以垂直的設計做排列,唯獨當額外添加 .navbar-expand 時會以水平方式排列(稍後介紹支援響應斷點)。
  • 子項目之間的靠齊方式,可使用 {me|ms}-auto 或善用 flex 技巧(預設已是 justify-content: space-between; 屬性)。
  • 字色控制 .navbar-{light|dark} ,可搭配 .bg-{color} 通用效果。
  • 常有以下三種方式對導覽列有不同的定位方式。
  • nav.navbar.flexd-top ,浮起並重疊 <body> 區,固定在頁首。
  • nav.navbar.flexd-bottom ,浮起並重疊 <body> 區,固定在頁尾。
  • nav.navbar.sticky-top ,只有當離開頁面時才浮起並重疊 <body> 區,固定在頁首(好用)。

子元素:LOGO 區 .navbar-brand

  • .navbar-brand 作為網站名稱文字或圖片,可以是任何標籤之組合,例如 a 元素包圖片並帶錨點連結。

子元素:選單區 .navbar-collapse

  • 必要性添加 div.navbar-collapse 使版面支援根據視寬決定水平或垂直排列,內層為 navbar 元素組合。
  • navbar 元素組合與 Navs 元件觀念操作雷同 (class 名稱有異),例如:
    • Navbar 為 ul.navbar-nav>li.nav-item>a.nav-link (然而 nav 元件為 ul.nav>li.nav-item>a.nav-link)
    • Navbar 為 div.navbar-nav>a.nav-link (然而 nav 元件為 div.nav>a.nav-link
  • 添加 .active 能代表當前頁面,可以寫在 .nav-item.nav-link 處。
    ...
    <!-- 選單 ul>li>a-->
    <div class="navbar-collapse">
    <ul class="navbar-nav">
    <li class="nav-item"><a class="nav-link active" href="#">Home</a></li>
    <li class="nav-item"><a class="nav-link" href="#">Features</a></li>
    <li class="nav-item"><a class="nav-link" href="#">Pricing</a></li>
    <li class="nav-item"><a class="nav-link disabled" href="#">Disabled</a></li>
    </ul>
    </div>
    ...
    <!-- 選單 div>a-->
    <div class="navbar-collapse">
    <div class="navbar-nav">
    <a class="nav-link active">Home</a>
    <a class="nav-link" href="#">Features</a>
    <a class="nav-link" href="#">Pricing</a>
    <a class="nav-link disabled" href="#">Disabled</a>
    </div>
    </div>
    ...
  • 可包裝 dropdown 到 .nav-link 內。
    ...
    <li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">Dropdown link</a>
    <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Action</a></li>
    <li><a class="dropdown-item" href="#">Another action</a></li>
    <li><a class="dropdown-item" href="#">Something else here</a></li>
    </ul>
    </li>
    ...

子元素:其他項目元件
直接整個元素組放入至 nav.navbar>.container 內使用即可。

<nav class="navbar navbar-light bg-light">
<div class="container-fluid">
<!-- LOGO -->
<a class="navbar-brand">Navbar</a>
<!-- FORM -->
<form class="d-flex">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
<!-- TEXT -->
<span class="navbar-text">
Navbar text with an inline element
</span>
<!-- BUTTON -->
<button class="btn btn-outline-success me-2" type="button">Main button</button>
<button class="btn btn-sm btn-outline-secondary" type="button">Smaller button</button>
</div>
</nav>

響應式收疊模組

響應式模組透過整合 collapse 元件進行設計,主要為當視寬達到條件時,垂直選單多一個收疊按鈕使選單隱密化。達成條件如下:

  • 指定 .navbar 主容器添加 .navbar-expand-{breakpoint} ,使得選單有垂直與水平兩種響應時機。
  • 指定 navbar-collapse 選單區添加 .collapse,使得導覽列在垂直模式下會隱藏,唯獨透過 collapse 元件啟用下才會顯示。
  • 建立觸發 button 放入主容器內並添加 .navbar-toggler,這個按鈕在水平模式下會自動隱藏。同時指定 icon 圖案(通常稱呼為漢堡包)。
  • 同上,透過 collapse 元件規則需要綁定 [data-bs-toggle="collapse"] 以及目標 [data-bs-target="#navbarID"]
    <button class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbarID">
    <span class="navbar-toggler-icon"></span>
    </button>
  • 如果收疊時包含 LOGO 隱匿,把 .navbar-brand 搬入到 .navbar-collapse 內。
  • 如果收疊時觸發按鈕於靠左且 LOGO 靠右,調整 HTML 位置順序為 button.navbar-toggler + a.navbar-brand (透過預設的 space-between 來定位)。
    <nav class="navbar navbar-expand-lg navbar-dark bg-success">
    <div class="container">
    <!--LOGO-->
    <a class="navbar-brand" href="#">LOGO</a>
    <!-- BUTTON -->
    <button class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#lokiNavbar">
    <span class="navbar-toggler-icon"></span>
    </button>
    <!--主角 MENU-->
    <div class="collapse navbar-collapse" id="lokiNavbar">
    <ul class="navbar-nav me-auto">
    <li class="nav-item active"><a class="nav-link" href="#">Home</a></li>
    <li class="nav-item"><a class="nav-link" href="#">Link</a></li>
    <li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">Dropdown</a>
    <div class="dropdown-menu">
    <a class="dropdown-item" href="#">Action</a>
    <div class="dropdown-divider"></div>
    <a class="dropdown-item" href="#">Something else here</a>
    </div>
    </li>
    </ul>
    <!-- 因為在 navbar-collapse 內,所以一同響應隱藏 -->
    <form class="d-flex">
    <input class="form-control me-2" type="search" placeholder="Search">
    <button class="btn btn-outline-success" type="submit">Search</button>
    </form>
    </div>
    </div>
    </nav>
  • 收疊按鈕可以當作一般模組使用,或參考 collapse 元件來自行設計。
    <div class="collapse" id="btnContent">
    <div class="bg-dark p-4">
    <h5 class="text-white h4">Collapsed content</h5>
    </div>
    </div>
    <nav class="navbar navbar-dark bg-dark">
    <div class="container-fluid">
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#btnContent">
    <span class="navbar-toggler-icon"></span>
    </button>
    </div>
    </nav>

分頁導覽 Pagination

用於多篇文章項目的分頁導覽,大致上就是包裝成群組外框與連續指定的連結標籤。主結構為 ul.pagination>li.page-item>a.page-link

  • 主容器 ul.pagination 可添加 .pagination-{lg|sm} 作為尺寸調整。
  • li 元素 .page-item 可添加 .active.disabled 來做為特殊示意。
  • 主容器 ul.pagination 同時因 flex 設計可自行調整對齊。
<nav>
<ul class="pagination justify-content-end">
<li class="page-item"><a class="page-link" href="#">&laquo;</a></li>
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item"><a class="page-link" href="#">&raquo;</a></li>
</ul>
</nav>

彈跳提示框 Popovers

這裡會依賴第三方外掛 popper.js,效果是從觸發紐獲得屬性資料生成一個浮動且格式固定的資料提示框。

  • 因效能問題預設不會啟用,必須手動執行 JS 語法初始化才能作用。
  • 至少需要 [title][data-bs-content] 否則無法生成內容。
    <button data-bs-toggle="popover" class="btn btn-lg btn-danger"
    title="Popover title"
    data-bs-content="writeing message here...">
    Button Click</button>
    <script>
    document.querySelectorAll('[data-bs-toggle="popover"]').forEach(function (item) {
    new bootstrap.Popover(item);
    });
    </script>
  • 在複雜的元素組內使用時,有可能提示框層級位置錯亂,可添加 [data-bs-container="body"] 處理,或在 js 初始化時一併處理。
  • 彈跳方向指定 [data-bs-placement={top|right|bottom|left}],在允許的空間下否則會自己找出路。
    <button data-bs-toggle="popover" class="btn btn-secondary"
    data-bs-container="body"
    data-bs-placement="top"
    data-bs-content="writeing message here...">
    Popover on top</button>
    <button data-bs-toggle="popover" class="btn btn-secondary"
    data-bs-container="body"
    data-bs-placement="right"
    data-bs-content="writeing message here...">
    Popover on right</button>
    <button data-bs-toggle="popover" class="btn btn-secondary"
    data-bs-container="body"
    data-bs-placement="bottom"
    data-bs-content="writeing message here...">
    Popover on bottom</button>
    <button data-bs-toggle="popover" class="btn btn-secondary"
    data-bs-container="body"
    data-bs-placement="left"
    data-bs-content="writeing message here...">
    Popover on left</button>
    <script>
    document.querySelectorAll('[data-bs-toggle="popover"]').forEach(function (item) {
    new bootstrap.Popover(item,{
    container:'body'
    });
    });
    </script>
  • 提示框預設關閉的方式是再點擊一次按鈕,你可以改為 [data-bs-trigger="{focus|hover}"] 決定以 focus 或 hover 來觸發切換。

JS 事件操作

如同前面所說 Bootstrap 沒有預設先啟用。這裡的操作方法以在上一節說明,這裡直接說明初始化參數的介紹:

const myNode = document.querySelector('[data-bs-toggle="popover"]');
const loki = new bootstrap.Popover(myNode, {
animation: true, //提供轉場 fade 特效
container: false, //指定的參考範圍為哪個 DOM,你可以指定 'body' 當發生顯示不如預期時
content: "writeing message AAA here...", //提示框之內文
delay: { show: 0, hide: 0 }, // 控制延遲之時間,單位毫秒
html: false, //是否以 html 方式為內文,否則以 innerText 方式插入
placement: "right", //提示框之推出方向,若為 auto 則動態的去找定位
selector: false, // 提供一個 DOM 位置,將目前的提示框受作用於該 DOM(適合後製生成的動態 DOM 來創立提示框)
template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',// 預設的提示框版型
title: "",//提示框之標題
trigger: "click", //觸發方式,可以是 click, hover, focus, manual。可複合綁定用空格分開 (唯獨 manual 不可混合)。manual 是只能透過show(), hide() 這類函式執行而不使用滑鼠事件。
offset:"0", //偏移,官方未說明(細節需從第三方 popper.js 理解)
fallbackPlacements: null, //回調位置,官方未說明(細節需從第三方 popper.js 理解)
boundary: "clippingParents", //彈出提示框的溢出邊界常數。可接受值為 viewport, window, scrollParent
customClass: "", //對提示框添加 class,多筆可輸入 `cls1 cls2`
sanitize: true, // 每次生成的資料是否從觸發按鈕來取得,若是則會清除這裡指定的 title 與 content
//allowList: {...}, // JSON 字串,列寫可允許的元素與屬性
sanitizeFn: null, // 自訂清除函式來執行清除操作
popperConfig: null //改變 popper 設定,官方未說明(細節需從第三方 popper.js 理解)
});

可用函式動作

const myNode = document.querySelector('[data-bs-toggle="popover"]');
const loki = new bootstrap.Popover(myNode); // 建構式

loki.toggle(); // 切換
loki.show(); // 顯示
loki.hide(); // 隱藏
loki.enable(); //開啟 popper 功能
loki.disable(); //關閉 popper 功能
loki.toggleEnabled(); // 切換 popper 功能開關
loki.update(); // 更新提示框的定位值
loki.dispose(); //銷毀

const lokiInstance=new bootstrap.Popover.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

const myNode = document.querySelector('[data-bs-toggle="popover"]');
const loki = new bootstrap.Popover(myNode);

myNode.addEventListener('show.bs.popover', function (e) {
console.log("顯示中", e);
});
myNode.addEventListener('shown.bs.popover', function (e) {
console.log("已顯示", e);
});
myNode.addEventListener('hide.bs.popover', function (e) {
console.log("隱藏中", e);
});
myNode.addEventListener('hidden.bs.popover', function (e) {
console.log("已隱藏", e);
});
myNode.addEventListener('inserted.bs.popover', function (e) {
console.log("提示框已加入 DOM", e);
});

進度條 Progress

一種作為固定表示進度用途的視覺元件,主要是拿來替代 HTML 醜陋的進度條元素,結構為 div.progress>div.progerss-bar

<!-- HTML5 version
<progress id="file" max="100" value="70"> 70% </progress>
-->
<div class="progress" style="height:40px">
<div class="progress-bar bg-danger" style="width:66%">66%</div>
</div>
  • 父容器 .progress 作為最大寬度,可自訂高度。
  • 子項目 .progress-bar 需指定寬度或百分比,作為進度值。
  • 子項目填寫文字將成為標籤字且置中。
  • 子項目可添加背景色 bg-{color} ,並累加糖果紙疊合 .progress-bar-striped 效果同時可再疊加 .progress-bar-animated 動畫。
  • 若父容器包覆多筆子項目,他們會累加並聯在一起。

滾動監控 Scrollspy

根據受監控的對象的錨點位置對應於 nav 或 list-group 元件內的 target 屬性並修正為 active 狀態,這需要 Bootstrap.js 的協助處理。

  • 設定對應:

    1. 導覽列主容器需持有屬性 ID vs 監控端的[data-bs-target=#ID]
    2. 導覽列子項目錨點連結 a[href=#id] vs 監控端的子項目屬性 ID。
  • 監控端必須是 position: relative 屬性,通常用於 body 元素,如果不是 body 元素需注意是否持有固定高度 (height) 且帶有滾輪 (overflow-y: scroll)。

  • 監控端需綁定 [data-bs-spy="scroll"] 啟用監控,另外 [data-offset=0] 能調整回報之位移值。

  • 整頁設計下,監控端是 body 則不需指定 relative, height, overflow。導覽列可推薦使用 .stick-top 設定。

  • 監控

<!-- list-group 版本 -->
<div class="container mt-5">
<div class="row">
<div class="col-4">
<div id="listMenu" class="list-group">
<a class="list-group-item list-group-item-action" href="#list-item-1">Item 1</a>
<a class="list-group-item list-group-item-action" href="#list-item-2">Item 2</a>
</div>
</div>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#listMenu" data-bs-offset="0" style="position: relative; height: 200px;overflow: auto;">
<h4 id="list-item-1">Item 1</h4>
<p>A Lorem ipsum dolor sit amet consectetur, adipisicing elit. Perferendis facere ad sint nemo eaque veniam
voluptatem modi adipisci nulla? In, vero, asperiores labore adipisci eaque fugit explicabo repellendus
incidunt blanditiis laboriosam est corrupti ad dolor possimus consequuntur a animi odit, dignissimos
placeat? Nisi odit accusamus cupiditate ratione delectus voluptatum alias ipsam, minus incidunt sapiente
commodi a qui illum quia, consectetur mollitia tempore esse beatae saepe laborum corporis! Porro doloribus
adipisci beatae dolor velit accusantium quos odio sequi corporis facilis recusandae iusto vel modi libero
perspiciatis excepturi, itaque omnis magni vero incidunt ipsum consequatur, culpa tempore. Numquam iste
culpa esse eaque doloribus </p>
<h4 id="list-item-2">Item 2</h4>
<p>B Lorem ipsum dolor sit amet consectetur adipisicing elit. Minima quaerat eveniet, quam expedita asperiores
magni eius quo dolorum fuga quisquam sed odio est ea repellat ullam excepturi. At dolore minus illum,
aliquid ex ea doloribus alias totam error cumque itaque quia atque, illo porro quas velit aspernatur debitis
deserunt inventore molestiae eligendi autem repudiandae sequi excepturi! Sint laboriosam asperiores beatae
officia commodi unde reiciendis illum aperiam quam sunt nam soluta excepturi illo obcaecati tempora vitae
corporis, accusantium adipisci voluptates, quasi enim! Laborum, consectetur deleniti aliquid velit aliquam
maxime amet aut mollitia adipisci voluptates provident quod alias nam ipsam nobis iusto quae numquam, veniam
iure </p>
</div>
</div>
</div>
</div>
<!-- body 版本 -->
<body data-spy="scroll" data-target="#list-example" data-offset="0">
<div class="row">
<div class="col-4">
<div id="list-example" class="list-group sticky-top" style="top:1.5rem">
<a class="list-group-item list-group-item-action" href="#list-item-1">Item 1</a>
<a class="list-group-item list-group-item-action" href="#list-item-2">Item 2</a>
</div>
</div>
<div class="col-8">
<h4 id="list-item-1">Item 1</h4>
<p>A Lorem ipsum dolor sit amet consectetur, adipisicing elit. Perferendis facere ad sint nemo eaque veniam voluptatem modi adipisci nulla? In, vero, asperiores labore adipisci eaque fugit explicabo repellendus incidunt blanditiis laboriosam est corrupti ad dolor possimus consequuntur a animi odit, dignissimos placeat? Nisi odit accusamus cupiditate ratione delectus voluptatum alias ipsam, minus incidunt sapiente commodi a qui illum quia, consectetur mollitia tempore esse beatae saepe laborum corporis! Porro doloribus adipisci beatae dolor velit accusantium quos odio sequi corporis facilis recusandae iusto vel modi libero perspiciatis excepturi, itaque omnis magni vero incidunt ipsum consequatur, culpa tempore. Numquam iste culpa esse eaque doloribus iure, </p>
<h4 id="list-item-2">Item 2</h4>
<p>B Lorem ipsum dolor sit amet consectetur adipisicing elit. Minima quaerat eveniet, quam expedita asperiores magni eius quo dolorum fuga quisquam sed odio est ea repellat ullam excepturi. At dolore minus illum, aliquid ex ea doloribus alias totam error cumque itaque quia atque, illo porro quas velit aspernatur debitis deserunt inventore molestiae eligendi autem repudiandae sequi excepturi! Sint laboriosam asperiores beatae officia commodi unde reiciendis illum aperiam quam sunt nam soluta excepturi illo obcaecati tempora vitae corporis, accusantium adipisci voluptates, quasi enim! Laborum, consectetur deleniti aliquid velit aliquam maxime amet aut mollitia adipisci voluptates provident quod alias nam ipsam nobis iusto quae numquam, veniam iure possimus, </p>
</div>
</div>
</body>

JS事件操作

如前面所提到都是透過 [data-bs-spy="scroll"] 方式來啟用。你可以改用JS來起作用。

初始參數

const myNode = document.body; //如果監控端為整個body
const loki = new bootstrap.ScrollSpy(myNode, {
target: "#list-example", // 偵測回報至目標對象
offset: 10, // 偵測回報的偏移量
method: "auto" //獲得監控端元素所在的滾動座標方式(auto = 自動選擇 | offset = 使用 Element.getBoundingClientRect() | position = 使用 HTMLElement.{offsetTop & offsetLeft} 屬性
});

可用函式動作

const myNode = document.body; //如果監控端為整個body
const loki = new bootstrap.ScrollSpy(myNode);

loki.refresh(); //若 body的DOM有變動,進行刷新重新偵測
loki.dispose(); //銷毀

const lokiInstance =new bootstrap.Dropdown.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

const myNode = document.body; //如果監控端為整個body
const loki = new bootstrap.ScrollSpy(myNode, {
target: "#list-example" // 偵測回報至目標對象
});

window.addEventListener('activate.bs.scrollspy', function (e) {
console.log("監控反應到,spy已運作完成", e);
});

動畫圖示 Spinners

這裡已經提供一些 HTML + CSS animation 的動態圖示,如果你希望拿來當資料處理的過渡時間,你需要自己動手做出 JS 腳本控制這些 DOM 與隱蔽圖示之時機。

<div class="spinner-border text-danger"></div>
<div class="spinner-grow text-danger"></div>
  • 提供旋轉或漸變模式,分別是 .spinner-{border|grow}
  • 由於 border-color:currentcolor關係會參考文字色,因此添加 .text-{color} 即可玩色。
  • 提供尺寸調整,另添加.spinner-{border|grow}-{lg|sm}
  • 本質為 inline-block,所以可以用 flex, text-align, float, margin 這類技巧去處理排版,也可整合到任何的元素或元件內。

吐司方塊 Toasts

常見於社群網站的資訊傳送或服務網頁的即時傳遞使用,主要是模仿電腦桌面角落的推播方塊,本身採用 flex 概念。架構為

div.toast>div.toast-header+div.toast-body

  • .toast 主容器初始下看不見(透明度 0),你可以添加 .show 來看見,或使用 JS 腳本執行 toast() 物件來操作。
  • .toast-body 預設半透明,若瀏覽起支援濾鏡 backdrop-filter:blur 會有模糊效果。
  • 可加入關閉按鈕 button[data-bs-dismiss="toast"].btn-close 做為觸發關閉。
<div class="toast fade show">
<div class="toast-header">
<img src="https://fakeimg.pl/45x45" class="rounded mr-2">
<strong class="me-auto">Bootstrap</strong>
<small>11 mins ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast"></button>
</div>
<div class="toast-body">
Hello, world! This is a toast message.
</div>
</div>
  • 多個 .toast 預設排版為 block 堆疊,可透過大容器 div.toast-container 包覆,能協助間格 0.75rem。
  • 可捨棄 .toast-header 並自訂自己的HTML設計與排版並整合各種通用與元件,例如背景色、flex、按鈕、postiion 等等。
<div class="toast-container position-fixed top-0 end-0 p-3">
<div class="toast fade show">
<div class="toast-header">
<img src="https://fakeimg.pl/45x45" class="rounded me-2" />
<strong class="me-auto">Bootstrap</strong>
<small class="text-muted">just now</small>
<button type="button" class="btn-close" data-bs-dismiss="toast"></button>
</div>
<div class="toast-body">See? Just like this. 1</div>
</div>
<div class="toast fade show">
<div class="toast-header">
<img src="https://fakeimg.pl/45x45" class="rounded me-2" />
<strong class="me-auto">Bootstrap</strong>
<small>11 mins ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast"></button>
</div>
<div class="toast-body">See? Just like this. 2</div>
</div>
</div>

JS事件操作

先前都是手動的添加 .fade.show 使手動出現,較正式的用法為JS語法來初始化並操作顯示時機。

初始參數

以下包含初始化方式與初始參數,當然你也可以用 [data-bs-*] 指定給 .toast

document.querySelectorAll('.toast').forEach(function (item) {
const Node= new bootstrap.Toast(item,{
animation:true, //是否fade特效
autohide:true, //是否自動消失
delay:3000 //停留多久才消失
});
Node.show();
})

可用函式動作

const myNode = document.querySelector('.toast');
const loki = new bootstrap.Toast(myNode);

loki.show(); //開啟
loki.hide(); //關閉
loki.dispose(); //銷毀

事件回應處理

document.querySelectorAll('.toast').forEach(function (item) {
const myNode = new bootstrap.Toast(item, {
animation: true, //是否fade特效
autohide: true, //是否自動消失
delay: 3000 //停留多久才消失
});

item.addEventListener('show.bs.toast', function (e) {
console.log("顯示中", e);
});
item.addEventListener('shown.bs.toast', function (e) {
console.log("已顯示", e);
});
item.addEventListener('hide.bs.toast', function (e) {
console.log("隱藏中", e);
});
item.addEventListener('hidden.bs.toast', function (e) {
console.log("已隱藏", e);
});

myNode.show();
});

工具提示 Tooltips

是一個比 Popovers 還更單調的元件,只能取得自身的 title 屬性變成泡泡方塊作為 hover 提示。這裡會依賴第三方外掛 popper.js。

  • 因效能問題預設不會啟用,必須手動執行 JS 語法初始化才能作用。
  • 需要 [title] 否則無法生成內容。
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top">Tooltip on top</button>
<script>
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(function (item) {
new bootstrap.Tooltip(item);
});
</script>
  • 在複雜的元素組內使用時,有可能提示框層級位置錯亂,可添加 [data-bs-container="body"] 處理,或在 js 初始化時一併處理。
  • 彈跳方向指定 [data-bs-placement={top|right|bottom|left}],在允許的空間下否則會自己找出路。
  • 提示訊息預設反應以 focus 或 hover 來觸發切換。

JS事件操作

如同前面所說 Bootstrap 沒有預設先啟用。這裡的操作方法以在上一節說明,這裡直接說明初始化參數的介紹:

const myNode = document.querySelector('[data-bs-toggle="tooltip"]');
const loki = new bootstrap.Tooltip(myNode, {
animation: true, //提供轉場 fade 特效
container: false, //指定的參考範圍為哪個 DOM,你可以指定 'body' 當發生顯示不如預期時
delay: { show: 0, hide: 0 }, // 控制延遲之時間,單位毫秒
html: false, //是否以 html 方式為內文,否則以 innerText 方式插入
placement: "top", //提示框之推出方向,若為 auto 則動態的去找定位
template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',// 預設的提示框版型
title: "",//提示框之標題
trigger: "hover focus", //觸發方式,可以是 click, hover, focus, manual。可複合綁定用空格分開 (唯獨 manual 不可混合)。manual 是只能透過show(),hide()這類函式執行而不使用滑鼠事件。
fallbackPlacements: null, //回調位置,官方未說明(細節需從第三方 popper.js 理解)
boundary: "clippingParents", //彈出提示框的溢出邊界常數。可接受值為 viewport, window, scrollParent
customClass: "", //對提示框添加 class,多筆可輸入 `cls1 cls2`
sanitize: true, // 每次生成的資料是否從觸發按鈕來取得,若是則會清除這裡指定的 title
//allowList: {...}, // JSON 字串,列寫可允許的元素與屬性
sanitizeFn: null, // 自訂清除函式來執行清除操作
popperConfig: null //改變 popper 設定,官方未說明(細節需從第三方 popper.js 理解)
});

可用函式動作

const myNode = document.querySelector('[data-bs-toggle="tooltip"]');
const loki = new bootstrap.Tooltip(myNode); // 建構式

loki.show(); // 顯示
loki.hide(); // 隱藏
loki.toggle(); // 切換
loki.dispose(); //銷毀
loki.enable(); //開啟 popper 功能
loki.disable(); //關閉 popper 功能
loki.toggleEnabled(); // 切換 popper 功能開關
loki.update(); // 更新提示框的定位值

const lokiInstance=new bootstrap.Tooltip.getInstance(myNode); // 獲取與 DOM 關聯的靜態方法

事件回應處理

const myNode = document.querySelector('[data-bs-toggle="tooltip"]');
const loki = new bootstrap.Tooltip(myNode);

myNode.addEventListener('show.bs.tooltip', function (e) {
console.log("顯示中", e);
});
myNode.addEventListener('shown.bs.tooltip', function (e) {
console.log("已顯示", e);
});
myNode.addEventListener('hide.bs.tooltip', function (e) {
console.log("隱藏中", e);
});
myNode.addEventListener('hidden.bs.tooltip', function (e) {
console.log("已隱藏", e);
});
myNode.addEventListener('inserted.bs.tooltip', function (e) {
console.log("提示框已加入 DOM", e);
});

結語

Boostrap 最大的學習重點是如何善用他的 grid 來發展你的 RWD 網站,以及如何快速的使用元件來完成網站部屬,在刻版過程當中使用通用操作完成簡單的屬性設定,但切記不要過度依賴 class 命名瘋狂指定,這會讓你的 HTML 的複雜度提升,如果你的 class 公式需求過高時還是回到自訂 class 來完成 CSS 屬性編寫。