CSS 技巧收錄

【本文會持續(xù)更新!】

1、color 影響 border-color

當(dāng)只設(shè)置元素的邊框?qū)挾群蜆邮綍r,邊框的顏色會取當(dāng)前元素 color 屬性的計算值。

<div style="color: blue;border: 1px solid;">這里設(shè)置了 border,但不指定 border-color</div>

瞧瞧該實例元素的 border-color 屬性的計算值:

可以看到,border-color 屬性未設(shè)置值時為 initial 關(guān)鍵字,代表取該屬性的默認(rèn)值。那么,為什么這里取的是 color 屬性的值而非瀏覽器對 border-color 的默認(rèn)值(如果有的話)呢?

因為 border-color 屬性的默認(rèn)值就是 currentColor 關(guān)鍵字(CSS 3),也就是當(dāng)前元素的 color 屬性的計算值,詳見 border-color | MDN。

color 前景色

MDN 中對 color 屬性是這樣介紹的:

The color property sets the foreground color of an element's text content, and its decorations. It doesn't affect any other characteristic of the element

翻譯過來就是,color 屬性設(shè)置元素文本內(nèi)容的 前景色修飾。

HTML 元素的前景色包括:

  • 字體顏色,也就是狹義上的 color;
  • border-color,邊框的顏色;
  • outline-color,輪廓的顏色;
  • box-shadow,陰影的顏色;
  • text-shadow,文本陰影的顏色;

以及文本修飾中的 text-decoration-color,下劃線的顏色。

<head>
  <style>
    p {
      color: blue;
      max-width: 500px;
    }
  </style>
</head>
<body>
  <p>這里沒有做任何處理</p>
  <p style="border: 1px solid;">這里設(shè)置了 border,但不指定 border-color</p>
  <p style="outline: 1px solid;">這里設(shè)置了 outline,但不指定 outline-color</p>
  <p style="text-decoration: underline;">這里設(shè)置了 text-decoration,但不指定 text-decoration-color</p>
  <p style="box-shadow: 0 1px 2px 0;">這里設(shè)置了 box-shadow,但不指定顏色</p>
  <p style="text-shadow: 10px 10px 2px;">這里設(shè)置了 text-shadow,但不指定顏色</p>
</body>

2、移動端 H5 禁止顯示系統(tǒng)菜單

當(dāng)在移動端 H5 上長按一個目標(biāo)元素時,瀏覽器會彈出一個關(guān)于目標(biāo)元素的菜單信息。請看下面針對文本元素的實例:

<span>這是一段文字,請在移動端長按</span>

在某些場景下,我們并不希望瀏覽器彈出這樣的菜單,應(yīng)該怎么做呢?我在網(wǎng)上搜羅了幾個常見方案:

  • 通過 -webkit-touch-callout 屬性禁用 callout【無效】

    -webkit-touch-callout: none;
    

    -webkit-touch-callout 屬性的兼容性非常差,之前只有在 Safari 瀏覽器上可用。而 現(xiàn)在應(yīng)該是被廢棄了,親測在 ios Safari 瀏覽器上不起效,Can I use 上也已經(jīng)搜索不到了。

  • JS 屏蔽 contextmenu 事件的默認(rèn)行為【無效】

    $elm.addEventListener('contextmenu', (e) => {
      e.preventDefault();
    });
    

    當(dāng)用戶嘗試打開上下文菜單(通常是鼠標(biāo)右鍵單擊)時,contextmenu 事件會被觸發(fā),我們可以通過 preventDefault() 方法來屏蔽菜單的顯示。那么這種方法是否適用于移動端 h5 呢?

    答案是否定的。不妨來看看 contextmenu 事件的兼容性:

    so,網(wǎng)上的部分教程就不要再誤人子弟了。

  • 通過 user-select 屬性讓元素不可選中【有效】

    -webkit-user-select: none;
    -moz-user-select: none; 
    -ms-user-select: none;
    -o-user-select: none;
    user-select: none;
    

    在移動端,若用戶不可選中元素,自然也就不能通過長按調(diào)起默認(rèn)菜單了。但需要注意的是,user-select: none 在部分瀏覽器(如 Safari)中會使 <input>、<textarea> 等表單元素失效

  • JS 屏蔽 touchstart 事件的默認(rèn)行為【有效】

    $elm.addEventListener('touchend', (e) => {
      e.preventDefault();
    });
    

    此方案和使用 user-select 是一樣的原理,但同樣 需要注意禁止默認(rèn)行為所帶來的負(fù)面影響,譬如作用于可滾動元素時。

