CSS揭祕實用技巧總結

幻靈爾依發表於2020-04-07

《css揭祕》中講了47個css技巧,其中有很多日常編碼中並不會用到,本文除了將書中部分實用技巧羅列出來之外,還嘗試用幫助讀者搞明白backgroundanimation 等常用但是卻掌握不牢固的知識點。所以閱讀本文不僅可以學習一些實用技巧,也可以鞏固自己的 css 基礎知識。

實用小技巧

DRY原則

全名Don't Repeat Yourself,該原則適用於所有程式語言而不限於css。

擴大可點選區域

  • 關鍵實現:偽元素
  • 具體分析:利用偽元素和定位達到滑鼠移到邊緣時候出現手型且可點選
.expand-range {
  position: relative;
}
.expand-range:after {
  content: '';
  position: absolute;
  top: -10px; right: -10px; bottom: -10px; left: -10px;
}
複製程式碼

推薦使用scss:

@mixin expand-range($top: -10px, $right: $top, $bottom: $top, $left: $right, $position: relative) {
  position: $position;
  &:after {
    content: '';
    position: absolute;
    top: $top;
    right: $right;
    bottom: $bottom;
    left: $left;
  }
}
//使用:.test { @include expand-range($top: -5px, $position: absolute) }
複製程式碼

巧用層疊上下文

  • 關鍵實現: 偽元素 層疊上下文
  • 具體分析: 利用層疊上下文和 z-index: -1 特性實現偽元素覆蓋背景同時又不會遮擋文字(具體實現原理參考這裡 )。這是一個非常常用又好用的技巧,善加利用可以達到很多意想不到的效果。地址
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: -1;
複製程式碼

CSS揭祕實用技巧總結

邊框內圓角

  • 關鍵實現:偽元素 層疊上下文
  • 具體分析:利用偽元素實現圓角矩形併疊加在父元素的背景之上文字之下:地址

CSS揭祕實用技巧總結

clip-path

  • 關鍵實現: clip-path
  • 具體分析:css3 新屬性 clip-path 可以實現區域裁剪,現在瀏覽器支援較好的有三個函式:clip-path: circle(50px at 50px 50px)50px 50px 的地方為圓心裁剪一個半徑 50px 的圓;clip-path: ellipse(30px 40px at 50px 50px)50px 50px 的地方為圓心裁剪一個橫向半徑 30px,縱向半徑 40px 的橢圓;clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%) 按照多個座標剪裁一個多邊形,此處是菱形。有了 clip-path,就可以輕易的實現任意多邊形了:地址

CSS揭祕實用技巧總結

自適應的橢圓

  • 關鍵實現:border-radius
  • 具體分析:border-radius 竟然可以設定 8 個角的半徑~ 其中水平方向(對角線上下有弧度的地方)和垂直方向(對角線左右有弧度的地方)各四個,可以用 / 分割。如果水平或垂直方向指定的值少於四個,則會按照和 margin、padding 一樣的規則重複。如果只指定來水平方向的,那麼垂直方向的跟水平方向的一樣。
    border-radius: 5em 1em; /*相當於border-radius: 5em 1em 5em 1em / 5em 1em 5em 1em;*/
複製程式碼

CSS揭祕實用技巧總結

自適應寬度

  • 關鍵實現:min-content關鍵字
  • 具體分析:如何實現一個元素的寬度根據後代元素的最大固定元素寬度自適應呢?絞盡腦汁,也只能利用 display: inline-block 的包裹特性實現一個不完全的版本:地址 這種方法的缺陷是文字脫離了文件流,高度未計入包含塊。但是如果利用 min-content 關鍵字,可以一行程式碼實現且無副作用:地址
  width: min-content;
複製程式碼

CSS揭祕實用技巧總結

投影模擬多重邊框

  • 關鍵實現:box-shadowinset
  • 具體分析:使用box-shadow可以模擬實現多重邊框,但是由於陰影不佔空間,所以無法觸發點選事件,滑鼠hover邊框時無法出現小手,所以需要配合inset關鍵字使用:地址
  height: 200px;
  background: cyan;
  box-shadow: 0 0 0 5px #000 inset,
              0 0 0 10px #555 inset,
              0 0 0 15px #999 inset;
複製程式碼

