Bootstrap 元件設計模式 — OOCSS

穎旻
8 min readJun 3, 2020

--

前言

說到 OOCSS 設計模式,最具代表的應用就是 Bootstrap 了!

你可能會想,自己有需要學這個嗎?了解設計模式可以幹嘛呢?我自己在學習前端一陣子後已經能順利刻出想要的版型,也熟悉標籤的使用、了解語意化的重要,但是面對 CSS 卻一直沒有在進步的感覺,同樣的 CSS 會在不經意中重複使用好幾次、沒有一個規劃,後來因為接觸了不同的設計模式我才慢慢理解良好的設計模式可以幫助程式碼更容易維護甚至擴充,寫起來也會更順手,所以如果你也跟我一樣,可以一起來認識 OOCSS!

如果你不清楚自己目前情況,可以透過範例來了解是否需要學習

範例一

  • 想要給 card li 樣式時會用 .content .card li {...} 而不是 .card li {...}
<div class="content">
<ul class="card">
<li>...</li>
<li>...</li>
</ul>
</div>

應該很多人都有使用過這樣的寫法,覺得.content .card li 權重分數較高,階層也不會過多,會用這種寫法其實很合理

範例二

  • 會把一個東西的 CSS 都全塞在一個 class 裡面
<a class="btn">123</a>.btn {
display: block;
color: white;
background-color: blue;
padding: 10px 20px;
text-decoration:none;
text-align:center;
border-radius: 2px;
cursor: pointer;
}

如果以上兩種都是你目前使用的撰寫方式,那恭喜你可以繼續看下去了XD

OOCSS

OOCSS 是 Object Oriented CSS 的縮寫,是 CSS 的架構方法,在這個原則下撰寫的 CSS 具有以下特點:

  • 容器與內容分離
  • 結構與樣式分離

容器與內容分離

容器與內容分離 圖來自六角學院

簡單來說, 內容 就是你的元件,而 容器 就是包住元件或其他內容的外層

當容器與內容分離時,容器的重用性就會變高、變彈性而不會受到命名的限制,例如:

header 區塊
<div class="header">
<ul class="menu">
<li>...</li>
<li>...</li>
</ul>
</div>
<style>
.header .menu li {...}
</style>
footer 區塊
<div class="footer">
<ul class="menu">
<li>...</li>
<li>...</li>
</ul>
</div>
<style>
.footer .menu li {...}
</style>

明明是同樣的內容,卻因為外層從 header 換成 footer 所以需要再寫一次 CSS
於是我們利用容器和內容分離的概念,再修改一下

<div class="container">
<!-- header -->
<div class="row">
<div class="col-12">
<ul class="menu">
<li>...</li>
<li>...</li>
</ul>
</div>
</div>

<!-- footer -->
<div class="row">
<div class="col-12">
<ul class="menu">
<li>...</li>
<li>...</li>
</ul>
</div>
</div>
</div><style>
.menu li {...}
</style>

可以發現改成分離的設計方式後

  • 內容的 CSS 是可以共用的
  • 內容的 CSS 不再受到容器命名的限制,可以寫成 .menu li 而不是 .col-12 .menu li

綜合以上兩點,這時再回顧範例一的問題,你會寫 .content .card li {…} 還是 .card li {…} 呢?

<div class="content">
<ul class="card">
<li>...</li>
<li>...</li>
</ul>
</div>

聰明的你理解過後就知道 .card {…} 才是比較好的選擇,原因在於 content 是容器,所以不會去使用容器當命名的開頭,就像我們不會拿 .col 當開頭一樣

講完容器與內容分離的原理,我們來看 Bootstrap 是如何應用在元件上

Bootstrap 元件也可以分為容器與內容(容器可以包內容)

  • 容器型元件:如 GridCardFormsModal
  • 內容型元件:如 AlertsBadgeBreadcrumbButtons
  1. Card 卡片:Card 是 容器 ,而 Button 屬於 內容
Card + Button
<div class="card" style="width: 18rem;">
<img src="..." class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">...</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
  1. List 列表:Card 是 容器 ,而 List 屬於 內容
Card + List
<div class="card" style="width: 18rem;">
<img src="..." class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class=”card-text”>...</p>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">Cras justo odio</li>
<li class="list-group-item">Dapibus ac facilisis in</li>
<li class="list-group-item">Vestibulum at eros</li>
</ul>
</div>

看完這兩個範例,就能體會他的彈性有多大了,不同元件可以互相組成,也不會受到容器的限制

那麼接下來我們來拆解 Bootstrap 的元件 class 設計吧!

結構與樣式分離

使用 Iphone 的人應該有玩過或是看過 Animoji,他可以透過選擇臉部的器官來打造出自己的角色

Animoji

你可以把原本所有器官的預設樣式想像成「結構」(左圖),結構是一個元件的基底(base)像是寬度、圓角、字體大小等等

而你也可以選擇頭髮顏色、皮膚顏色等等的就是所謂的「樣式」(右圖),在 Bootstrap 按鈕元件中就是以顏色區分(包含字體顏色、背景顏色)

這時我們再回到一開頭的範例二

<a class="btn">123</a>.btn {
display: block;
color: white;
background-color: blue;
padding: 10px 20px;
text-decoration:none;
text-align:center;
border-radius: 2px;
cursor: pointer;
}

利用結構與樣式分離的概念,我們再重寫一次

<a class="btn btn-primary">123</a>.btn {
display: block;
padding: 10px 20px;
text-decoration:none;
text-align:center;
border-radius: 2px;
cursor: pointer;
}
.btn-primary {
color: white;
background-color: blue;
border: lightblue;
}

應該有看到在 class 的部分多拆出了 btn-primary

他的優點是

  • 按鈕需要換一個顏色,不需要先去找到那顆按鈕的 CSS 然後改掉顏色
  • 當想要寫第二顆按鈕在他旁邊時,不再需要重複寫一堆類似的 CSS,而是把不一樣的部分抽離出來管理,一樣的部分就保留起來不會去動它

總結

以上就是 OOCSS 的強大之處,理解這個設計模式後你也能套用他的方法設計出屬於自己的元件,不但好維護好管理,也能大大減少 CSS 的容量,是不是很讚~快來試試吧!

--

--

穎旻

👩🏻‍🎓Student / 👩🏻‍💻 Frontend Developer