所有方案的測試情況見:https://codepen.io/JunreyCen/pen/rEBYPV

總結(jié)一下,移動端的兼容性一直是非常棘手的問題,各種手機操作系統(tǒng)、各種瀏覽器應(yīng)用沒有一套統(tǒng)一的 web 標(biāo)準(zhǔn),都喜歡 “各抒己見”。也因此,上面提及的方案在某些型號手機的瀏覽器中(譬如 Oppo 自帶的瀏覽器)依然是不起作用的,這種情況下開發(fā)者只能 “見招拆招”,無招可使時也只能擇 “較優(yōu)解” 了。


3、文本溢出顯示省略號

我們經(jīng)常遇到單行文本溢出時顯示省略號的場景,那多行文本的類似處理該如何實現(xiàn)?

單行文本

overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;      /* 文本不換行 */

多行文本

多行文本溢出時,最后一行截斷并顯示省略號。這里提供兩種實現(xiàn)方式:

  • 使用 line-clamp 屬性

    line-clamp 是一個不規(guī)范的屬性,沒有出現(xiàn)在 CSS 規(guī)范草案中。而且,它必須結(jié)合舊版的 flexbox(伸縮盒)模型才起作用。

    overflow: hidden;
    display: -webkit-box;           /* 舊版伸縮盒模型 */
    display: -moz-box;
    -webkit-box-orient: vertical;   /* 子元素垂直排列 */
    -moz-box-orient: vertical;
    -webkit-line-clamp: 2;          /* 塊元素顯示的文本行數(shù) */
    -moz-line-clamp: 2;
    

    如下圖所示,line-clamp 在兼容性方面還是有點缺陷的。

    除此之外還需要注意的是,autoprefixer 等預(yù)處理插件會自動刪除一些舊的樣式屬性(包括 -webkit-box-orient 屬性),所以使用這種方式時要對 autoprefixer 插件進行配置,詳見這個 issue

  • JS + CSS 手動加省略號

    處理流程:

    1. 元素的 height 值設(shè)置為 line-height 值的整數(shù)倍n;
    2. JS 獲取元素的文本節(jié)點高度(scrollHeight),若高度\geq n+1line-height 值則視為文本溢出;
    3. 文本溢出時,于元素右下方顯示省略號,否則不顯示;
    <style>
    #ellipsis {
      position: relative;
      display: block;
      overflow: hidden;
      line-height: 20px;
      height: 40px;           /* height 為整數(shù)倍 line-height */
      word-break: break-all;  /* 使文本填充滿容器,利于省略號和文本的銜接 */
    }
    .show-ellipsis {
      padding-right: 12px;    /* 給省略號騰出空間 */
    }
    .show-ellipsis:after {
      content: '...';
      position: absolute;
      right: 0;
      bottom: 0;
    } 
    </style>
    
    <p id="ellipsis">JS 和 CSS 設(shè)置多行文本字?jǐn)?shù)超出時最后一行顯示省略號,JS 和 CSS 設(shè)置多行文本字?jǐn)?shù)超出時最后一行顯示省略號</p>
    
    <script>
      const $elm = document.getElementById('js-ellipsis');
      const style = window.getComputedStyle($elm);
      const limitHeight = +style.height.replace('px', '') + +style.lineHeight.replace('px', '');
      if ($elm.scrollHeight >= limitHeight) {
        // 文本溢出則顯示省略號
        $elm.className = 'show-ellipsis';
      }
    </script>
    

    這種實現(xiàn)方式基本不存在兼容性問題(除了低版本 IE 瀏覽器),但效果肯定比不上 line-clamp 的方式,只能靜待 W3C 制訂一套規(guī)范的處理方案了。