CSS揭祕實用技巧總結

單側投影

  • 關鍵實現:box-shadow
  • 具體分析:box-shadow 前兩個引數指定陰影的x、y偏移量,注意若為正數時整體向右/向下偏移,那麼相應的左方/上方會空出一部分來(可以用來隱藏模糊半徑或擴張半徑),負數相反;第三個引數是陰影模糊半徑,即高斯模糊多增加出來的過度顏色;第四個引數是陰影擴張半徑,表示陰影增加的尺寸,可以是負數,表示陰影縮短的尺寸:地址
  box-shadow: 0 5px 4px -4px black;
複製程式碼

第二個引數使陰影整體下移 5px ,第三個引數使陰影四周多了 4px 的高斯模糊(注意由於整體下移了 5px,所以此時上方還是沒有陰影露出的),第四個引數又把陰影整體縮小了 4px,,所以左右兩邊才沒有出現模糊半徑導致的高斯模糊陰影色,從而實現單側投影。

CSS揭祕實用技巧總結

還可以逗號分隔設定多個陰影色,比如下面的兩側投影效果:地址

  box-shadow: 5px 0 5px -5px black,
             -5px 0 5px -5px black;
複製程式碼

CSS揭祕實用技巧總結

不規則投影

  • 關鍵實現:filter: drop-shadow()
  • 具體分析:box-shadow 不能透過透明背景顯示出來,不能越過偽元素/子元素顯示出來,而這些drop-shadow能做到。(但無論哪種投影都會被clip-path剪裁掉~~)地址
  filter: drop-shadow(2px 2px 10px rgba(0,0,0,.5));
複製程式碼

CSS揭祕實用技巧總結

濾鏡的染色和褪色效果

前端開發大都瞭解糊濾的高斯模鏡效果是filter: blur()實現的,但是卻很少使用濾鏡的其他幾個調色效果。filter 的值有blur()drop-shadow()url()brightness()contrast()grayscale()hue-rotate()invert()opacity()saturate()sepia()~~可以使用複合形式如:filter: sepia(1) saturate(4)等。下面是filter屬性值大集合:地址

CSS揭祕實用技巧總結

餅圖 svg

餅圖的 css 實現方案非常奇怪,所以我忽略之。推薦使用 svg 的實現方案,非常簡單,先來個基本教學吧~

先畫個圓:

<svg width="100" height="100">
  <circle r="25" cx="50" cy="50" />
</svg>
複製程式碼

這裡 r="25" 是半徑25, cx cy 分別表示圓心的 x y 座標。

circle {
  fill: yellowgreen;
  stroke: #666;
  stroke-width: 50;
}
複製程式碼

這裡給圓形定義了一個寬度 40 的描邊:

CSS揭祕實用技巧總結

再把描邊設為線段長度 20 間隔 10 的虛線:

circle {
    ...
    stroke-dasharray: 20 10;
}
複製程式碼

當把虛線的間隔設定為大於等於圓周時,虛線的線段長度就是一個扇形區域(當線段長度等於圓周時扇區達到100%):

CSS揭祕實用技巧總結

給 svg 設定圓角和背景色,並旋轉 -90deg ,就可以實現一個餅圖:地址(使用currentColor關鍵字和color: inherit 是為了實現DRY原則。)

CSS揭祕實用技巧總結

但是這樣的餅圖其扇區大小是不易計算的,為了方便計算,可以讓虛線的線段長度同時也是圓周無限接近100,這樣就可以更方便的設定扇區的百分比。圓周是 2πr ,所以 100 = 2πr ,計算得出半徑 r 近似值 16。再利用 svg 的 viewBox 屬性,實現自適應容器大小的餅圖:地址

CSS揭祕實用技巧總結

這種方法有個弊端,就是當設定 stroke-dasharray: 100 100 時會有一條縫,這是取近似值無法避免的。

背景 background

background 是我們最常用的屬性之一,但作為一個老前端,我也只能羞恥的說我目前並沒有完全掌握這個屬性。

