提高幸福感的 9 個(gè) CSS 技巧

前言

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


調(diào)試css

所以這篇文章我會(huì)介紹 9 個(gè)使你的 CSS 更加簡(jiǎn)潔優(yōu)雅的使用技巧,幫你搞定一些css難題。
本文修改自公眾號(hào)小生方勤的文章

9 個(gè) CSS 技巧

特此聲明,這里說的 CSS 并不止包含 CSS,也包含 CSS 預(yù)處理器(Less Sass 等),愿各位看官不要糾結(jié)于此。

正文現(xiàn)在開始。

1. 盡量使用 padding 代替 margin

我們?cè)谠O(shè)計(jì)稿還原的時(shí)候, paddingmargin 兩個(gè)是常用的屬性,但我們知道屬于同一個(gè) BFC 的兩個(gè)相鄰 Box 的 margin 會(huì)發(fā)生重疊,所以如果 margin 使用的過于頻繁的時(shí)候,Box 的垂直距離可能就會(huì)發(fā)生重疊。

還有一個(gè)問題就是第一個(gè)子元素的 margin-top 值會(huì)加在父元素上的 bug(最后一個(gè)子元素的 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.

翻譯過來就是:

所有毗鄰的兩個(gè)或多個(gè)盒元素的 margin 將會(huì)合并為一個(gè) margin 共享。 毗鄰的定義為:同級(jí)或者嵌套的盒元素,并且它們之間沒有非空內(nèi)容、 PaddingBorder 分隔。

至于為什么合并我個(gè)人覺得這和排隊(duì)取款的安全距離有點(diǎn)類似,人與人之間的安全距離是 1m,如果安全距離不合并,那么我們?cè)谂抨?duì)的時(shí)候是不是人與人的距離就變成 2m 了。當(dāng)然很可能不是這個(gè)原因。

所以我們可以在首位元素使用 padding 來替代 margin。當(dāng)然有的時(shí)候使用 padding 不能滿足需求,這時(shí)你也可以在“非空內(nèi)容”這個(gè)條件做文章。即在父元素添加一個(gè)偽元素。

所以我們?cè)谑褂?/strong> margin 的時(shí)候一定要注意 collapsing margins 問題。

2. position:fixed 降級(jí)問題

不知道曾經(jīng)的你是不是遇到吸頂效果,就是使用 position:fixed 這個(gè)屬性。其實(shí)如果其父元素中有使用 transform, fixed 的效果會(huì)降級(jí)為 absolute。

解決方案:

既然會(huì)降級(jí)為 absolute 效果,我們?cè)撛趺唇鉀Q這個(gè)問題呢?我們就改考慮什么情況下 fixedabsolute 的表現(xiàn)效果會(huì)是一樣的。

即當(dāng)使用 fixed 元素的直接父元素的高度和屏幕的高度相同時(shí) fixedabsolute 的表現(xiàn)效果會(huì)是一樣的。

如果這個(gè)直接父級(jí)內(nèi)的元素存在滾動(dòng)的情況,那就加上 overflow-y:auto

3. 合理使用 px | em | rem | % 等單位

在 CSS 中有許多距離單位,比如 px | em | rem | %,還有 CSS3 中的 vh | vw 等單位。

那么我們?cè)陧?xiàng)目中應(yīng)該如何使用呢?我們?cè)?pc 端不需要考慮的這么復(fù)雜,所以這里我們主要講講這些單位在移動(dòng)端中的使用。

基礎(chǔ)單位 px

px 是我們最早接觸到的單位了,不過我們?cè)谝苿?dòng)端自適應(yīng)的要求下,使用的頻率不是很高;我總結(jié)了以下使用的情況:

比較小的圖案

比如需要我們畫一個(gè) r 為 5px 的圓,如果我們使用 rem 作為單位,我們很快會(huì)發(fā)現(xiàn)在一些機(jī)型上的圖案不圓,會(huì)呈現(xiàn)橢圓形。這是由于 rem 轉(zhuǎn) px 會(huì)存在精度丟失問題。

