# 語意化樣式 追求語意化、可擴充性的撰寫樣式。 ## 從命名開始 在一個 HTML 元素上,我們將會替元素的 `id`、`class` 屬性加上各種名稱,分為以下幾種: ### 模組命名 > 名其所圖 模組要是功能的說明,應為單一,通常是抽象名詞,比如像是 `#user-register`、`#product-management` 等。 應避免混雜畫面的資訊在其中,如下: - `#user-register-form`,應改為 `#user-register`,假設存在於該功能為名的路徑,可以考慮使用 `#main` 作為名稱。 ### 元件命名 > 名其所見 元件要是個實體名詞,比如像是 `.button`、`.form` 等。 應避免混雜功能與特徵在其中,如下: - `.user-register-form`,視情況應改為:`.form`、`.form.for-user-register` (適用存在特殊樣式、功能時) - `.large-button`,應改為:`.large.button` ### 子元件命名 > 名其所屬 子元件大致與元件相同,唯一不同之處在於,子元件無法單獨存在與使用,必須歸屬於該元件之下,因此,需加上該元件的前綴,如 `.table-row`、`.header-bar` 等。 應避免不必要的子元件命名發生,如下: - `.table-row-col`,應改為:`.table-col` ### 變體命名 > 名其所形 變體涵蓋了狀態與外觀的變化,通常是個形容詞抑或抽象名詞,比如像是 `.animated`、`.error` 等。 若含有其他實體名詞時,則可採用 `-` 後綴進行表達,如 `.menu-.icon`,藉此避免與[元件命名](#元件命名)可能發生的衝突。 應避免過於精簡的描述,如下: - `.left`,視情況應改為: `.left-text-aligned` (指元件中的文字對齊靠左)、`.is-left-aligned` (子項靠左對齊) ### 響應式變體命名 > 名其所適 使用大小代號命名 `xxs`、`xs`、`sm`、`md`、`lg`、`xl`、`xxl`。 - `-on-{size}` 後綴:僅適用於該斷點 - `-on-{size}-to-{size}` 後綴:適用於該斷點以上,到特定斷點為止 - `-on-{size}-or-above` 後綴:適用於該斷點以上 - `-on-{size}-or-below` 後綴:適用於該斷點以下,不鼓勵使用 ### 特殊命名 > 名其所殊 特殊命名不得獨立撰寫樣式,應搭配元件,作為額外的說明。 - `as-` 前綴:視為特定元件,主要用於供容器辨識。 - 如:`.card > .card-body` 透過增加 `.card > .as-card-body`,讓 `.carousel.as-card-body` 能被視為 `.card-body` 而被排版。 - `for-` 前綴:描述用途或功能,可用於容器辨識或改變自身排版。如:`.form.for-register` - `is-` 前綴:描述特徵,主要用於供容器辨識。 - 如:`.form > .primary.button` 透過增加 `.form > .button.is-primary`,讓 `.secondary.button.is-primary` 能夠如同 `.primary.button` 被排版。 - `in-` 前綴:在特定容器中。主要用於改變自身排版,如:`.carousel.in-card`,在和[響應式變體命名](#響應式變體命名)組合使用時,會是:`.in-card-on-sm-or-below` ## 撰寫樣式 ### 選擇器 > 各司其職 建議都使用子項選擇器 `>`,能夠有效的避免污染的發生。 例如: ```css .cards .button /* 載入卡片按鈕 */ { margin-left: auto; /* 我想按鈕要靠右邊 */ } .card .button /* 卡片內文按鈕 */ { margin-right: auto; /* 我想按鈕要靠左邊 */ } ``` 對應畫面的結構通常會是這樣: ```xml <div class="cards"> <button class="button">more</button> <div class="card"> <button class="button">detail</button> </div> ... </div> ``` 因此實際上,卡片內文按鈕會在中間,而不是在左邊。因為該也符合 `.cards .button` 理想的方式: ```css .cards > .button /* 載入卡片按鈕 */ { margin-left: auto; /* 我想按鈕要靠右邊 */ } .card > .button /* 卡片內文按鈕 */ { margin-right: auto; /* 我想按鈕要靠左邊 */ } ``` ### 響應式 > 涇渭分明 排版方式不同時,建議使用嚴格斷點,能夠有效的避免污染的發生。 發現需要過多的覆蓋樣式時(如:`margin-top` 改回 `0px`,需要 `unset` 等),建議直接使用嚴格斷點進行區分。 ```css /* 在小螢幕要疊起來用滑動的 */ @media (max-width: 767.98px) { .cards.for-recommendation { position: relative; } .cards.for-recommendation > * { position: absolute; } .cards.for-recommendation > .cards-arrow { top: 50%; transform: translateY(-50%); } .cards.for-recommendation > .cards-arrow.is-left { left: 0; } .cards.for-recommendation > .cards-arrow.is-right { right: 0; } } /* 在中螢幕顯示一部分,另一部分透過按鈕來展開 */ @media (min-width: 768px) and (max-width: 1279.98px) { .cards.for-recommendation { height: var(--cards-height); } .expanded.cards.for-recommendation { height: var(--expanded-cards-height); } } /* 中螢幕、大螢幕都是彈性排版,不推薦簡寫成中螢幕以上 */ @media (min-width: 768px) and (max-width: 1279.98px), (min-width: 1280px) { .cards.for-recommendation { display: flex; align-items: center; justify-content: space-between; } .cards.for-recommendation > .cards-arrow { display: none; } } /* 小螢幕、大螢幕都沒有展開按鈕 */ @media (max-width: 767.97px), (min-width: 1280px) { .cards.for-recommendation > .button.for-expanding { display: none; } } ``` ### 排版思路 > 適得其所 我們不應該假設任何的元件或子元件自身的位置,因此我們應該要避免在單純的元件上直接那麼撰寫樣式。 我們很容易寫出這樣的樣式: ```css .button { margin-left: auto; /* 按鈕通常都置中吧 */ margin-right: auto; } ``` 但實際上使用時: ```css .form > .button.for-submit { margin-right: unset; /* 並沒有,按鈕要靠右邊,用起來真不直觀 */ } ``` 理想的過程: ```css .button { /* 按鈕不知道會擺哪,也不知道會多大 */ } ``` ```css .form > .button.for-submit { margin-left: auto; /* 表單中,供送出的按鈕會靠右邊 */ } ``` 避免使用如 `top`、`left`、`bottom`、`right`、`margin`、`transform` 等會使位置在預設情況下不符預期的樣式。 追求元件可以在任何大小下有著一個理想的樣子,如被設定 `width`、`height`、`font-size` 時,能夠使內容等比例的縮放或位移。 ### 分層處理 > 層層有別 我們通常會寫出這樣的樣式: ```css .button { transition: transform 400ms; } .button:active { transform: scale(0.8); /* 按下的時候會有些反應 */ } ``` 但實際上使用時: ```css .form > .button.for-submit { transform: translateX(50%); /* 是沒錯,但是我要保持移動啊 */ } ``` 通常會想的解決方法也許是: ```css .form > .button.for-submit:active { transform: translateX(50%) scale(0.8); /* 把原本的樣式也加上位移就好啦 */ } ``` 不過... ```css .button:active { transform: scale(0.6); /* 啊,縮放 0.6 不錯 */ } ``` 然後我們就很有可能忘記要改變 `.form` 裡面的部分 解決方式: ```xml <form class="form"> <div class="form-button-wrapper as-button for-submit"> <button class="button"></button> </div> </form> ``` ```css .form > .as-button.for-submit, /* 排版兼容類別 `.as-button` */ .form > .button.for-submit { transform: translateX(50%); } .form-button-wrapper.for-submit > .button { /* 原有的 button 大小對應等處理 */ } ``` 得益於[排版思路](#排版思路),對於 `.form` 來說,他只負責將 `.button` 或 `.as-button` 進行排版,不知道裡頭具體有什麼差別。 因此我們可以透過在 `.button` 外面包覆一層,將會混在一起的效果分離撰寫,如 `transform`、`transition`、`animation` 等。 ### 變體應用 > 森羅萬象 透過父項與子項的變體表達,使排版能夠多元的實現。 ```css .form > .primary.button /* 預設情況下,主要按鈕靠右邊 */ { order: 1; } .form > .as-button.is-primary, /* 作為主要按鈕,更靠右邊 */ .form > .button.is-primary /* 為主要按鈕,更靠右邊 */ { order: 2; } .form > .as-button.is-primary, /* 作為特殊按鈕,再更靠右邊 */ .form > .button.for-special /* 為特殊按鈕,再更靠右邊 */ { order: 3; } .button-order-reversed.form > .primary.button /* 按鈕排序反向表單,主要按鈕靠左邊 */ { order: -1; } .button-order-reversed.form > .as-button.is-primary, /* 按鈕排序反向表單,作為主要按鈕,更靠左邊 */ .button-order-reversed.form > .button.is-primary /* 按鈕排序反向表單,為主要按鈕,更靠左邊 */ { order: -2; } .button-order-reversed.form > .as-button.is-primary, /* 按鈕排序反向表單,作為特殊按鈕,再更靠左邊 */ .button-order-reversed.form > .button.for-special /* 按鈕排序反向表單,為特殊按鈕,再更靠左邊 */ { order: -3; } ``` 雖說如此,但在構思元件的排版時,應盡可能確保其泛用性,避免不必要的樣式覆蓋不斷產生。 ### 善用變數 > 去其糟粕 有些變體可能只是一小部分的變動,卻總是額外寫了很多的樣式程式碼。 可參考[變體應用](#變體應用)中的程式碼,採用變數達到一定簡化: ```css .form { /* 1 靠右、-1 靠左、0 取消,預設為 1 */ --button-in-form-order: 1; } .form > .primary.button { order: var(--button-in-form-order); } .form > .as-button.is-primary, .form > .button.is-primary { order: calc(var(--button-in-form-order) * 2); } .form > .as-button.is-primary, .form > .button.for-special { order: calc(var(--button-in-form-order) * 3); } .button-order-reversed.form { --button-in-form-order: -1; } ``` 比較之下可以發現,使用變數後,變體樣式的部分僅有 `.button-order-reversed.form`,而不需要以此再替 `.button, .as-button` 額外撰寫樣式。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up