4、圖像自適應(yīng)

我們寫頁面的時候經(jīng)常會遇到,獲取的圖片尺寸與我們所期待的渲染尺寸不符。譬如在渲染用戶頭像的場景下,我們往往希望用戶上傳的圖片都是統(tǒng)一的正方形尺寸,然而用戶給的可能是這樣的:

常見的處理方式是 適當(dāng)?shù)募舨檬箞D片填滿容器而不被拉伸,我們可以利用背景圖(background-size / background-position)來實現(xiàn):

<style>
.avatar {
  width: 200px;
  height: 200px;
  border: 2px solid #07C160;
  background: url('./images/captain.jpeg') no-repeat;
  background-size: cover;
  background-position: center; 
}
</style>
<div class="avatar"></div>

CSS 3 中提供了新的屬性:object-fit,可以對 <img> 標(biāo)簽作寬高自適應(yīng)處理,效果類似于 background-size 屬性。

object-fit 提供了5個取值:

  • none:內(nèi)容保持原有尺寸;
  • contain:內(nèi)容保持寬高比地縮放,內(nèi)容和容器的寬高比不匹配時會 留下白邊
  • cover:內(nèi)容保持寬高比地填滿容器,內(nèi)容和容器的寬高比不匹配時會 被裁剪
  • fill:內(nèi)容剛好填滿容器,內(nèi)容和容器的寬高比不匹配時會 被拉伸;
  • scale-down:內(nèi)容尺寸和 nonecontain 中的一個相同,最終會顯示尺寸較小的那個;

background-size 和 object-fit 的效果對比

同樣的,background-positionobject-position 的作用類似,比較明顯的區(qū)別在于:

background-position 的默認(rèn)值是 0% 0%,而 object-position 的默認(rèn)值是 50% 50%

object-fit 的意義

  • 解放了 background-image 的能力;
    譬如可以同時利用 background-image<img> 標(biāo)簽完成圖片的堆疊等。
  • object-fit 對所有 可替換元素 都有效;
    常見的可替換元素包括:<iframe><video>、<embed><img>、<input type="image">

兼容性

額,如果要兼容 IE 瀏覽器的話,還是乖乖用背景圖的方式把。


5、塊元素等比縮放

現(xiàn)在的網(wǎng)頁開發(fā)都講究響應(yīng)式設(shè)計,以使在各種尺寸的設(shè)備上也能保持良好的 UI 呈現(xiàn)。在響應(yīng)式布局中,我們經(jīng)常需要實現(xiàn)隨網(wǎng)頁視窗寬度動態(tài)變化的元素,尤其是支持等比縮放的元素。

比較傳統(tǒng)的做法,是通過 JS 監(jiān)聽 resize 事件,動態(tài)獲取容器的寬度然后調(diào)整元素的寬高。這里提供一種純 CSS 實現(xiàn)的方式,主要利用的是 padding 屬性的百分比取值

padding 屬性的百分比取值是相對于其包含塊的寬度。

所以,當(dāng)包含塊的寬度發(fā)生變化時,子元素的 padding 屬性的計算值會隨之發(fā)生變化,也就是說子元素的總寬高都會被改變,且與包含塊寬度成正比。

<style>
.wrapper {
  width: 200px;
  height: 300px;
  border: 2px solid #07C160;
}
.content {
  padding: 50%;
  width: 0;
  height: 0;
  background-color: #FA5151;
}
</style>

<div class="wrapper">
  <div class="content"></div>
</div>

接下來的工作,只需要讓目標(biāo)元素的寬高參考于 padding 子元素的寬高,就完成了元素的等比縮放。我們可以利用 絕對定位 來實現(xiàn)。

這里實現(xiàn)一個寬高比為 1:2、寬度保持為容器\frac{1}{2}的等比縮放元素:

<style>
.wrapper {
  width: 20%;
  height: 40%;
  border: 2px solid #07C160;
}
.container {
  position: relative;
  padding: 50%;
  width: 0;
  height: 0;
}
.content {
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: 100%;
  background-color: #FA5151;
}
</style>

