前言
在這篇文章我會介紹 9 個使你的 CSS 更加簡潔優雅的使用技巧。這些技巧小生經常使用,覺得挺高效實用,所以也就有了這篇文章。
9 個 CSS 技巧
特此宣告,這裡說的 CSS 並不止包含 CSS,也包含 CSS 前處理器(Less Sass 等),願各位看官不要糾結於此。
正文現在開始。
1. 建議使用 padding 代替 margin
我們在設計稿還原的時候,padding
和 margin
兩個是常用的屬性,但我們知道屬於同一個 BFC 的兩個相鄰 Box 的 margin 會發生重疊,所以如果 margin
使用的過於頻繁的時候,Box 的垂直距離可能就會發生重疊。
還有一個問題就是第一個子元素的 margin-top
值會加在父元素上的 bug(最後一個子元素的 margin-bottom
也存在類似的問題)。這裡是不是有人問為什麼呢?
原因就在於:
the expression collapsing margins means that adjoining margins (no non-empty content, padding or border areas or clearance separate them) of two or more boxes (which may be next to one another or nested) combine to form a single margin.
翻譯過來就是:
所有毗鄰的兩個或多個盒元素的
margin
將會合併為一個margin
共享。 毗鄰的定義為:同級或者巢狀的盒元素,並且它們之間沒有非空內容、Padding
或Border
分隔。
至於為什麼合併我個人覺得這和排隊的安全距離有點類似,人與人之間的安全距離是 1m,如果安全距離不合並,那麼我們在排隊的時候是不是人與人的距離就變成 2m 了。當然很可能不是這個原因。
所以我們可以在首位元素使用 padding
來替代 margin
。當然有的時候使用 padding
不能滿足需求,這時你也可以在“非空內容”這個條件做文章。即在父元素新增一個偽元素。
所以我們在使用
margin
的時候一定要注意 collapsing margins 問題。
2. position:fixed 降級問題
不知道曾經的你是不是遇到吸頂效果,就是使用 position:fixed
這個屬性。其實如果其父元素中有使用 transform
,fixed
的效果會降級為 absolute
。
解決方案:
既然會降級為 absolute
效果,我們該怎麼解決這個問題呢?我們就改考慮什麼情況下 fixed
和 absolute
的表現效果會是一樣的。
即當使用 fixed
的直接父元素的高度和螢幕的高度相同時 fixed
和 absolute
的表現效果會是一樣的。
如果這個直接父級內的元素存在滾動的情況,那就加上
overflow-y: auto
。
3. 合理使用 px | em | rem | % 等單位
在 CSS 中有許多距離單位,比如 px | em | rem | %,還有 CSS3 中的 vh | vw 等單位。
那麼我們在專案中應該如何使用呢?我們在 pc 端不需要考慮的這麼複雜,所以這裡我們主要講講這些單位在移動端中的使用。
基礎單位 px
px 是我們最早接觸到的單位了,不過我們在移動端自適應的要求下,使用的頻率不是很高;我總結了以下使用的情況:
比較小的圖案
比如需要我們畫一個 r 為 5px 的圓,如果我們使用 rem 作為單位,我們很快會發現在一些機型上的圖案不圓,會呈現橢圓形。這是由於 rem 轉 px 會存在精度丟失問題。
所以這個時候我們就需要使用 px 配合 dpr 來實現:
// less
/*@size 建議取雙數*/
.circle(@size, @backgroundColor) {
width: @size;
height: @size;
background-color: @backgroundColor;
[data-dpr="1"] & {
width: @size * 0.5;
height: @size * 0.5;
}
[data-dpr="3"] & {
width: @size * 1.5;
height: @size * 1.5;
}
}
複製程式碼
1px 細線問題
這個問題下面我會單獨做一小節講,在這裡就不累述。
字型大小(基本都是用 rem 作為單位)
一般情況字型的大小我也會使用 rem 作為單位,因為精度丟失我認為在可以接受的範圍之內。
相對單位 rem
rem 是 CSS3 新增的一個相對單位(root em),即相對 HTML 根元素的字型大小的值。
rem 應該是自適應使用的最廣泛的單位了。
相對單位 em
em 也是一個相對單位,卻是相對於當前物件內文字的字型大小。
line-height
一般建議在 line-height
使用 em。因為在需要調整字型大小的時候,只需修改 font-size
的值,而 line-height
已經設定成了相對行高了。
首行縮排兩個字元
在存在首行縮排的需求,我也會使用這個單位。
text-indent: 2em
複製程式碼
視口單位 vw | vh
vw: 1vw = 視口寬度的 1%
vh: 1vh = 視口高度的 1%
我們知道以 rem 單位設計的彈性佈局,是需要在頭部載入一段指令碼來進行監聽解析度的變化來動態改變根元素字型大小,使得 CSS 與 JS 耦合了在一起。
那麼有沒有方案解決這個耦合的問題呢?
答案就是視口單位 vw | vh。
以下就是前人給出的使用方案:
$vm_fontsize: 75;
@function rem($px) {
@return ($px / $vm_fontsize ) * 1rem;
}
$vm_design: 750;
html {
font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw;
@media screen and (max-width: 320px) {
font-size: 64px;
}
@media screen and (min-width: 540px) {
font-size: 108px;
}
}
// body 也增加最大最小寬度限制,避免預設100%寬度的 block 元素跟隨 body 而過大過小
body {
max-width: 540px;
min-width: 320px;
}
複製程式碼
4. 合理使用變數
一般設計稿中的某一類的文字(元素)都是用相同的字型大小、顏色、行高等樣式屬性,所以這些值我們不必每次都重複寫,因為當 UI 更新設計方案,你需要改的地方就很多了。這些重複使用的值我們完全可以存放在變數裡面。
Sass 和 Less 稍微有點區別:
// sass
$direction: left;
// less
@direction: left;
複製程式碼
當然 CSS 原生也是存在變數的,使用規則如下:
變數定義的語法是: --*; // 為變數名稱。
變數使用的語法是:var();
- 無論是變數的定義和使用只能在宣告塊 {} 裡面
- CSS 變數字元限制為: [0-9]、[a-zA-Z]、_、-、中文和韓文等。
:root {
--blue_color: #3388ff;
--main_bgcolor: #fafafa;
--font_size_12: 12px;
--font_size_14: 14px;
--color: 20px;
}
.div1{
background-color: var(--main_bgcolor);
font-size: var(--font_size_12);
}
複製程式碼
5. 使用 Mixin 歸類重複樣式
和重複變數一樣,重複的樣式也可以歸類。我覺得優秀的程式碼其中有一條肯定是程式碼的複用性強。
之前我們寫 CSS 的時候,也會將一些重複使用的程式碼放在一個 class 中,這樣的確達到了一定的複用性,不過最後的效果可能就是在一個元素裡面放了很多 class,如下圖:
這樣下一個接手得人難免會有點迷糊,而且這樣會造成樣式越來越難修改。
這個時候,mixin( 可以理解成 class 中的 class )就能發揮它的作用了。
這是一個描述性文字的樣式:
.font-description {
.font-des-style(24px,#fff,1.5em);
.line-camp(2);
}
// less
/* 多行顯示 */
.line-camp( @clamp:2 ) {
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: @clamp;
-webkit-box-orient: vertical;
}
.font-des-style( @fontSize, @color, @lineHeight, @textAlign:left ) {
font-size: @fontSize;
color: @color;
line-height: @lineHeight;
text-align: @textAlign;
}
複製程式碼
這只是一個簡單的例子,我們可以把可複用的樣式放在 mixin 中,這樣接手專案的人只需要熟悉你寫的 mixin.less 就可以開始迭代需求了。
6. 1px 方案
做過移動端需求的前端肯定是避免不了處理 1px
細線問題,這個問題的原因就是 UI 對頁面美觀度的要求越來越高(不要和我說這是 retina 屏的問題)。
據小生所知好像沒有什麼相容性特別好的方案,這裡我只是提供兩種種相對較好的方案。
使用偽類 + transform
.border_bottom {
overflow: hidden;
position: relative;
border: none!important;
}
.border_bottom:after {
content: ".";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 1px;
background-color: #d4d6d7;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
複製程式碼
當然這個方案在一些版本較低的機型也是會出現粗細不均、細線消失斷裂的相容性問題。不過現在在已經 2019 年了,版本較低的機型也淘汰的差不多了。
使用 box-shadow 模擬
.border_bottom {
box-shadow: inset 0px -1px 1px -1px #d4d6d7;
}
複製程式碼
這個方案基本可以滿足所有場景,不過有個缺點也就是顏色會變淺。
多謝 D文斌 分享的另一種方案: 這種方案對 dpr 做了不同的處理,可謂更加精細。
.min-device-pixel-ratio(@scale2, @scale3) {
@media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
transform: @scale2;
}
@media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
transform: @scale3;
}
}
.border-1px(@color: #DDD, @radius: 2PX, @style: solid) {
&::before {
content: "";
pointer-events: none;
display: block;
position: absolute;
left: 0;
top: 0;
transform-origin: 0 0;
border: 1PX @style @color;
border-radius: @radius;
box-sizing: border-box;
width: 100%;
height: 100%;
@media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
width: 200%;
height: 200%;
border-radius: @radius * 2;
transform: scale(.5);
}
@media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
width: 300%;
height: 300%;
border-radius: @radius * 3;
transform: scale(.33);
}
}
}
.border-top-1px(@color: #DDD, @style: solid) {
&::before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
border-top: 1Px @style @color;
transform-origin: 0 0;
.min-device-pixel-ratio(scaleY(.5), scaleY(.33));
}
}
複製程式碼
7. 從 html 元素繼承 box-sizing
在大多數情況下我們在設定元素的 border
和 padding
並不希望改變元素的 width,height
值,這個時候我們就可以為該元素設定 box-sizing:border-box;
。
我不希望每次都重寫一遍,而是希望他是繼承而來的,那麼我們可以使用如下程式碼:
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
複製程式碼
這樣的好處在於他不會覆蓋其他元件的 box-sizing
值,又無需為每一個元素重複設定 box-sizing: border-box;
。
8. 內聯首屏關鍵 CSS
效能優化中有一個重要的指標 —— 首次有效繪製(FMP),即指頁面的首要內容(primary content)出現在螢幕上的時間。這一指標影響使用者看到頁面前所需等待的時間,而 內聯首屏關鍵 CSS(即 Critical CSS,可以稱之為首屏關鍵 CSS) 能給使用者一個更好的心理預期。
如圖:
我們知道內聯 CSS 能夠使瀏覽器開始頁面渲染的時間提前,即在 HTML 下載完成之後就能渲染了。
既然是內聯關鍵 CSS,也就說明我們只會將少部分的 CSS 程式碼直接寫入 HTML 中。至於內聯哪些 CSS 你可以使用 Critical。
9. 文字超出省略、文字兩端對齊
需求中我們也經常遇到這樣的需求,這裡直接提供方案。
超出省略
.line-camp( @clamp:2 ) {
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: @clamp;
-webkit-box-orient: vertical;
}
複製程式碼
所遇到的問題:
-webkit-box-orient: vertical
在使用 webpack 打包的時候這段程式碼會被刪除掉,原因是optimize-css-assets-webpack-plugin
這個外掛的問題。
解決方案:
可以使用如下的寫法:
.line-camp( @clamp:2 ) {
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: @clamp;
/*! autoprefixer: off */
-webkit-box-orient: vertical;
/* autoprefixer: on */
}
複製程式碼
兩端對齊
// html
<div>姓名</div>
<div>手機號碼</div>
<div>賬號</div>
<div>密碼</div>
// css
div {
margin: 10px 0;
width: 100px;
border: 1px solid red;
text-align: justify;
text-align-last:justify
}
div:after{
content: '';
display: inline-block;
width: 100%;
}
複製程式碼
效果如下:
前端詞典系列
《前端詞典》這個系列會持續更新,每一期我都會講一個出現頻率較高的知識點。希望大家在閱讀的過程當中可以斧正文中出現不嚴謹或是錯誤的地方,本人將不勝感激;若通過本系列而有所得,本人亦將不勝欣喜。
如果你覺得我的文章寫的還不錯,可以關注我的微信公眾號,公眾號裡會提前劇透呦。
你也可以新增我的微信 wqhhsd, 歡迎交流。
下期預告
在接下來的幾篇文章中我會介紹 Vue 相關