background 是一個簡寫屬性,可以包括多個屬性:background-clip、background-color、background-image、background-origin、background-position、background-repeat、background-size、background-attachment 。接下來我們一個個來看看這些屬性的作用:

  • background-color 最常用的屬性,預設不繼承(background的所有屬性都預設不繼承),初始值為 transparent;有時候使用預設繼承可以實現一些好玩的效果,比如倒影;
  • backgroundo-image 背景圖片,可以逗號分割設定多個,可以是圖片url或者漸變色;
  • background-clip 背景剪裁,可以逗號分割設定多個,值可以為 broder-box(初始值)、padding-boxcontent-boxtext(新,將背景被文字剪裁);
  • background-origin 設定背景起始點的相對區域,搭配 background-position 使用,可以逗號分割設定多個,值可以是border-boxpadding-box(初始值)、content-box
  • background-position 設定背景的起始點,可以逗號分割設定多個,值可以是 10px 20pxcenter centerleft 10px bottom 20px等等,非常靈活;
  • background-size 設定背景的大小,可以逗號分割設定多個,值可以是數字值如30px 40pxauto auto(初始值)、convercontainbackground-repeat: repeat就是根據這個尺寸大小來重複的。
  • background-repeat 設定背景的重複方式,初始值為 repeat,常使用值的還有no-repeat
  • background-attachment 設定背景影像的位置是在視口內固定,還是隨著包含它的區塊滾動。可以逗號分割設定多個,值有scroll(初始值)、localfixed。詳情檢視MDN

簡寫時 background-size 只能緊接著 background-position 出現,以 / 分割,如: "center / 80%"。

半透明邊框

  • 關鍵實現:background-clip
  • 具體分析:由於background屬性預設會覆蓋整個盒模型包括邊框border,所以設定border-color: rgba(0, 0, 0, .5)時會透出背景色,達不到半透明邊框的效果。css3增加了background-clip屬性,定義背景填充的裁剪區域。設定padding-box便可以實現半透明邊框:地址
  border: 10px solid rgba(255, 255, 255, .5);
  background: white;
  background-clip: padding-box;
複製程式碼

CSS揭祕實用技巧總結