<div class="wrapper">
  <div class="container">
    <div class="content"></div>
  </div>
</div>

為了突出演示效果,稍微 “修飾” 了一下:

需要體驗 Demo 的請?zhí)D(zhuǎn):https://codepen.io/JunreyCen/pen/agzoyG


6、垂直外邊距合并

當(dāng)兩個垂直外邊距鄰接時,會合并成一個外邊距。只有普通文檔流中塊元素的垂直外邊距才會發(fā)生合并,不在同一個 BFC 內(nèi)(譬如行內(nèi)元素、浮動元素、絕對定位等)的垂直外邊距不會合并,水平方向的外邊距也不會合并。

通常發(fā)生外邊距合并的場景有:

  • 相鄰的兩個塊元素,鄰接的上/下外邊距發(fā)生合并

    圖片摘自 http://www.w3school.com.cn/css/css_margin_collapsing.asp

    發(fā)生合并時外邊距的計算規(guī)則:

    • 兩個外邊距都是正數(shù)時,取兩者中的較大值;
    • 兩個外邊距一正一負(fù)時,取兩者之和;
    • 兩個外邊距都是負(fù)數(shù)時,比較兩者的絕對值大小,誰大取誰;
  • 無內(nèi)邊距(padding)和邊框(border)的父元素的垂直外邊距會與子元素的垂直外邊距合并

    圖片摘自 http://www.w3school.com.cn/css/css_margin_collapsing.asp
  • 無內(nèi)邊距(padding)、邊框(border)和內(nèi)容(content)的空元素的上/下外邊距會合并

    圖片摘自 http://www.w3school.com.cn/css/css_margin_collapsing.asp

這里提供一個完整 Demo:https://codepen.io/JunreyCen/pen/zVxPWX


7、行內(nèi)(塊)元素空隙

試試執(zhí)行這段代碼:

<img src="./images/captain.jpeg" width="200">
<img src="./images/captain.jpeg" width="200">

奇怪,兩張圖片之間出現(xiàn)了一道縫隙……

這是因為 img 元素默認(rèn)會被渲染成行內(nèi)元素(display: inline;),而上述代碼中兩個 <img> 之間其實是存在一個 換行符 (以及若干個 制表符)的,這些都會被渲染成一個空白格,也就導(dǎo)致了縫隙的產(chǎn)生。

解決辦法有倆:

  • 寫 HTML 代碼的時候避免行內(nèi)元素間的空格、換行符等特殊字符;
    <img src="./images/captain.jpeg" width="200"><img src="./images/captain.jpeg" width="200">
    
  • 把行內(nèi)元素所在行的字體大小設(shè)為 font-size: 0;
    <style>
    body { font-size: 0; }
    </style>
    
    <img src="./images/captain.jpeg" width="200">
    <img src="./images/captain.jpeg" width="200">
    

PS:行內(nèi)塊元素(display: inline-block)也會存在同樣的問題。


8、pointer-events: none;

pointer-events 屬性可以指定元素是否可以成為鼠標(biāo)事件的 target ,通俗點講就是該元素是否可以接收鼠標(biāo)事件。

pointer-events 屬性有多種取值,詳見 MDN。這里著重介紹取值 none

pointer-events: none; 指定元素及其后代元素不會成為鼠標(biāo)事件的 target,父元素不受影響。

實驗 Demo

實驗內(nèi)容:三層 DOM 元素都監(jiān)聽了鼠標(biāo)點擊事件,其中 target 節(jié)點設(shè)置了 pointer-events: none,點擊 child 元素,看看有哪層元素可以響應(yīng)點擊事件。

<div class="parent" onclick="alert('parent')">
  <div class="target" onclick="alert('target')">
    <div class="child" onclick="alert('child')"></div>
  </div>
</div>

左邊不作處理的實例會 alert 三次;而右邊的實例只會 alert 一次,內(nèi)容為 parent

