Try   HackMD

CSS 專家密技 - CSS Protips

竹白筆記本,學習筆記,2019/03/21

tags: CSS 專家密技 CSS Protips

CSS 專家密技
CSS專家密技3 - CSS Protips - 阿莫斯の網頁料理室


1. 使用 CSS Reset

CSS Reset 可以幫你在不同的瀏覽器上維持一致的樣式風格。

幾套常見的 CSS Reset:

因為 reset.css 重置了各個瀏覽器的樣式設定,使得有些有用、常用標籤的默認樣式必須要重新設定,因為這個問題,有人開發出了 Normalize.css

在 Normalize.css 的官方頁面上點出了他們的目標:

  • 保留有用的瀏覽器默認設置,而不是將其刪除。
  • 為廣泛的 HTML 元素提供一般化的樣式。
  • 修正瀏覽器的 Bug 與不一致。
  • 透過微妙的改善提高可用性。
  • 有詳細的文檔來解釋代碼。(每個樣式都有註解是處理什麼問題。)

最大的特色就是保留原本預設 HTML 標籤的樣式,僅針對不同瀏覽器與各版本間不相容的標籤進行些微調整。

更簡潔的 CSS Reset 方法:

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

2. 繼承 box-sizing

一般使用 box-sizing 都是:

*, *::before, *::after {
  box-sizing: border-box;
}

但假設今天有一個元件是使用 box-sizing: content-box;

.component {
  box-sizing: content-box;
}

元件中的其他子元素也要是 content-box,但使用第一種方法設定 box-sizing 會影響到。

所以讓 box-sizing 屬性自動從 html 元素繼承下來 :