所以這個(gè)時(shí)候我們就需要使用 px 配合 dpr 來實(shí)現(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 細(xì)線問題

這個(gè)問題下面我會(huì)單獨(dú)做一小節(jié)講,在這里就不累述。

字體大小

一般情況字體的大小我也會(huì)使用 rem 作為單位,因?yàn)榫葋G失我認(rèn)為在可以接受的范圍之內(nèi)。
(ps: 但某些情況下,大屏需要顯示更多的字時(shí),就需要使用px作為單位了。推薦媒體查詢來適配字體大小,不能一概而論。)

相對(duì)單位 rem

rem 是 CSS3 新增的一個(gè)相對(duì)單位(root em),即相對(duì) HTML 根元素的字體大小的值。

rem 應(yīng)該是自適應(yīng)使用的最廣泛的單位了。

相對(duì)單位 em

em 也是一個(gè)相對(duì)單位,卻是相對(duì)當(dāng)前元素的字體大小。

line-height

一般建議在 line-height 使用 em。因?yàn)樵谛枰{(diào)整字體大小的時(shí)候,只需修改 font-size 的值,而 line-height 已經(jīng)設(shè)置成了相對(duì)行高了。

首行縮進(jìn)兩個(gè)字符

在存在首行縮進(jìn)的需求,我也會(huì)使用這個(gè)單位。

text-indent: 2em

視口單位 vw | vh

vw: 1vw = 視口寬度的 1%
vh: 1vh = 視口高度的 1%

我們知道以 rem 單位設(shè)計(jì)的彈性布局,是需要在頭部加載一段腳本來進(jìn)行監(jiān)聽分辨率的變化來動(dòng)態(tài)改變根元素字體大小,使得 CSS 與 JS 耦合了在一起。

那么有沒有方案解決這個(gè)耦合的問題呢?

答案就是視口單位 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 也增加最大最小寬度限制,避免默認(rèn)100%寬度的 block 元素跟隨 body 而過大過小
body {
    max-width: 540px;
    min-width: 320px;
}

4. 合理使用變量

一般設(shè)計(jì)稿中的某一類的文字(元素)都是用相同的字體大小、顏色、行高等樣式屬性,所以這些值我們不必每次都重復(fù)寫,因?yàn)楫?dāng) UI 更新設(shè)計(jì)方案,你需要改的地方就很多了。這些重復(fù)使用的值我們完全可以存放在變量里面。

Sass 和 Less 稍微有點(diǎn)區(qū)別:

// sass
$direction: left;
// less
@direction: left;

當(dāng)然 CSS 原生也是存在變量的,使用規(guī)則如下:

變量定義的語法是: --; // *為變量名稱。
變量使用的語法是:var();

  1. 無論是變量的定義和使用只能在聲明塊 {} 里面

  2. 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 歸類重復(fù)樣式

和重復(fù)變量一樣,重復(fù)的樣式也可以歸類。我覺得優(yōu)秀的代碼其中有一條肯定是代碼的復(fù)用性強(qiáng)。

之前我們寫 CSS 的時(shí)候,也會(huì)將一些重復(fù)使用的代碼放在一個(gè) class 中,這樣的確達(dá)到了一定的復(fù)用性,不過最后的效果可能就是在一個(gè)元素里面放了很多 class,如下圖:

這樣下一個(gè)接手得人難免會(huì)有點(diǎn)迷糊,而且這樣會(huì)造成樣式越來越難修改。

這個(gè)時(shí)候,mixin( 可以理解成 class 中的 class )就能發(fā)揮它的作用了。

這是一個(gè)描述性文字的樣式:

.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;

這只是一個(gè)簡(jiǎn)單的例子,我們可以把可復(fù)用的樣式放在 mixin 中,這樣接手項(xiàng)目的人只需要熟悉你寫的 mixin.less 就可以開始迭代需求了。

6. 1px 方案

