CSS 中的簡寫到底有多少坑?以后不敢了...
簡寫(語法糖)可能給我們編碼帶來了很多便利,但簡寫也會帶來一些問題,今天來討論一下 CSS 中的簡寫的"愛恨情仇"
為什么說是愛恨情仇呢?因?yàn)楹唽懡o我們帶來了很多的便利,但凡事都有好有壞,你不能說簡寫一點(diǎn)壞處都沒有。所以我們就聊聊簡寫的 "好" 和 "壞"
background
這個(gè) CSS 屬性大家肯定是再熟悉不過了,給元素設(shè)置背景色
是這樣?
.demo?{
??background:?#333;
}
還是這樣?
.demo?{
??background-color:?#333;
}
應(yīng)該都有吧,換作我自己,平常這兩者用哪個(gè)好像也是看心情,如果你說肯定用前者啊,因?yàn)榍罢呔鸵粋€(gè)單詞,那其實(shí)后者也不麻煩,現(xiàn)在大家都用編輯器,在智能提示的輔佐下輸入 bgc 再按回車就能打出 background: ; 了,其實(shí)也不麻煩

回到正題,其實(shí)這兩者寫法我更推薦后者,為什么?來看個(gè)例子??
<style>
??.demo?{
????background:?#333;??/*?給元素設(shè)置了背景色#333?*/
??}
??
??/*?...?中間隔了很多樣式代碼?*/
??.demo:hover?{
????background:?url("example.png");?
??}
style>
<div?class="demo"/>
這個(gè)場景很簡單:鼠標(biāo)移到元素上就展示某張照片,未加載前用一個(gè)純色占位
然而實(shí)際效果是?

為了效果明顯,我加了邊框、文字,網(wǎng)速調(diào)成
slow 3G
可以看到 hover 時(shí)的 background 覆蓋掉了前者的 background,使得效果差強(qiáng)人意
是因?yàn)榍罢吆秃笳叨际?background,所以后者自然會覆蓋前者嗎?不全是
即便我們前者用的 background-color: #333;,也仍然會被后者覆蓋
大家都知道 background 是一個(gè)語法糖,即很多屬性的簡寫 ??

那像例子中用 background: url('example.png')時(shí),做了什么呢?

如上圖所示,它默認(rèn)把所有值都設(shè)置成了 initial,因此無論之前用到了其中哪個(gè)值都會被覆蓋,雖然 initial 設(shè)置了跟沒設(shè)置是一樣,都表示保持元素該屬性的初始值
會不會有人想說:我一直都這么用的,都沒遇到啥問題啊!
我只想說一句:可能運(yùn)氣比較好,等代碼比較復(fù)雜了,你可能會回來補(bǔ)這個(gè)窟窿的
結(jié)論:這就是一個(gè)簡寫造成的隱患,大家能避免則避免
margin
又提了一個(gè)大家再熟悉不過的屬性 margin,這里面又有啥坑呢?沒啥坑,就是想介紹一下其它用法
以下都是它的簡寫:
margin: 10px 20px 30px 40pxmargin: 10px 20px 30pxmargin: 10px
這些簡寫確實(shí)幫我們省去了不少的代碼量
讓我們投身到一個(gè)例子??中:現(xiàn)在我想讓我的元素水平居中,我想用 margin 來實(shí)現(xiàn)
<style>
??.parent?{
????width:?300px;
????height:?300px;
????border:?1px?solid?black;
??}
??.child?{
????width:?100px;
????height:?100px;
????background-color:?red;
????margin:?auto;??/*?水平居中?*/
??}
style>
<div?class="parent">
??<div?class="child"/>
div>
效果如你所愿:

但你使用 margin: auto 時(shí)有沒有那么一瞬間想過,前面是否設(shè)置過 margin-top 或 margin-bottom 呢?比如這樣:
??
預(yù)期的效果是什么樣的?而此時(shí)的效果是什么樣的?


可以看到,預(yù)期是想要既水平居中,又距離頂部 100px,而現(xiàn)在 margin-top 被覆蓋了
其實(shí)你單純想實(shí)現(xiàn)水平居中完全沒必要用 margin: auto,因?yàn)槟惚疽馐遣幌肴バ薷捻敳亢偷撞康拈g距的,只是因?yàn)槟阌昧诉@個(gè)簡寫,不得不這么做
不然試試另一個(gè)簡寫?讓你只處理水平的間距
??
這樣同樣能實(shí)現(xiàn)我們想要的效果,且不會影響 margin-top 和 margin-bottom 的屬性
那同理,有沒有能只影響豎直方向的 margin 的簡寫呢?當(dāng)然有,那就是 margin-block
一起來看另一個(gè)例子??
<style>
????.parent?{
??????position:?relative;
??????border:?1px?solid?black;
??????width:?300px;
??????height:?300px;
????}
????.child?{
??????position:?absolute;
??????top:?0;
??????bottom:?0;
??????left:?0;
??????right:?0;
??????width:?100px;
??????height:?100px;
??????margin:?auto;
??????background-color:?red;
????}
style>
<div?class="parent">
??<div?class="child"/>
div>
效果如下:

