提高幸福感的 9 個 CSS 技巧

前言

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


調(diào)試css

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

9 個 CSS 技巧

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

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

1. 盡量使用 padding 代替 margin

我們在設(shè)計稿還原的時候, paddingmargin 兩個是常用的屬性,但我們知道屬于同一個 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)容、 PaddingBorder 分隔。

至于為什么合并我個人覺得這和排隊取款的安全距離有點類似,人與人之間的安全距離是 1m,如果安全距離不合并,那么我們在排隊的時候是不是人與人的距離就變成 2m 了。當然很可能不是這個原因。

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

所以我們在使用 margin 的時候一定要注意 collapsing margins 問題。

2. position:fixed 降級問題

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

解決方案:

既然會降級為 absolute 效果,我們該怎么解決這個問題呢?我們就改考慮什么情況下 fixedabsolute 的表現(xiàn)效果會是一樣的。

即當使用 fixed 元素的直接父元素的高度和屏幕的高度相同時 fixedabsolute 的表現(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();

  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 歸類重復樣式

和重復變量一樣,重復的樣式也可以歸類。我覺得優(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è)置元素的 borderpadding 并不希望改變元素的 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 */
}
image

兩端對齊

// 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

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

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