前言
做過前端的都知道,我們調(diào)試css往往是這樣的:

所以這篇文章我會介紹 9 個使你的 CSS 更加簡潔優(yōu)雅的使用技巧,幫你搞定一些css難題。
本文修改自公眾號小生方勤的文章
9 個 CSS 技巧
特此聲明,這里說的 CSS 并不止包含 CSS,也包含 CSS 預處理器(Less Sass 等),愿各位看官不要糾結(jié)于此。
正文現(xiàn)在開始。
1. 盡量使用 padding 代替 margin
我們在設(shè)計稿還原的時候, padding 和 margin 兩個是常用的屬性,但我們知道屬于同一個 BFC 的兩個相鄰 Box 的 margin 會發(fā)生重疊,所以如果 margin 使用的過于頻繁的時候,Box 的垂直距離可能就會發(fā)生重疊。
還有一個問題就是第一個子元素的 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共享。 毗鄰的定義為:同級或者嵌套的盒元素,并且它們之間沒有非空內(nèi)容、Padding或Border分隔。
至于為什么合并我個人覺得這和排隊取款的安全距離有點類似,人與人之間的安全距離是 1m,如果安全距離不合并,那么我們在排隊的時候是不是人與人的距離就變成 2m 了。當然很可能不是這個原因。
所以我們可以在首位元素使用 padding 來替代 margin。當然有的時候使用 padding 不能滿足需求,這時你也可以在“非空內(nèi)容”這個條件做文章。即在父元素添加一個偽元素。
所以我們在使用
margin的時候一定要注意 collapsing margins 問題。
2. position:fixed 降級問題
不知道曾經(jīng)的你是不是遇到吸頂效果,就是使用 position:fixed 這個屬性。其實如果其父元素中有使用 transform, fixed 的效果會降級為 absolute。
解決方案:
既然會降級為 absolute 效果,我們該怎么解決這個問題呢?我們就改考慮什么情況下 fixed和 absolute 的表現(xiàn)效果會是一樣的。
即當使用 fixed 元素的直接父元素的高度和屏幕的高度相同時 fixed 和 absolute 的表現(xiàn)效果會是一樣的。
如果這個直接父級內(nèi)的元素存在滾動的情況,那就加上
overflow-y:auto。
3. 合理使用 px | em | rem | % 等單位
在 CSS 中有許多距離單位,比如 px | em | rem | %,還有 CSS3 中的 vh | vw 等單位。
那么我們在項目中應(yīng)該如何使用呢?我們在 pc 端不需要考慮的這么復雜,所以這里我們主要講講這些單位在移動端中的使用。
基礎(chǔ)單位 px
px 是我們最早接觸到的單位了,不過我們在移動端自適應(yīng)的要求下,使用的頻率不是很高;我總結(jié)了以下使用的情況:
比較小的圖案
比如需要我們畫一個 r 為 5px 的圓,如果我們使用 rem 作為單位,我們很快會發(fā)現(xiàn)在一些機型上的圖案不圓,會呈現(xiàn)橢圓形。這是由于 rem 轉(zhuǎn) px 會存在精度丟失問題。
所以這個時候我們就需要使用 px 配合 dpr 來實現(xiàn):
// less
/*@size 建議取雙數(shù)*/
.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 細線問題
這個問題下面我會單獨做一小節(jié)講,在這里就不累述。
字體大小
一般情況字體的大小我也會使用 rem 作為單位,因為精度丟失我認為在可以接受的范圍之內(nèi)。
(ps: 但某些情況下,大屏需要顯示更多的字時,就需要使用px作為單位了。推薦媒體查詢來適配字體大小,不能一概而論。)
相對單位 rem
rem 是 CSS3 新增的一個相對單位(root em),即相對 HTML 根元素的字體大小的值。
rem 應(yīng)該是自適應(yīng)使用的最廣泛的單位了。
相對單位 em
em 也是一個相對單位,卻是相對當前元素的字體大小。
line-height
一般建議在 line-height 使用 em。因為在需要調(diào)整字體大小的時候,只需修改 font-size 的值,而 line-height 已經(jīng)設(shè)置成了相對行高了。
首行縮進兩個字符
在存在首行縮進的需求,我也會使用這個單位。
text-indent: 2em
視口單位 vw | vh
vw: 1vw = 視口寬度的 1%
vh: 1vh = 視口高度的 1%
我們知道以 rem 單位設(shè)計的彈性布局,是需要在頭部加載一段腳本來進行監(jiān)聽分辨率的變化來動態(tài)改變根元素字體大小,使得 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. 合理使用變量
一般設(shè)計稿中的某一類的文字(元素)都是用相同的字體大小、顏色、行高等樣式屬性,所以這些值我們不必每次都重復寫,因為當 UI 更新設(shè)計方案,你需要改的地方就很多了。這些重復使用的值我們完全可以存放在變量里面。
Sass 和 Less 稍微有點區(qū)別:
// sass
$direction: left;
// less
@direction: left;
當然 CSS 原生也是存在變量的,使用規(guī)則如下:
變量定義的語法是: --; // *為變量名稱。
變量使用的語法是: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 歸類重復樣式
和重復變量一樣,重復的樣式也可以歸類。我覺得優(yōu)秀的代碼其中有一條肯定是代碼的復用性強。
之前我們寫 CSS 的時候,也會將一些重復使用的代碼放在一個 class 中,這樣的確達到了一定的復用性,不過最后的效果可能就是在一個元素里面放了很多 class,如下圖:
這樣下一個接手得人難免會有點迷糊,而且這樣會造成樣式越來越難修改。
這個時候,mixin( 可以理解成 class 中的 class )就能發(fā)揮它的作用了。
這是一個描述性文字的樣式:
.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 屏的問題)。
據(jù)小生所知好像沒有什么兼容性特別好的方案,這里我只是提供兩種種相對較好的方案。
使用偽類 + 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);
}
當然這個方案在一些版本較低的機型也是會出現(xiàn)粗細不均、細線消失斷裂的兼容性問題。不過現(xiàn)在在已經(jīng) 2019 年了,版本較低的機型也淘汰的差不多了。
使用 box-shadow 模擬
.border_bottom {
box-shadow: inset 0px -1px 1px -1px #d4d6d7;
}
這個方案基本可以滿足所有場景,不過有個缺點也就是顏色會變淺。
還可以使用淘寶的Flexible.js來通過規(guī)定縮放比解決。
7. 從 html 元素繼承 box-sizing
在大多數(shù)情況下我們在設(shè)置元素的 border 和 padding 并不希望改變元素的 width,height值,這個時候我們就可以為該元素設(shè)置 box-sizing:border-box;。
我不希望每次都重寫一遍,而是希望他是繼承而來的,那么我們可以使用如下代碼:
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
這樣的好處在于他不會覆蓋其他組件的 box-sizing 值,又無需為每一個元素重復設(shè)置 box-sizing:border-box;。
8. 內(nèi)聯(lián)首屏關(guān)鍵 CSS
性能優(yōu)化中有一個重要的指標 —— 首次有效繪制(FMP),即指頁面的首要內(nèi)容(primary content)出現(xiàn)在屏幕上的時間。這一指標影響用戶看到頁面前所需等待的時間,而 內(nèi)聯(lián)首屏關(guān)鍵 CSS(即 Critical CSS,可以稱之為首屏關(guān)鍵 CSS) 能給用戶一個更好的心理預期。
如圖:
我們知道內(nèi)聯(lián) CSS 能夠使瀏覽器開始頁面渲染的時間提前,即在 HTML 下載完成之后就能渲染了。
既然是內(nèi)聯(lián)關(guān)鍵 CSS,也就說明我們只會將少部分的 CSS 代碼直接寫入 HTML 中。至于內(nèi)聯(lián)哪些 CSS 你可以使用 Critical。
9. 文字超出省略、文字兩端對齊
需求中我們也經(jīng)常遇到這樣的需求,這里直接提供方案。
超出省略
.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: 10px0;
width: 100px;
border: 1px solid red;
text-align-last: justify;
-moz-text-align-last: justify; } /* 針對 Firefox 的代碼 */
}
效果如下:
這方案很酷,但是
text-align-last的兼容性不好,這個text-align-last的意思是專門作用于段落的最后一行,justify的意思是最后一行被調(diào)整為兩端對齊。這個屬性ie兼容的不錯,但是Safari不支持哈哈哈~
寫在最后
這是一篇很高質(zhì)量的css技巧,再次感謝原作者小生方勤,最后,祝大家調(diào)試愉快,一次成功!
原文地址:https://mp.weixin.qq.com/s/4d-ON-9zKgKr-EdyDBuItA