html {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

如此一來,你就很容易的在其他外掛或元件裡改變 box-sizing 的值。


3. 使用 unset 而不是重置所有屬性

unset 從其父級繼承,則將該屬性重新設置為繼承的值,如果沒有繼承父級樣式,則將該屬性重新設置為初始值。

  • 如果該屬性是默認繼承屬性,該值等同於 inherit
  • 如果該屬性是非繼承屬性,該值等同於 initial

舉個例子,先列舉一些 CSS 中默認繼承父級樣式的屬性:

  • 部分可繼承樣式:font-size, font-family, color, text-indent
  • 部分不可繼承樣式:border, padding, margin, width, height

all: unset; 將元素中所有樣式屬性回復到預設值:

button {
  all: unset;
}

all|MDN


4. 使用 :not() 選擇器來決定表單是否顯示邊框

假設你用以下樣式先替元素新增邊框

/* 新增邊框 */
.nav li {
  border-right: 1px solid #666;
}

然後在最後一個元素去除邊框

/* 去掉邊框 */
.nav li:last-child {
  border-right: none;
}

不過你可以改用 :not() 偽類別 (pseudo-class) 來做到完全相同的效果:

.nav li:not(:last-child) {
  border-right: 1px solid #666;
}

當然,你也可以用 .nav li + li,但是使用 :not() 可以使語句更加清晰,更具可讀性。

CodePen::not 選擇器


5. 將 line-height 加入到 body 元素

你不必為分別為每一個 <p><h*> 元素加入 line-height 樣式,相反的,你應該直接新增到 body 元素:

body {
  line-height: 1.5;
}

所有的文字元素預設就會繼承 body 的樣式。


6. 為表單元素設置 focus

給予使用者回饋,讓使用者可以距焦、確定所在位置。

a:focus,
button:focus,
input:focus,
select:focus,
textarea:focus {
  box-shadow: none;
  outline: #000 dotted 2px;
  outline-offset: .05em;
}

CodePen:Search Box

focus 在超連結中

考量到 CSS 的優先權,在超連結中要註意擺放順序,由上而下依序為:

a:link {}
a:visited {}
a:focus {}
a:hover {}
a:active {}

7. 將所有元素設定垂直居中

此處有問題,故跳過。

CSS 垂直置中技巧 23 招


8. 逗號分隔列表

使列表的每項都由逗號分隔:

ul > li:not(:last-child)::after {
  content: ',';
}

列表中最後一項不用加逗號,所以可以使用 :not() 偽類別 (pseudo-class)。


9. 使用負數的 nth-child 來選擇元素

CSS3 :nth-child(n) 選取器教學

使用負數的 nth-child 可以選擇 1 至 n 個元素。

li {
  display: none;
}

/* 選擇第 1 至第 3 個元素並顯示出來 */
li:nth-child(-n+3) {
  display: block;
}

或者使用 :not() 選擇器來決定表單是否顯示邊框:

/* 選擇除了前 3 個之外的所有項目,並顯示出來 */
li:not(:nth-child(-n + 3)) {
  display: none;
}

10. 使用 SVG 圖示

SVG 在所有解析度下都可以良好縮放,並且支援 IE9 之後的所有瀏覽器。

注意: 如果你有一個只用 SVG 圖示的按鈕,只給看的見的人來點選。當 SVG 無法載入的時候,以下樣式可以幫助你維持網頁的可及性(Accessibility):

.no-svg .icon-only::after {
  content: attr(aria-label);
}

attr()|MDN


11. 貓頭鷹 選擇器

Lobotomized Owl(貓頭鷹)

* + * {
  margin-top: 1.5em;
}

在此範例中,在文件中所有的元素,只要緊接著其他元素,就會套用一個 margin-top: 1.5em 樣式。

效能不好,不建議使用。


12. 使用 max-height 來建立純 CSS 的捲動軸

你可以透過 max-heightoverflow-y: hidden 來實作出 CSS-only 的捲動軸:

.slider {
  max-height: 200px;
  overflow-y: hidden;
  width: 300px;
}

.slider:hover {
  max-height: 600px;
  overflow-y: scroll;
}

當滑鼠移到 .slider 的元素時,元素的內容如果過多,最大高度只會擴展到 max-height 的值,而且會自動顯示捲動軸。

CodePen:建立純 CSS 的捲動軸

此方法有個缺點,因為需要鼠標移過去才會顯示卷軸,使用者會不知道此處可以捲動,所以需要額外增加提示。


13. 讓表格中每個儲存格維持等寬

表格中要維持每一格都等寬是一件痛苦的是,所以你應該嘗試用 table-layout: fixed 來讓所有儲存格維持等寬:

.calendar {
  table-layout: fixed;
}

CodePen:Equal-Width Table Cells


14. 利用 Flexbox 去除多餘的 Margin 技巧

排版的時候,為了設計出每一欄的間隙(gutters),一般都會用到像是 nth-first-last-child 的技巧,來去除頭尾多餘的間隙,不如使用 Flexbox 的 space-between 屬性:

.list {
  display: flex;
  justify-content: space-between;
}

.list .person {
  flex-basis: 23%;
}

15. 利用屬性選擇器填滿空白連結的文字內容

<a> 元素沒有文字內容,但有 href 屬性的時候,可以這樣做:

a[href^='http']:empty::before {
  content: attr(href);
}

:empty 代表沒有子元素的元素。子元素只可以是元素節點或文本(包括空格)。

CodePen:Use Attribute Selectors with Empty Links

16. 幫沒有類別的連結設定一個預設樣式

幫沒有套用 class 的超連結設定一個預設樣式:

a[href]:not([class]) {
  color: #008000;
  text-decoration: underline;
}

使用者透過後台 CMS 系統插入的超連結通常沒有 class 屬性,以上樣式可以針對這些超連結進行設定,且不會影響其它樣式定義。

17. 一致的垂直韻律

在元素中使用 通用選擇器 *,可以確保一致的垂直韻律 (consistent vertical rhythm):

.intro > * {
  margin-bottom: 1.25rem;
}

一致的垂直韻律可以提供視覺美感,並且讓內容更具可讀性。

沒啥用的技巧

18. 等比例的方塊(RWD 相關)

要建立一個固定比例的方塊(Box),你需要的就是將 padding-toppadding-bottom 設定到 <div> 元素:

.container {
  height: 0;
  padding-bottom: 20%;
  position: relative;
}

.container div {
  border: 2px dashed #ddd;
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}

padding-bottom 設定 20% 意味著各個 div 方塊的高度等同於 20% 的寬度。無論 Viewport 現在的寬度多少,子元素的 div 將維持其寬高比(100% / 20% = 5:1)。

CodePen:Intrinsic Ratio Boxes

19. 為破圖定義樣式

只要一點 CSS 就可以美化所有破圖:

img {
  display: block;
  font-family: Helvetica, Arial, sans-serif;
  font-weight: 300;
  height: auto;
  line-height: 2;
  position: relative;
  text-align: center;
  width: 100%;
}

接著新增一個 偽元素規則(pseudo-elements rules)來顯示使用者訊息,以及這張破圖的 URL 參考:

img::before {
  content: "We're sorry, the image below is broken :(";
  display: block;
  margin-bottom: 10px;
}

img::after {
  content: '(url: ' attr(src) ')';
  display: block;
  font-size: 12px;
}

想學習更多這類樣式技巧,可以參考 Ire Aderinokun原始文章

20. 用 rem 來調整全域大小;用 em 來調整區域大小

在根元素設定基礎字體大小後(html { font-size: 100%; }), 使用 em 設定文字元素的字體大小:

h2 {
  font-size: 2em;
}

p {
  font-size: 1em;
}

然後設定模組的字體大小為 rem

article {
  font-size: 1.25rem;
}

aside .module {
  font-size: 0.9rem;
}

現在,每個模組變得獨立,更容易、靈活的樣式便於維護。

CSS 中的 EM REM PX 解析與運用|六角學院

21. 隱藏沒有靜音並設定自動播放的影片

當你在一個可以自訂樣式的後台環境設定網站樣式時,這是一個不錯的小技巧。畢竟自動撥放影片是蠻惱人的,這個技巧可以幫助你避免影片在沒有靜音的情況下自動撥放。

video[autoplay]:not([muted]) {
  display: none;
}

22. 使用 :root 選擇器來設定彈性的字體大小

在響應式版面(responsive layout)中,字體大小通常需要根據不同的 Viewport(畫面大小)進行調整。你可以根據 :root 所定義的 Viewport 高度與寬度來調整字體大小:

:root {
  font-size: calc(1vw + 1vh + 0.5vmin);
}

現在你便能使用依 :root 字級為基準的 rem 單位了。

body {
  font: 1rem/1.6 sans-serif;
}

CodePen:Use :root for Flexible Type

23. 為了更好的行動體驗來設定表單元素的 font-size

為了避免使用者在行動瀏覽器(iOS Safari, 等等)點擊 <select> 的下拉選單時在 HTML 表單元素進行縮放,你可以加上font-size 到這些選取器樣式規則:

input[type='text'],
input[type='number'],
select,
textarea {
  font-size: 16px;
}

24. 使用 pointer-events 控制鼠標事件

pointer-events 允許您指定鼠標如何與其觸摸的元素進行交互。要禁用按鈕上的默認指針事件,例如:

.button-disabled {
  opacity: .5;
  pointer-events: none;
}