靈活的背景定位

  • 關鍵實現:backgrond-position background-origin
  • 具體分析:我們都知道background-position可以定位背景圖片等位置,但是都是相對padding-box的左上角開始等。css3 允許這樣寫:background-position: right 10px bottom 20px,同時 css3 還支援background-origin,其預設值如同其表現border-box,支援設為padding-boxcontent-box地址
  height: 200px;
  padding: 10px;
  border: 5px solid cyan;
  background: lightblue;
  background: radial-gradient(#00a4fd, cyan) no-repeat right 100px bottom / 100px 100px;
  background-origin: content-box;
複製程式碼

CSS揭祕實用技巧總結

background-position 設為百分比值較為複雜。百分比值實際上執行了以下的計算公式:

(container width - image width) * (position x%) = (x offset value)
(container height - image height) * (position y%) = (y offset value)
複製程式碼

由計算公式可知:當值為0%時,實際偏移值為0px,此時圖片的左邊界(或上邊界)和容器的左邊界(或上邊界)重合;當值為50%時,實際偏移值為容器減圖片剩餘空間的一半,圖片左右邊界(或上下邊界)距離容器左右邊界(或上下邊界)相等,此時圖片的中點和容器的中點重合。當值100%時,實際偏移值為容器減圖片的剩餘空間,所以此時圖片的右邊界(或下邊界)和容器的右邊界(或下邊界)重合。二者之差為負值時同樣有效。地址

CSS揭祕實用技巧總結

條紋背景

  • 關鍵實現:background-image
  • 實現分析:利用線性漸變實現多種顏色的交錯重複,形成條紋背景。lienar-gradient的第一個引數是漸變的角度,可以是方向關鍵字to top(初始值,可忽略不寫)等,也可以是角度90deg等;#fb3 50%指的是色標和終點位置值;這裡linear-gradient的第二個位置值設定為0會被解析為前一個色標的位置值即50%,這樣寫更加符合DRY原則。
background: linear-gradient(#fb3 50%, #58a 0);
background-size: 100% 30px;
複製程式碼

CSS揭祕實用技巧總結

也可以設定為垂直條紋背景:

background: linear-gradient(to right, #fb3 50%, #58a 0);
background-size: 100% 30px;
複製程式碼

還可以設定為斜向條紋:

background: linear-gradient(45deg, #fb3 25%, #58a 0, #58a 50%, #fb3 0, #fb3 75%, #58a 0);
background-size: 30px 30px;
複製程式碼

CSS揭祕實用技巧總結

斜向條紋需要設定四條條紋才能在平鋪到時候做到無縫拼接。

更好的斜向條紋:(這裡必須設定起始值#fb3 0)

background: repeating-linear-gradient(60deg, #fb3 0, #fb3 15px, #58a 0, #58a 30px);
複製程式碼

CSS揭祕實用技巧總結

網格

  • 關鍵實現:background-imagebackground-size
  • 給多個漸變設定不同的方向、大小,可以實現網格的效果。地址
background: #58a;
background-image: linear-gradient(white 1px, transparent 0),
                  linear-gradient(to right, white 1px, transparent 0);
background-size: 30px 30px;
複製程式碼

CSS揭祕實用技巧總結

更好的網格:

background: #58a;
background-image: linear-gradient(white 2px, transparent 0),
                  linear-gradient(to right, white 2px, transparent 0),
                  linear-gradient(rgba(255, 255, 255, .5) 1px, transparent 0),
                  linear-gradient(to right, rgba(255, 255, 255, .5) 1px, transparent 0);
background-size: 75px 75px, 75px 75px, 15px 15px, 15px 15px;
複製程式碼

CSS揭祕實用技巧總結

棋盤

  • 關鍵實現:background-imagebackground-sizebackground-position
  • 具體分析:給多個漸變設定不同的大小、位置,可以實現網格的效果。地址
  background: #eee;
  background-image:
    linear-gradient(45deg, rgba(0, 0, 0, .25) 25%, transparent 0, transparent 75%, rgba(0, 0, 0, .25) 0),
    linear-gradient(45deg, rgba(0, 0, 0, .25) 25%, transparent 0, transparent 75%, rgba(0, 0, 0, .25) 0);
  background-size: 30px 30px;
  background-position: 0 0, 15px 15px;
複製程式碼

CSS揭祕實用技巧總結

折角

  • 關鍵實現:線性漸變
  • 具體分析:150deg 是為了形成30度角,方便利用勾股定理測出各種長度,其他的靠你自己看了~ 地址

CSS揭祕實用技巧總結

到這裡 background 屬性基本講完了,光看無用,多動手實踐吧。

波點

  • 關鍵實現:徑向漸變
  • 具體分析:利用徑向漸變實現一個個小圓點,按規律擺放即能生成波點 地址
  background:
    radial-gradient(tan 30%, transparent 0),
    radial-gradient(tan 30%, transparent 0);
  background-color: #666;
  background-size: 30px 30px;
  background-position: 0 0, 15px 15px;
複製程式碼

CSS揭祕實用技巧總結

切角

  • 關鍵實現:clip-path、徑向漸變
  • 具體分析:一般來說多邊形的切角效果(其實還是不規則多邊形)用clip-path都可以輕鬆實現,但是對於圓形的切角,使用徑向漸變是最好的選擇。但是如果有弧形的切角呢?radial-linear第一個引數指定漸變的起始點點(預設為中心點),同時可指定漸變型別是橢圓還是圓;地址
  background:
    radial-gradient(circle at top left, transparent 15px, blue 0) top left,
    radial-gradient(circle at top right, transparent 15px, cyan 0) top right,
    radial-gradient(circle at bottom right, transparent 15px, cyan 0) bottom right,
    radial-gradient(circle at bottom left, transparent 15px, cyan 0) bottom left;
  background-size: 50% 50%;
  background-repeat: no-repeat;
複製程式碼

CSS揭祕實用技巧總結

餅圖

  • 關鍵實現:錐形漸變
  • 具體分析:利用錐形漸變可以輕鬆實現多個扇區,所以 svg 的方法權當學習了一波 svg 用法吧。
  background: conic-gradient(lightblue 30%, yellowgreen 0, yellowgreen 50%, cyan 0);
複製程式碼

CSS揭祕實用技巧總結

動畫 animation

animation 屬性是 animation-name、animation-duration、 animation-timing-function、animation-delay、animation-iteration-count、animation-direction、animation-fill-mode、animation-play-state 屬性的一個簡寫屬性形式。

  • animation-name 指定動畫的名稱,可以逗號分割設定多個(以下皆可);
  • animation-duration 指定動畫執行的時間;
  • animation-delay 指定動畫執行前的延時;
  • animation-timing-function 指定動畫執行的速度函式,如linearease(預設)、ease-in-out等,也可用貝塞爾函式cubic-bezier()
  • animation-iteration-count 指定動畫的執行的次數,預設為1,可以為Infinite無限次;
  • animation-direction 指定動畫是否反方向播放,normal 正常的順序,alternate 交替執行,reverse 反向執行,alternate-reverse 反向交替執行;
  • animation-fill-mode 設定CSS動畫在執行之前和之後的樣式,none 不設定,forwards 保留最後一幀動畫的樣式,backwards 立即應用第一個關鍵幀中定義的值,並在animation-delay期間保留此值,both 同時應用forwardsbackwards的規則;
  • animation-play-state 定義一個動畫是否執行或者暫停,值為runningpaused

回彈效果

如何給動畫加上回彈效果呢?這裡介紹一種最便利的方法:

  • 關鍵實現:cubic-bezier(x1, y1, x2, y2)
  • 具體分析:利用貝塞爾曲線的第二個控制錨點大於 1 時的特性實現回彈

CSS揭祕實用技巧總結

上圖圖橫軸為時間,縱軸為動畫進度。圖中貝塞爾曲線有兩個控制手柄,x1, y1 控制第一個錨點,x2, y2控制第二個錨點。其中 x1 、x2 不能大於/小於 1,但是y1, y2 可以。當 y2 大於 1 時,就會產生提前到達終點,然後超過終點,然後再返回終點的效果,像回彈一樣。地址

  animation: bounce 3s both cubic-bezier(.7, .1, .3, 2);
複製程式碼

transition 屬性是 transition-property、transition-duration、transition-timing-function、transition-delay 的一個簡寫屬性。使用 transition 同樣可以實現回彈效果:地址

p {
  transform-origin: 1.4em -.4em;
  transition: transform .5s cubic-bezier(.25, .1, .3, 1.5);
}

input:not(:focus) + p {
  transform: scale(0);
  transition: transform 300ms; /*此處是為了縮小時重置transition-timing-function,不觸發回彈*/
}
複製程式碼

CSS揭祕實用技巧總結

會動的背景

  • 關鍵實現:animationbackground-position
  • 具體分析:將動畫最後一幀的background-position設為100% 0%,動畫便會將背景位置從最初的0% 0%向最後的100% 0%過度:地址
div {
  width: 150px; height: 150px;
  background: url('http://c3.staticflickr.com/3/2671/3904743709_74bc76d5ac_b.jpg');
  background-size: auto 100%;	
  animation: panoramic 10s linear infinite alternate;
}
div:hover {
  animation-play-state: paused;
}

@keyframes panoramic {
  to { background-position: 100% 0; }
}
複製程式碼

環形路徑移動的動畫

  • 關鍵實現:animation transform-origin
  • 具體分析:設定旋轉容器的transform-origin為大圓容器中心點,同時利用兩個元素在向不同方向旋轉時旋轉角度互相抵消的原理,實現影像沿環形路徑旋轉同時保持自身角度的不變。注意小圓距離大圓的距離由大圓的padding屬性控制,調整padding時需要調整小圓的旋轉原點transform-origin以保持環形路徑的正確:地址
@keyframes spin {
  to { transform: rotate(1turn); }
}
.avatar {
  animation: spin 3s linear 2s infinite;
  transform-origin: 110px 110px;
}
.avatar > img {
  animation: inherit;
  animation-direction: reverse;
}
複製程式碼

CSS揭祕實用技巧總結

筆者推薦css文章

其實現在社群已經不乏介紹 css 技巧的好文,這裡推薦幾篇我覺得寫的極好的css技巧文章(當然可能大家也看過,很慚愧我其實現在也沒看完):

總結

總體來說,《css揭祕》這本書並沒有給我帶來太大驚喜,個人感覺不如閱讀《css世界》帶來的收穫多。當然了,這本書屬於純技巧型的,並沒有講述很多原理知識,所以也不能苛責吧。有興趣的同學可以跟著我學習一波 css世界,相信肯定會有更大的收穫~

相關文章