應(yīng)用場景

  • 同層元素點擊穿透

    我們在寫 UI 基礎(chǔ)組件時,多多少少會接觸到 Field 輸入框組件。比如下面的實例,需求是滿足 0.5px 邊框 + input 輸入框。

    <style>
    .field {
      position: relative;
      width: 250px;
      height: 50px;
      text-align: center;
    }
    .field:after {
      position: absolute;
      top: -50%;
      left: -50%;
      right: -50%;
      bottom: -50%;
      content: '';
      border: 1px solid #ccc;
      transform: scale(0.5);
    }
    </style>
    
    <div class="field">
      <input type="text" placeholder="請輸入">
    </div>
    

    你會發(fā)現(xiàn),左邊的輸入框無法聚焦。這其實跟 0.5px 邊框的實現(xiàn)方式有關(guān),實例中利用偽元素 :after 制造了一個2倍尺寸的子元素,然后通過 transform: scale(0.5) 縮放,從而實現(xiàn) 0.5px 邊框。然而,**這個偽元素和 input 輸入框?qū)儆谕瑢釉兀鶕?jù)渲染的先后順序偽元素是層疊于輸入框之上的,所以鼠標(biāo)點擊事件是無法被輸入框捕獲的。

    我們只需要給偽元素設(shè)置 pointer-events: none;,使其無法成為鼠標(biāo)事件的 target,input 輸入框就可以成功被聚焦。

  • 阻止 :hover、:active 等鼠標(biāo)行為狀態(tài)的觸發(fā)

    設(shè)置了 pointer-events: none; 的元素?zé)o法響應(yīng)鼠標(biāo)事件,自然也就無法觸發(fā)相關(guān)的狀態(tài)了。

想體驗實例的請訪問:https://codepen.io/JunreyCen/pen/NZqKOx


9、:first-child 和 :first-of-type 的區(qū)別

  • :first-child
    匹配其父元素的符合特定類型的首個子元素。條件更為苛刻,需要滿足 首個子元素 + 符合特定類型。

  • :first-of-type
    匹配其父元素的符合特定類型的第一個元素。條件較為寬松,在滿足 符合特定類型 的范疇下尋找第一個元素即可。

<style>
  .group-1 h2:first-child,
  .group-1 h3:first-child,
  .group-2 h2:first-of-type,
  .group-2 h3:first-of-type {
    color: #FA5151;
  }
</style>

<div class="group-1">
  <h2>父元素的第一個元素,第一個 h2 元素</h2>
  <h3>父元素的第二個元素,第一個 h3 元素</h3>
</div>
<div class="group-2">
  <h2>父元素的第一個元素,第一個 h2 元素</h2>
  <h3>父元素的第二個元素,第一個 h3 元素</h3>
</div>

10、當(dāng)心分號 ;

我們都知道,在樣式表的聲明塊({...})內(nèi),樣式聲明之間會用分號隔開,這是因為引擎在解析時,每條聲明之間的空格(包括換行符等)會被忽略:

<style>
div {
  color: red;
  font-size: 20px;
}
</style>
<div>content</div>

那如果,分號寫在聲明塊之外呢?

這相當(dāng)于告訴引擎,樣式表解析到這里就結(jié)束了,后面的東西就不用管了。來看看這個 demo:

<style>
div {color: red};
.ctn-1 {color: blue}
.ctn-2 {font-weight: 600}
</style>
<div id="ctn-1">藍色字體</div>
<div id="ctn-2">加粗字體</div>

遇到類似的面試題時,就要注意仔細(xì)看別被 “坑” 了~

最后編輯于
?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補...
    _Yfling閱讀 14,091評論 1 92
  • 學(xué)習(xí)CSS的最佳網(wǎng)站沒有之一 http://www.w3school.com.cn/tags/index.asp ...
    Amyyy_閱讀 1,172評論 0 1
  • 1.塊級元素和行內(nèi)元素 塊級(block-level)元素;行內(nèi)(內(nèi)聯(lián)、inline-level)元素。 塊元素的...
    饑人谷_小侯閱讀 2,190評論 1 4
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 28,771評論 1 45
  • CSS 指層疊樣式表(Cascading Style Sheets),是一種用來為結(jié)構(gòu)化文檔(如 HTML 文檔或...
    神齊閱讀 2,231評論 0 14

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