---
# System prepended metadata

title: 10個CSS小技巧

---

# 10個CSS小技巧

:::info
:bulb: 一項投票調查中，關於Web開發人員合作中使他們最痛苦的技術，CSS位居榜首。
:::

CSS確實臃腫且難以全面學習，但這只是因為它在過去25年中不斷發展。它出現在1996年，netscape那時還是top瀏覽器。而如今RWD(Responsive Web Design)的想法也已有十多年，越來越多瀏覽器進入市場，它們又以不同方式去呈現CSS。這導致code在一個瀏覽器中工作，另一個又不工作，使得開發人員就必須在代碼中編寫一堆令人困惑的供應商前綴。

```css
.lame-sauce {
    -webkit-transition: all 4s ease; /* chrome */
    -moz-transition: all 4s ease; /* firefox */
    -ms-transition: all 4s ease; /* IE */
    -o-transition: all 4s ease; /* opera */
    transition: all 4s ease;
}
```

所以我今天會介紹幾個最近在做side project查資料時，看到國外大佬使用的一些tips。讓我學習用現代功能編寫乾淨的CSS，同時避免3202年還在編寫意義不明的:poop:。

## :book: 學習Box Model

:::success
"學習時不要用==bootstrap==或==tailwind==這樣的框架。它們確實非常sexy，可以快速幫助你獲得一個漂亮的UI。但在你的project中用這類東西，就像結婚一樣，你不會學習到CSS基礎知識，當你主意變了，你還必須歷經離婚一般的痛苦。"  ---Fireship
:::

當你學習基本的CSS，你將更好更自由的去控制你的code。

開始說回第一個標題。關於Box Model，你可以先把每個html元素都視為一個box，每個box都有自己的寬高，你可在內壁填充去擠壓內容。外部可以添加邊框，而周邊還有個不可見的範圍叫做邊距。

CSS中與佈局和位置相關的所有內容都受到Box Model的影響，所以關於如何應用就顯得更為重要。