這是一種對于非相對定位的垂直水平居中方法(記好了,面試官問你垂直水平居中的方法又多了一個(gè)),我是從 HTML 原生的 標(biāo)簽中了解到的(之前在12個(gè)可能你沒見過,但非常實(shí)用的 HTML 標(biāo)簽介紹過 標(biāo)簽)

為什么要用這個(gè)例子呢,我就是想引申出這個(gè)知識點(diǎn),跟大家分享一下我最近看到的小 tips
我們可以刪除 margin: auto,用上前面說的 margin-inline: auto 和 margin-block: auto


結(jié)論:
margin的簡寫不如background那么復(fù)雜,但使用上了margin-inline和margin-block也可以給自己降低心智負(fù)擔(dān)
inset
上面說了那么多簡寫帶來的隱患,要不再來說說簡寫帶來的好處?
還是舉個(gè)例子??
<style>
??.parent?{
????position:?relative;
????border:?3px?solid?blue;
????margin:?200px;
????width:?300px;
????height:?300px;
??}
??.child?{
????position:?absolute;
????top:?0;
????bottom:?0;
????left:?0;
????right:?0;
????background-color:?red;
??}
style>
<div?class="parent">
??<div?class="child"/>
div>
這段代碼大家應(yīng)該都很熟悉,我們給 .child 元素設(shè)置成了絕對定位,并賦予了以下屬性:
top: 0;bottom: 0;left: 0;right: 0;
然后元素就撐滿父元素了,達(dá)到了 width: 100% + height: 100% 的效果,那為啥不直接設(shè)置寬高都 100% 呢?只用設(shè)置兩個(gè)屬性
??? 不這么做的原因還是要回到 position 本身,當(dāng)一個(gè)元素脫離文檔流時(shí),若未設(shè)置 top、bottom、left、right,默認(rèn)元素停留的位置就是其未脫離文檔流時(shí)的位置
可能有點(diǎn)繞,直接上張圖


可以看到,零一 這個(gè)元素在脫離文檔流后,仍然是停留在它處于文檔流時(shí)的位置,那此時(shí)如果給他設(shè)置寬高 100% 會是什么樣呢?

漂亮,超出父元素了,雖然解決這個(gè)問題也很簡單,直接加一個(gè) left: 0 即可但我們還有更簡單的方法,那就是用 inset 這個(gè)屬性
其實(shí) inset 就是 top、right、bottom、left 的簡寫,不知道為什么,我看過很多人的代碼,都沒用過這個(gè)屬性,所以也給大家安利一下
語法跟 margin 類似,因此我們用它來簡化剛才的代碼
??
這里為什么我又推薦大家用 inset 了呢?本質(zhì)是因?yàn)榇颂幬覀兇_實(shí)是需要同時(shí)設(shè)置上下左右四個(gè)值的,那為何不用 inset 呢?
border
?? 天吶,受不了了!怎么全是平時(shí)常用到的屬性,有這么多坑嗎?
其實(shí) border 這個(gè)還好,還是建議用簡寫的哈,只不過有一個(gè)特殊的 case,想給大家分享一下,避免踩坑
有這樣一個(gè)場景:一個(gè)元素本身沒有邊框,當(dāng)鼠標(biāo)移入時(shí)出現(xiàn)邊框,邊框從有到無要有過渡動畫;同時(shí)鼠標(biāo)移除,邊框消失,也伴隨有過渡動畫
<style>
??.demo?{
????width:?100px;
????height:?100px;
????background-color:?lightblue;
????border:?none;
????box-sizing:?border-box;
????transition:?border?1s?linear;
??}
??.demo:hover?{
????border:?4px?solid?red
??}
style>
<div?class="demo"/>
大部分人都會這么寫對不對?效果如何呢?可惜只成功了一半!

為什么鼠標(biāo)移出時(shí),border 的過渡動畫消失了?

圖中可以看到,border: none 其實(shí)就是把 border-style 設(shè)置成了 none,大家都知道 transition 對于 border 的過渡動畫其實(shí)是針對 border-color 和 border-width 的,但如果 border-style 都沒有,那還怎么看得到過渡動畫呢?
所以我們想要實(shí)現(xiàn)鼠標(biāo)移出時(shí)的過渡動畫,就不能用 border: none 這個(gè)簡寫了,那該怎么辦?
我想到了一個(gè)思路,可能不是最完美的,但根本看不出瑕疵,大家可以借鑒一下:
將元素的 border 初始狀態(tài)設(shè)置為 border: 0px solid transparent,這樣既保證了 border-style 的存在,又能保證邊框會從 4px 過渡到 0px,顏色也從 有 過渡到 無
效果如下:

總結(jié)
對于 「我們到底該如何使用簡寫?」 這個(gè)問題,我認(rèn)為:需要一次性設(shè)置簡寫屬性中全部或絕大部分屬性時(shí),可以使用簡寫;反之,則不太應(yīng)該使用簡寫