做過移動(dòng)端需求的前端肯定是避免不了處理 1px 細(xì)線問題,這個(gè)問題的原因就是 UI 對(duì)頁(yè)面美觀度的要求越來越高(不要和我說這是 retina 屏的問題)。

據(jù)小生所知好像沒有什么兼容性特別好的方案,這里我只是提供兩種種相對(duì)較好的方案。

使用偽類 + 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);
}

當(dāng)然這個(gè)方案在一些版本較低的機(jī)型也是會(huì)出現(xiàn)粗細(xì)不均、細(xì)線消失斷裂的兼容性問題。不過現(xiàn)在在已經(jīng) 2019 年了,版本較低的機(jī)型也淘汰的差不多了。

使用 box-shadow 模擬

.border_bottom {
    box-shadow: inset 0px -1px  1px -1px  #d4d6d7;
}

這個(gè)方案基本可以滿足所有場(chǎng)景,不過有個(gè)缺點(diǎn)也就是顏色會(huì)變淺。
還可以使用淘寶的Flexible.js來通過規(guī)定縮放比解決。

7. 從 html 元素繼承 box-sizing

在大多數(shù)情況下我們?cè)谠O(shè)置元素的 borderpadding 并不希望改變?cè)氐?width,height值,這個(gè)時(shí)候我們就可以為該元素設(shè)置 box-sizing:border-box;。

我不希望每次都重寫一遍,而是希望他是繼承而來的,那么我們可以使用如下代碼:

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

這樣的好處在于他不會(huì)覆蓋其他組件的 box-sizing 值,又無需為每一個(gè)元素重復(fù)設(shè)置 box-sizing:border-box;。

8. 內(nèi)聯(lián)首屏關(guān)鍵 CSS

性能優(yōu)化中有一個(gè)重要的指標(biāo) —— 首次有效繪制(FMP),即指頁(yè)面的首要內(nèi)容(primary content)出現(xiàn)在屏幕上的時(shí)間。這一指標(biāo)影響用戶看到頁(yè)面前所需等待的時(shí)間,而 內(nèi)聯(lián)首屏關(guān)鍵 CSS(即 Critical CSS,可以稱之為首屏關(guān)鍵 CSS) 能給用戶一個(gè)更好的心理預(yù)期。

如圖:

我們知道內(nèi)聯(lián) CSS 能夠使瀏覽器開始頁(yè)面渲染的時(shí)間提前,即在 HTML 下載完成之后就能渲染了。

既然是內(nèi)聯(lián)關(guān)鍵 CSS,也就說明我們只會(huì)將少部分的 CSS 代碼直接寫入 HTML 中。至于內(nèi)聯(lián)哪些 CSS 你可以使用 Critical。

9. 文字超出省略、文字兩端對(duì)齊

需求中我們也經(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 打包的時(shí)候這段代碼會(huì)被刪除掉,原因是optimize-css-assets-webpack-plugin 這個(gè)插件的問題。

解決方案:

可以使用如下的寫法:

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 */
}
image

兩端對(duì)齊

// html
<div> 姓名</div>
<div>手機(jī)號(hào)碼</div>
<div>賬號(hào)</div>
<div>密碼</div>

// css
div {
    margin: 10px0; 
    width: 100px;
    border: 1px solid red;
    text-align-last: justify;
    -moz-text-align-last: justify; } /* 針對(duì) Firefox 的代碼 */
}

效果如下:


這方案很酷,但是text-align-last的兼容性不好,這個(gè)text-align-last的意思是專門作用于段落的最后一行,justify的意思是最后一行被調(diào)整為兩端對(duì)齊。這個(gè)屬性ie兼容的不錯(cuò),但是Safari不支持哈哈哈~

寫在最后

這是一篇很高質(zhì)量的css技巧,再次感謝原作者小生方勤,最后,祝大家調(diào)試愉快,一次成功!
原文地址:https://mp.weixin.qq.com/s/4d-ON-9zKgKr-EdyDBuItA

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容