打開瀏覽器的開發人員選項有圖化形界面可以參考。
![](https://hackmd.io/_uploads/SkZ5KhhE2.png)

## :book: 調試時使用Firefox

Firefox的開發工具更優秀，尤其是涉及CSS時。檢查一個元素時，能像在chrome中那樣分解Box Model，列出所有屬性細目，甚至也可以直接在上面編輯屬性。
![](https://hackmd.io/_uploads/BkQdAhhV2.png)

它還在HTML中提供了有料的註釋，例如當一個元素使另一元素溢出時會有overflow標記。
![](https://hackmd.io/_uploads/HyUj46nVn.png)

它還為flex和grid提供了很好的圖形。
![](https://hackmd.io/_uploads/BkgaxH63N2.png)

## :book: Flexbox好棒棒

關於佈局和元素間的定位，歷史上一直是CSS最具挑戰性的方面之一。就像問你如何在水平和垂直方向居中一個div這種古老問題。一種方法是給child絕對定位，然後用top和left屬性把它移動到右下角，然後反向位移50%讓它回到中間。但它非常不直觀，也讓看的人也覺得很有病。
```css
.classic {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
```

使用flex就相當於給div一個x、y軸，想要置中就讓它沿著水平軸和鉛直軸對齊就好了。
```css
.flex {
    display: flex;
    justify-content: center;
    align-items: center;
}
```

雖然flex用起來挺簡便的，但如果你今天遇到一個很大還很複雜的UI，它的一個主要缺點就出來了。許多相交的行與列，會使你HTML中有很多容器或包裝元素。這些元素沒有語意意義，它們只會一直待在那裡。
```htmlmixed
<div class="row-wrapper">
    <div class="column-wrapper">
        <div class="box">💩</div>
        <div class="box">💩</div>
    </div>
    
    <div class="column-wrapper">
        <div class="box">💩</div>
        <div class="box">💩</div>
    </div>
    
    <div class="column-wrapper">
        <div class="box">💩</div>
        <div class="box">💩</div>
    </div>
</div>
```

```css
.row-wrapper {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.column-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}
```

## :book: Grid好棒棒

上述的問題，grid佈局可以幫你解決。它不像felxbox只能處理單獨的行與列。而它看起來像舊時代的表格佈局。
![](https://hackmd.io/_uploads/S1EtCThEn.png)

你若使用grid，你的code會相對友善一些。你可以將children定義為一堆列元素，行列寬度可以使用模板列屬性定義。這裡注意一下fr值，它會與grid中其它列元素共享可用空間。我們還可以定義一些行，grid內元素都將自動定位。和flexbox或table layout相比，能減少許多HTML和CSS的code數量。
```htmlmixed
<div class="grid">
    <i>😎</i>
    <i>😎</i>
    <i>😎</i>
    <i>😎</i>
    <i>😎</i>
    <i>😎</i>
</div>
```
```css
.grid {
    display: grid;
    grid-template-columns: 1fr 500px 1fr;
    grid-template-rows: 100px 200px;
    place-items: center;
}
```
![](https://hackmd.io/_uploads/BJ2HzAhE3.png)

## :book: Clamp夾爛它

前面講了一堆關於佈局和定位的東西，而當我們在實現RWD時，我們要因應用戶的設備螢幕可用空間調整畫面呈現。這時候有很多方式能做到這點。

例如你可能有一篇文章，它首選寬度為50%。但在小螢幕上，你可能會希望它寬度固定在200px。而換到大螢幕時，又希望它固定在800px。你可以透過==media query==來實現。
```css
article {
    width: 50%;
}

@media only screen and (max-width: 600px) {
    article {
        width: 200px;
    }
}

@media only screen and (max-width: 1200px) {
    article {
        width: 800px;
    }
}
```

但唯一的缺點是，==media query==會讓你在project變大時想自殺。

但好消息是你可以透過使用==min==、==max==、==clamp==之類的函數去改寫它。
```css
article {
    width: clamp(200px, 50%, 600px);
}
```

## :book: 用emoji挑戰你的同事與上司

當你的className長到你想死的時候，試試看用emoji代替。為你煩躁的一天增添些許樂趣。
![](https://hackmd.io/_uploads/ryGqvC2Vh.png)
![](https://hackmd.io/_uploads/BJlsw0243.png)

## :book: 使用Aspect Ratio

如果你曾經不得不編寫一個保持一定寬高比的RWD圖片或影片(好像有種既視感🤔，你說對吧，日程本)，這東西會make u shock😮

例如今天你想放一個16x9的影片，你可能會被迫寫出一個像這樣的鳥東西。
```css
.container-16x9 {
    position: relative;
    padding-top: 56.25%;
}

video {
    width: 100%;
    position: absolute;
    top: 0;
}
```

這時候，你可以使用==aspect-ratio==這屬性。
```css
video {
    width: 100%;
    aspect-ratio: 16/9;
}
```

但有個缺點是老地方不一定支援這屬性，這部份自己斟酌。

## :book: 創造變量

除了減少代碼量，更重要的一點是讓code更靈活，這樣在改寫和重構時才不會讓人想死。一種方式是用CSS自定義屬性和變量。像下列code中，我們在多個地方使用了相同顏色，當我們想更改顏色時，你會開始想鑽個洞把自己埋進去。
```css
p {
    color: rgb(255, 0, 0);
}

h1 {
    color: rgb(255, 0, 0);
}

h2 {
    color: rgb(255, 0, 0);
}
```

而更好的方法是在==root==選擇器上定義一個全局變量，然後在需要的地方進行引用。
```css
:root {
    --text-color: rgb(255, 0, 0);
}

p {
    color: var(--text-color);
}

h1 {
    color: var(--text-color);
}

h2 {
    color: var(--text-color);
}
```

你甚至可以在tree更深的的地方重新定義去override。
```css
:root {
    --text-color: rgb(255, 0, 0);
}

p {
    --text-color: rgb(0, 255, 0);
    color: var(--text-color);
}
```

抑或分解組合成得更細。
```css
:root {
    --r: 255;
    --g: 0;
    --b: 0;
    --text-color: rgb(var(--r), var(--g), var(--b));
}

p {
    --text-color: rgb(0, 255, 0);
    color: var(--text-color);
}
```

## :book: 花式calc

現在CSS不是傳統意義上的編程語言，但它確實能夠使用calc函數進行基本運算。了解這點的你，現在你可以快樂的和小學生一起做算術題了。
```css
calc(2px + 2px)
```

單位甚至不用相同。
```css
width: calc(100vw - 80px);
font-size: calc(1rem * 1.25);
padding: calc(5% + 2px);
```

更酷的是，你可以這樣做動畫，就能在不增加CSS代碼的情況下實現相同效果。
```htmlmixed
<style>
    .drop {
        animation: dropIn 1s ease forwards;
        animation-delay: calc(var(--order) * 100ms);
    }
    @keyframes dropIn {
        from { transform: translateY(-500px); }
        to { transform: translateY(0); }
    }
</style>
<i class="drop" style="--order: 1">1️⃣</i>
<i class="drop" style="--order: 2">2️⃣</i>
<i class="drop" style="--order: 3">3️⃣</i>
```

## :book: 狀態管理計數器

雖然剛才說CSS不是一種編程語言，但它實際上有一個內置的狀態管理機制，你可以追蹤你code中的運行記數，而不用多編寫一行JavaScript。

若你想對標題進行編號，最白癡的方法就長這樣。
```htmlmixed
<h1> 1. apple </h1>
<h1> 2. bird </h1>
<h1> 3. dog </h1>
```

當你突然想要從中間補上一個新的標題時，就會有種想去頂樓自由落體的感覺。
```htmlmixed
<h1> 1. apple </h1>
<h1> 2. bird </h1>
<h1> 3. cat </h1>   ←←←←←←←←←←←←←←
<h1> 3. dog </h1>
```

聰明的方法是去root創建一個計數器，用==counter-reset==給一個你喜歡的名字，然後在需要應用的地方去用==counter-increment==遞增它，它將從0開始將1添加到dom的每個h1元素。
```css
:root {
    counter-reset: headings;
}

h1 {
    counter-increment: headings;
}

h1::before {
    content: counter(headings);
}
```

## :book: focus-within的魔力

構建複雜下拉式選單時，你可能會認為這必須涉及一些JavaScript來管理選單的開啟和關閉state，但你可能也會想你若只透過純CSS可以做到多遠。

大家都很熟悉==focus==這偽類，當你進行表單輸入或單擊按鈕時，該偽類會應用於元素上。問題是，在構建下拉式選單時，你可能會使用==focus==打開選單，但當你點擊選單內的某個內容時，它會失去焦點並關閉。這就為何你會使用JavaScript去管理state。

但有趣的是，有個偽類叫做==focus-within==，如果任何children也有這偽類，它就會保持active的狀態。

這樣簡單的一個功能，可以多減少幾行用於管理打開和關閉state的JavaScript代碼。
```css
.dropdown {
    opacity: 0;
    visibility: hidden;
}

button:focus-withing .dropdown {
    opacity: 1;
    visibility: visible;
}
```

## :book: 結語

這樣，我們就簡單提完了幾個CSS技巧。還記的剛開頭提到的瀏覽器供應商前綴嗎，那東西就像皰疹一樣不會消失。但幸運的是我們有些有料的小工具可以讓它變得不成問題。

其中一個工具就是==PostCSS==(看起來像光明會來的)，它使用一個叫做auto prefixer的工具，來自動添加所有供應商前綴。此外，它還允許你使用現代CSS功能，會幫你自動轉換代碼，以盡可能讓所有目標瀏覽器都支援。你還可以去看看==Sass==、==stylus==、==less==等預處理器。之後有緣再分享。
![](https://hackmd.io/_uploads/H1FmMgpVn.png)
