《CSS揭祕》讀書筆記

Madman0621發表於2019-05-02

摘要

《CSS揭祕》主要是介紹了使用CSS的技巧,通過47個案例來靈活的使用CSS進行實現,同時在實現過程中注重CSS程式碼的靈活性與健壯性。通過閱讀這本書有利於我們編寫高質量的CSS程式碼以及打破使用CSS時的固定思維,能夠更加靈活的使用CSS。

《CSS揭祕》中的所有案例程式碼均上傳到:play.csssecrets.io/。

關於《CSS揭祕》的讀書筆記主要是記錄通過閱讀書中的CSS案例所獲得啟發和對CSS樣式新的認知點。

第二章 背景與邊框

background-clip

background-clip屬性設定元素的背景(背景圖片或顏色)覆蓋到什麼位置。
屬性值為:border-box(預設值) | padding-box | content-box | text
注:text屬性值是設定將背景被裁剪為文字的前景色(chrome瀏覽器支援需要新增-webkit-字首;最新版本的火狐瀏覽器 [ 63.0.3 (64 位) ]直接支援background-clip: text 屬性)。

background-origin

background-origin規定了指定背景圖片background-image屬性的原點位置的背景相對區域。
屬性值為:border-box | padding-box(預設) | content-box

多重邊框

傳統做法:通過多重元素巢狀來生成多重邊框。

新的思路:
方法一:通過box-shadow的第四個引數可以讓投影面積增大或者縮小,設定box-shadow: 0 0 0 10px #809;得到的“投影”其實就像一道實線邊框,並且box-shadow支援逗號分割法,因此我們可以建立任意數量的投影。
缺點:邊框的樣式單一,只能夠是實線邊框。

方法二:通過outline描邊屬性來設定第二重邊框
缺點:只能夠適用於兩重邊框(border一重,outline一重),並且outline的描邊不能夠貼合border-radius的圓角,只能夠是矩形。

背景圖片的靈活定位

傳統做法:通過計算元素的大小,設定background-position的位置。

新的思路:
方法一:background-position屬性模式是通過左上角進行定位的,可以隨機指定距離任意角的偏移量,background-position:left 20px top 30px;

方法二:通過calc()函式來實時計算background-position的位置,background-position: calc(100% - 20px) calc(100% - 30px);

方法三:可以通過background-origin:content-box,使得background-position以內容區的左上角作為基準,圖片距離邊角的偏移量等於內邊距。

邊框內圓角(矩形容器,內側有圓角)

傳統做法:通過兩個div巢狀,內部的div設定為圓角,外部的div保持矩形邊框形狀。

新的思路:outline屬性結合box-shadow屬性。
1、通過outline可以為border-radius描邊,但是描邊為矩形,與圓角之前存在空白縫隙,通過box-shadow可以填充縫隙。
2、需要填充的縫隙大小為,圓角半徑為r,圓心到描邊頂角的距離為√2 r,因此填充的距離為(√2 - 1)r
缺點:因為box-shadow的寬度至少需要設定為(√2 - 1)r,如果描邊的寬度小於這個值,那麼描邊將會被box-shadow遮住。

linear-gradient()

linear-gradient()函式建立一個漸變“影像”
函式內容為:linear-gradient(direction, colorItem1,colorItem2...)
1、角度設定是根據時鐘順時針進行計算的;
2、下一個顏色開始位置與上一個顏色的結束位置一致,則不需要填充顏色之間空餘的位置,形成不同的顏色條而非過渡條;
3、當後面顏色位置小於前面顏色位置時,瀏覽器之間將後面顏色位置更正為與前面顏色位置一致。

repeating-linear-gradient()

repeating-linear-gradient()建立一個重複線性漸變的“影像”
函式內容為:repeating-linear-gradient(direction, colorItem1,colorItem2...)
每次重複時,色標位置的偏移量都是基準漸變長度(最後一個色標和第一個之間的距離)的倍數,因此要設定開始處(0位置)的顏色。

條紋背景

傳統做法:通過兩種顏色進行設定

新的思路:
方法一:首先通過background-color設定背景色,然後通過background-image:linear-gradient(rgba(0,0,0,0.2) 50%,transparent 50%);以及background-size:auto 2em;建立一個“黑白條”蓋在上面並且高度為2em(1em代表為1行)。

background-color:red;
background-image:linear-gradient(rgba(0,0,0,0.2) 50%,transparent 50%);
background-size:auto 2em;
複製程式碼

方法二:通過linear-gradient()直接設定兩種顏色,然後設定background-size 大小,根據background直接複製平鋪。

方法三:通過repeating-linear-gradient()直接設定顏色自動重複。

錯落相間的背景圖案

1、通過設定兩個linear-gradient(),然後各自設定其background-position,來使的背景圖案錯落開來。
2、矩形的背景圖案,可以通過linear-gradient()45deg的建立2個直角三角形拼接而成。

帶有圖案的邊框

傳統做法:通過建立兩個div,外層的div設定背景圖片,內層的div在背景圖片上覆蓋一層白色背景色,兩層之間的差距就形成了圖案邊框。

新的思路:
1、background可以設定多個背景,但是白色背景色會預設在最底層,無法上浮到圖片上方,所以白色背景色通過線性漸變來實現,並且將背景圖片的鋪蓋範圍設定為border-box。
2、background-origin預設值是padding-box,因此圖片預設是放置在padding-box的原點上,然後通過平鋪複製蔓延到border-box,因此border區域的圖片顯示異常,所以要將border-origin設定border-box。

padding: 1em;
border: 1em solid transparent;
background: linear-gradient(white, white),
	        url(https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSGTVf63Vm3XgOncMVSOy0-jSxdMT8KVJIc8WiWaevuWiPGe0Pm);
background-size:cover;
background-clip:padding-box,border-box;
background-origin:border-box;
複製程式碼

注:除了圖片之外還可以通過漸變來實現有規律的邊框圖案。

第三章 形狀

半橢圓/四分之一橢圓/八分之一橢圓

通過border-radius可以分別設定每個角的水平和垂直圓形半徑,進而達到對每個角的變形設定。

平行四邊形

傳統做法:對元素新增skew()屬性進行變形。
缺點:元素的形狀是發生了改變,但是內部的文字和其他元素也都全部發生了變形。

新的思路:
方法一:通過巢狀元素,外部元素負責形狀的變形,內部元素進行反向變形,使元素恢復正常。如果需要圖片填充變形的形狀,除了對內部圖片進行反向變形外,還需要scale放大,填充滿整個變形圖案。
缺點:需要新增額外的html元素。

方法二:通過新增偽元素,讓偽元素來完成形狀的變形,元素本身不發生變化。
缺點:無法使圖片填充變形的形狀。

.button {
	position: relative;
	display: inline-block;
}
.button::before {
	content: ''; /* To generate the box */
	position: absolute;
	top: 0; right: 0; bottom: 0; left: 0; /* 能夠自適應元素大小的變化 */
	z-index: -1; /* 背景顏色不會覆蓋在字型上方 */
	background: #58a;
	transform: skew(45deg);
}
複製程式碼

注:以上方法適用於任何我們想要變形一個元素而不想變形它的內容情況

菱形圖片

除了使用“平行四邊形”中的方法一來建立一個菱形圖片之外,還可以使用clip-path屬性來直接對圖片元素進行裁剪。
缺點:需要提前考慮clip-path屬性的相容性。

img {
	-webkit-clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
	clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
複製程式碼

切角效果

方法一:
1、切角效果的核心方式就是使用:linear-gradient(45deg, transparent 15px, red 0);通過漸變來實現一個透明的小角,導致視覺效果像切角了。
2、當對元素進行多個切角時,將背景進行劃分,每塊單獨做切角處理,然後定位每塊的位置,“拼接”成一個背景。

div{
	background: #58a;
	background: linear-gradient(135deg, transparent 15px, #58a 0) top left,
	            linear-gradient(-135deg, transparent 15px, #58a 0) top right,
	            linear-gradient(-45deg, transparent 15px, #58a 0) bottom right,
	            linear-gradient(45deg, transparent 15px, #58a 0) bottom left;
	background-size: 50% 50%;
	background-repeat: no-repeat;
}
複製程式碼

3、要實現弧形切角(內凹圓角)時,只需要將徑向漸變替換線性漸變即可。

div{
	background: #58a;
	background:	radial-gradient(circle at top left, transparent 15px, #58a 0) top left,
	            radial-gradient(circle at top right, transparent 15px, #58a 0) top right,
	            radial-gradient(circle at bottom right, transparent 15px, #58a 0) bottom right,
	            radial-gradient(circle at bottom left, transparent 15px, #58a 0) bottom left;
	background-size: 50% 50%;
	background-repeat: no-repeat;
}
複製程式碼

缺點:只能是純色背景。

方法二:通過SVG畫一個切角效果的圖片,然後基於border-image的工作原理,將切角效果應用於border上。

div{
	border: 15px solid transparent;
	border-image: 1 url('data:image/svg+xml,\
	                      <svg xmlns="http://www.w3.org/2000/svg" width="3" height="3" fill="%2358a">\
	                      <polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2" />\
	                      </svg>');
	background: #58a;
	background-clip: padding-box;
}
複製程式碼

缺點:背景顏色只能是純色或者是邊緣接近純色的背景圖片。

方法三:使用clip-path對元素進行裁剪,裁剪出切角效果,無論你的背景是什麼這種方法都能夠適用,但是要注意clip-path屬性的相容性。

div {
	height:50px;
	background: #58a;
	-webkit-clip-path: 
		polygon(20px 0, calc(100% - 20px) 0, 100% 20px, 100% calc(100% - 20px),
		calc(100% - 20px) 100%,
		20px 100%, 0 calc(100% - 20px), 0 20px);
	clip-path:
	 	polygon(20px 0, calc(100% - 20px) 0, 100% 20px, 100% calc(100% - 20px),
	 	calc(100% - 20px) 100%,
	 	20px 100%, 0 calc(100% - 20px), 0 20px);
}
複製程式碼

梯形圖案

1、通過元素3D旋轉投影成2D的梯形形狀,然後通過scale將元素按照比例放大,彌補因為旋轉造成的高度縮小。
2、通過固定元素的transform-origin,選擇元素的哪幾條邊不需要變化。
3、使用新增偽元素變形方案,因為3D旋轉無法進行反向變形,因此不採納巢狀元素變形方案。
缺點:同種旋轉角度不同的寬度,梯形元素的傾斜角因為寬度原因會不相同。

div::before {
	content: ''; /* To generate the box */
	position: absolute;
	top: 0; right: 0; bottom: 0; left: 0;
	z-index: -1;
	background: red;
	transform: scaleY(1.5) perspective(.5em) rotateX(5deg);
	transform-origin: bottom; /* 通過設定transform-origin為bottom left或bottom right可以得到左側傾斜和右側傾斜的梯形 */
}
複製程式碼

餅狀圖

方法一:
步驟一:
1、通過建立一個陰陽圖,左邊為餅狀圖預設顏色,右邊為餅狀圖顯示顏色。
2、0~50%通過建立偽元素(顏色為預設顏色),擋住右邊的顯示顏色,通過旋轉(0~0.5turn),一點點將顯示顏色顯示出來。
3、50%~100%通過建立偽元素(顏色為顯示顏色),通過旋轉(0~0.5turn),一點點覆蓋左邊的預設顏色。
4、通過animation切換偽元素背景色與重置旋轉角度。

.pie {
	width: 100px; height: 100px;
	border-radius: 50%;
	background: yellowgreen;
	background-image: linear-gradient(to right, transparent 50%, currentColor 0);
	color: #655;
}

.pie::before {
	content: '';
	display: block;
	margin-left: 50%;
	height: 100%;
	border-radius: 0 100% 100% 0 / 50%;
	background-color: inherit;
	transform-origin: left;
	animation: spin 3s linear infinite, 
				bg 6s step-end infinite;
}

@keyframes spin {
	to { transform: rotate(.5turn); }
}
@keyframes bg {
	50% { background: currentColor; }
}
複製程式碼

步驟二:
1、通過animation-delay將直接跳轉到動畫的指定時間點。

// html
<div class='pie'>50%</div>
// css
.pie {
	display: inline-block;
	position: relative;
	width: 100px;
	line-height: 100px;
	border-radius: 50%;
	background: yellowgreen;
	background-image: linear-gradient(to right, transparent 50%, #655 0);
	color: transparent;
	text-align: center;
}

@keyframes spin {
	to { transform: rotate(.5turn); }
}
@keyframes bg {
	50% { background: #655; }
}

.pie::before {
	content: '';
	position: absolute;
	top: 0; left: 50%;
	width: 50%; height: 100%;
	border-radius: 0 100% 100% 0 / 50%;
	background-color: inherit;
	transform-origin: left;
	animation: spin 50s linear infinite,
				bg 100s step-end infinite;
	animation-play-state: paused;
	animation-delay: inherit;
}
// js
var _dom = document.querySelector('.pie')
_dom.style.animationDelay = '-' + parseFloat(_dom.textContent) + 's';
複製程式碼

方法二:
1、使用SVG中的虛線描邊,將圓形描邊的大小設定為半徑的2倍,能夠完全覆蓋圓形。
2、設定虛線的間隔為圓形的周長,能夠保證只顯示一塊虛線。
3、設定虛線的長度為所佔比例,顯示出我們所需要的餅狀圖。

// html
<svg viewBox='0 0 32 32'>
	<circle r='16' cx='16' cy='16'
</svg>
// css
svg {
	width:100px;
	height:100px;
	background:yellowgreen;
	border-radius:50%;
	transform:rotate(-90deg);
}
circle{
	fill:yellowgreen;
	stroke:#655;
	stroke-width:32; 
	stroke-dasharray:20 100; /* 半徑為16,會使的周長剛剛好為100,通過設定虛線長度,直接就能夠顯示為百分比餅狀圖 */
}
複製程式碼

總結

通過以上的案例發現,元素的變形主要通過以下幾種方式:
方法一:使用transform變形屬性對元素進行2D/3D變形,然後通過scale方法元素來彌補因為變形所造成的寬高損失。

方法二:使用clip-path屬性直接對元素進行裁剪。

方法三:使用linear-gradient()對元素進行處理。

第四章 視覺效果

單側投影/鄰邊投影/雙側投影

1、box-shadow的第四個引數,稱為擴張半徑,可以根據指定的值去擴大或者縮小投影的的尺寸。
2、根據擴張尺寸,投影時如果陰影在別的邊漫出來了,我們可以設定擴張尺寸為負,這樣就能夠在保留陰影效果的同時,將其他邊的陰影縮排去已到達去除陰影的效果。

不規則投影

1、box-shadow的投影無法作用於偽元素或者半透明的裝飾上(比如虛線中間的縫隙,切角效果)
方法一:使用CSS濾鏡filter屬性的drop-shadow()函式,它可以為任何非透明的地方新增上陰影,引數等同於box-shadow但是不支援inset關鍵字和擴張半徑。

div {
	filter:url(drop-shadow.svg#drop-shaodow) // 附上一個SVG濾鏡可以得到稍好一點的瀏覽器支援度
	filter: drop-shadow(2px 2px 10px rgba(0,0,0,.5));
}
複製程式碼

缺點:drop-shaodow可以為任何非透明的地方新增上陰影,因此如果你的背景是透明的,則drop-shadow會為字型新增上陰影。

圖片染色效果

方法一:在圖片的上層覆蓋一層半透明的純色或者把圖片設為半透明並覆蓋在一層實色背景之上。
缺點:並不是真正的染色效果,並且削弱了圖片的對比度。

方法二:把圖片放置在<canvas>中,並利用指令碼對其進行染色處理。

方法三:通過多個filter濾鏡組合對圖片進行處理。

img {
	// 根據需求自由組合濾鏡
	filter: 
		sepia()  // 將影像轉換為深褐色
		saturate(4) // 轉換影像飽和度
		hue-rotate(295deg); // 給影像應用色相旋轉
}
複製程式碼

缺點:當新增動畫將img切換會原圖的效果時,切換效果不是一點點的漸變而是將濾鏡一個個剔除的過渡變化。

方法四:混合模式-mix-blend-mode,只需要把圖片包裹在一個容器中,併為這個容器的背景色設定為我們想要的主色調。

<div>
	<img src='demo.jpg'/>
</div>
div {
	background:rgba(255,0,0,0.5);
}
img {
	mix-blend-mode:luminosity;
}
複製程式碼

缺點:要注意屬性的相容性,混合模式不支援動畫,可以將容器的背景色設定為透明來實現正常/染色的切換。

方法五:混合模式-background-blend-mode,只需要使用一個div元素,將第一層背景設定為要染色的圖片,將第二層背景設定為我們想要的主色調。

<div style="background-image:url(demo.jpg)"></div>
div {
	width: 640px; 
	height: 440px;
	background-size: cover;
	background-color: rgba(255,0,0,0.5);
	background-blend-mode: luminosity;
}
複製程式碼

缺點:要注意屬性的相容性,混合模式不支援動畫,可以將容器的背景色設定為透明來實現正常/染色的切換。

毛玻璃效果

1、背景圖片之上存在文字,文字層所覆蓋的那部分圖片區域作模糊處理。
方法一: 為文字層新增一個偽元素,偽元素的設定的背景圖片與之前的背景圖片一致,導致偽元素的背景圖片重疊在原背景圖片上方,然後只需要對偽元素背景圖片做模糊處理就可以了。

div, .text::before {
	background: url("demo.jpg") 0 / cover fixed;
}

.text {
	position: relative;
	background: hsla(0,0%,100%,.25) border-box; 
	overflow: hidden;
}

.text::before {
	content: '';
	position: absolute;
	top: 0; right: 0; bottom: 0; left: 0;
	margin: -30px; // 模糊到文字層邊緣的時候會消失,擴大一圈區域,避免邊緣無模糊。
	z-index: -1;
	-webkit-filter: blur(10px);
	filter: blur(10px);
}
複製程式碼

折角效果

1、使用漸變描繪一個空白的折角區域。
2、通過偽元素建立一個折角,通過三角函式來計算折角的大小,通過折角的角度來計算折角旋轉角度和偏移角度,來創造出合乎常理的折角效果。
缺點:只能夠對純色背景進行折角效果。

第五章 字型排印

插入換行

傳統做法:通過<br/>標籤來進行換行

新的思路:可以通過:before或:after偽類選擇器中的content設定為“\A”來進行換行,因為Unicode字元中代表換行符的為“0x000A”,在CSS中可以寫為“\000A”或者簡化為“\A”

div::after {
	content: "\A";
	white-space: pre; // 能夠保留原始碼中空白和換行符,否則content中的換行符將被忽略。
}
複製程式碼

tab-size屬性

在需要展示程式碼的網頁上時,通過設定tab-size屬效能夠指定一個tab縮排幾個字元。

為某些字元單獨設定字型

傳統做法:為需要單獨設定字型的字元設定class,通過class為它們設定獨特的字型。

新的思路:@font-face中的unicode-range屬性可以設定字型的適用於哪些字元。

@font-face {
	font-family: demoFont;
	src: local('Baskerville-Italic'), local('GoudyOldStyleT-Italic'); /* 應用於指定字元的字型 */
	unicode-range: U+26; /* 設定生效字元,'&'的Unicode碼位,可以通過'&'.chatCodeAt(0).toString(16)獲取'&'的十六進位制碼位'26',然後前面加上'U+'字首 */
}

p {
	font-family: demoFont, Helvetica; /* demoFont字型只應用於'&'字元,其他字元會適用後續的字型'Helvetica' */
}
複製程式碼

自定義文字下劃線

傳統做法:通過text-decoration:underline;

新的思路:
1、通過background與background-size設定一條自定義格式的下劃線;
2、通過text-shadow可以讓字元周圍出現一圈白邊,使的顯示為下劃線遇到字母的降部自動斷開避讓。
3、文字最好放置在行內元素內,這樣下劃線才能隨這文字的換行也進行換行。

span {
	background: linear-gradient(gray, gray) no-repeat;
	background-size: 100% 1px;
	background-position: 0 1.2em;
	text-shadow: .05em 0 white, -.05em 0 white;
}
複製程式碼

空心字效果/文字外發光效果/文字凸起效果

通過text-shadow為文字新增效果來實現。

環形文字

1、通過SVG的path畫出一個圓形。
2、通過text與textPath新增文字,並通過xlink:href屬性將文字連結到路徑上。

<div class='demo'>
	<svg viewBox='0 0 100 100'>
		<path d='M0,50 a50,50 0 1,1 0,1z' id='circle'></path>
		<text>
			<textPath xlink:href="#circle">fdsfdsfdsfdsfsdfdsfsdfds</textPath>		
		</text>
	</svg>
</div>

.demo {
	width:300px;
	height:300px;
	margin: 4em auto 0;
}
svg{
	display:block;
	overflow: visible;
}
path {
	fill:none;
}
複製程式碼

注:這種方法不但適用於環形文字還適用於所有需要特殊路徑排序的文字。

第六章 使用者體驗

擴大使用者互動熱區

方法一:使用透明的border擴大互動熱區。使用background-clip重新定義背景的填充區域。

.demo1 {
	border:20px solid transparent;
	background-clip:padding-box;
	/* 實際border-radius效果值為border-radius減去border的值 */
	border-radius:25px;
	box-shadow: 0 0 0 1px rgba(0,0,0,0.3) inset;
}
複製程式碼

注:
1、如果要設定border-radius的值時需要注意,實際border-radius效果值為border-radius減去border的值。
2、如果要設定邊框可以通過內嵌投影在模擬出一道實色邊框。
缺點:無法為元素設定box-shadow陰影效果,因為陰影效果時設定border-box外面的。

方法二:使用一個偽元素,擴大偽元素的範圍,偽元素的範圍也可以觸發熱區。通過偽元素可以隨意設定熱區的尺寸、位置、形狀。

.demo2 {
	position:relative;
}
.demo2:before {
	content:'';
	position:absolute;
	top:-10px;
	bottom:-10px;
	left:-10px;
	right:-10px;
}
複製程式碼

自定義check樣式

使用label與checkbox進行相關聯,然後將checkbox隱藏起來,最後通過設定label偽元素的樣式來頂替checkbox的樣式。

建立蒙層

傳統做法:建立一個額外HTML元素來設定為蒙層。

新的思路:
方法一:通過body上的偽元素來設定為蒙層。
缺點:偽元素無法繫結獨立的JS事件處理函式以及對於元素的z-index設定可能會出現偏差。

方法二:通過box-shadow來設定蒙層。box-shoadow: 0 0 0 50vmax rgba(0,0,0,.8)
缺點:只能覆蓋當前視窗,頁面如果滾動就會露餡以及無法阻止使用者與頁面其他元素互動。

方法三:使用dialog元素backdrop偽元素可以只能蒙層。
缺點:要考慮backdrop偽元素的相容性。

彈出視窗背景模糊

實現效果類似毛玻璃效果,只是模糊的不是一張背景圖片而是頁面上的任意元素。
方法一:頁面的元素全部包裹在一個div中,dialog與這個div同級,dialog彈出的時候,將這個div新增上模糊濾鏡blur().

滾動提示

方法一:
1、background-attachment:scroll可以使的背景圖片隨著元素滾動而固定在元素上,因此可以在滾動的時候建立一個漸變陰影。這樣滾動的時候上方都會存在一個陰影。
2、background-attachment:local可以使背景圖片相對於元素的內容固定,因此可以建立一個白色遮罩層當使用者滾動到頂部的時候遮擋住陰影。

ul {
	overflow: auto;
	background: linear-gradient(white 15px,rgba(255,255,255,0)),
		radial-gradient(at top, rgba(0,0,0,.9), transparent 70%);
	background-repeat:no-repeat;
	background-size:100% 50px,100% 15px;
	background-attachment: local, scroll;
}
複製程式碼

互動式圖片對比

方法一:將兩張圖片重疊在一起,然後通過resize:horizontal來調節覆蓋在上層的圖片width。

<div class="image-slider">
	<div>
		<img src="https://user-gold-cdn.xitu.io/2019/5/2/16a777e69b3ab1e4?w=400&h=400&f=jpeg&s=57981" alt="Before" />
	</div>
	<img src="https://user-gold-cdn.xitu.io/2019/5/2/16a777e6a9e65856?w=400&h=400&f=jpeg&s=63250" />
</div>

.image-slider {
	position:relative;
	display: inline-block;
}

.image-slider > div { /* 覆蓋在上層的圖片 */
	position: absolute;
	top: 0; bottom: 0; left: 0;
	width: 50%;
	max-width: 100%;
	overflow: hidden;
	resize: horizontal;
}

.image-slider img {
	display: block;
	user-select: none;
}
複製程式碼

第七章 結構與佈局

自適應內部元素

width與height中存在一些關鍵詞,其中width:min-content將會解析為這個容器內最大的不可斷行元素的寬度(即最寬的單詞、圖片和具有固有寬度的盒元素)

<figure>
	<img src="https://user-gold-cdn.xitu.io/2019/5/2/16a777e6a9e65856?w=400&h=400&f=jpeg&s=63250" />
	<figcaption>
		The great Sir Adam Catlace was named after Countess Ada Lovelace, the first programmer ever.
	</figcaption>
</figure>

figure {
	max-width: 300px; /* 相容回退處理 */
	max-width: min-content;
	margin: auto;
}

figure > img { max-width: inherit }
複製程式碼

精確控制表格樣式

通過table-layout:fixed能夠讓我們更加自由的控制表格中的種種樣式。

根據兄弟元素數量/範圍設定樣式

1、只有1個子元素

li:only-child { /* code */}
或
li:first-child:nth-last-child(1) {/* code */ } /* 元素是第一個元素同時也是最後一個元素,就等同於只有一個元素 */
複製程式碼

2、判斷有多少個元素

li:first-child:nth-last-child(4) {/* code */ } /* 元素是第一個元素同時也是倒數第四個元素,就等同於一共有四個元素 */
li:first-child:nth-last-child(4)~ li {/* code */} /* 當列表只有4個元素時,為列表設定樣式 */
複製程式碼

3、根據兄弟元素範圍

li:first-child:nth-last-child(n+4)~ li {/* code */} /* n可以為任何數,表示當列表至少含有4個元素時,為列表設定樣式 */
li:first-child:nth-last-child(-n+4)~ li {/* code */} /* n可以為任何數,表示當列表最多含有4個元素時,為列表設定樣式 */
li:first-child:nth-last-child(n+2):nth-last-child(-n+6)~ li {/* code */} /* n可以為任何數,表示當列表含有2~6個元素時,為列表設定樣式 */
複製程式碼

滿幅的背景,定寬的內容

傳統做法:外層的html元素設定為滿幅的背景,然後內層html設定為定寬居中的內容。
缺點:需要額外一層html元素。

新的思路:通過calc()函式來設定內容的左右邊距,使其定寬居中。

outer {
	padding:0 calc(50% - 450px);/* 通過calc()函式計算內容居中時元素的左右邊距;450px為內容定寬900px/2計算得到 */
}
複製程式碼

垂直居中

CSS 技巧篇(七):設定元素居中

緊貼底部的頁尾

方法一:設定mai主體元素的min-height為視窗高度減去footer的高度。

.main {
	min-height:calc(100vh - 100px) /* 100px為footer的高度*/
}
複製程式碼

缺點:要求footer的高度必須是固定已知的。

方法二:將body元素設定為flexBox,然後設定main主體元素設定為flex:1。

body {
	display:flex;
	flex-flow:colum;
	min-height:100vh;
}
.main {
	flex:1;
}
複製程式碼

第八章 過渡與動畫

緩動效果

在animation或者transition中的調速引數除了ease等關鍵詞之外,還可以通過cubic-bezier()函式自定義調速函式。
cubic-bezier()函式線上除錯可以前往貝塞爾曲線線上除錯。

逐幀動畫(以loading動畫為例)

傳統做法:設定為一張gif圖片。
缺點:gif無法設定為透明並且無法修改動畫的屬性。

新的思路:將動畫劃分為逐幀的圖片,然後通過animation對圖片進行過渡切換,steps()能夠將動畫切分為多幀,而且是幀與幀之間的硬切。

@keyframes loader {
	to { background-position: -800px 0; }
}

.loader {
	width: 100px; height: 100px;
	text-indent: 999px; overflow: hidden; /* Hide text */
	background: url(http://dabblet.com/img/loader.png) 0 0;
	animation: loader 1s infinite steps(8);
}
複製程式碼

閃爍效果

方法一:動畫的50%設定為transparent,這樣動畫就形成了從有->無→有的變化。

@keyframes blink { 50% { color: transparent } }
.blink-smooth {
	animation: 1s blink 3;
}
複製程式碼

方法二:通過animation中的animation-direction:alternate屬效能夠設定動畫的迴圈週期。

@keyframes blink { to { color: transparent } }
.blink-smooth {
	animation: .5s blink 6;
	animation-direction: alternate;
}
複製程式碼

打字動畫

1、通過animation和steps控制width的值,將字元一個個的顯示出來;
2、通過border-right來創造游標;
3、ch可以表示為每一個字元的寬度。

@keyframes typing {
	from { width: 0 }
}

@keyframes caret {
	50% { border-right-color: currentColor; }
}

h1 {
	/*width: 8.25em;*/
	width: 15ch; /* ch單位為每個字元的寬度。 */
	white-space: nowrap; /* 禁止內容換行 */
	overflow: hidden;
	border-right: .05em solid transparent; /* 通過border-right來創造游標 */
	animation: typing 8s steps(15),   /* 打字動畫 */
	           caret 1s steps(1) infinite; /* 游標動畫 */
}
複製程式碼

沿環形路徑平移的動畫

方法一:在圖片外在包裹一層div,div為順時針圍繞一個大圓的圓心正常旋轉,而img則是相對自身中心逆時針旋轉來抵消外部旋轉。

<div class="path">
	<div class="avatar">
		<img src="https://user-gold-cdn.xitu.io/2019/5/2/16a777e684aa60d7?w=400&h=400&f=jpeg&s=63250" />
	</div>
</div>

@keyframes spin {
	to { transform: rotate(1turn); }
}

.avatar {
	animation: spin 3s infinite linear;
	transform-origin: 50% 150px;
}

.avatar > img {
	animation: inherit;
	animation-direction: reverse;
}

/* Anything below this is just styling */

.avatar {
	width: 50px;
	margin: 0 auto;
	border-radius: 50%;
	overflow: hidden;
}

.avatar > img {
	display: block;
	width: inherit;
}

.path {
	width: 300px; height: 300px;
	padding: 20px;
	border-radius: 50%;
	background: #fb3;
}
複製程式碼

方式二:通過translate的移動來頂替transform-origin的效果

<div class="path">
	<img src="https://user-gold-cdn.xitu.io/2019/5/2/16a777e684aa60d7?w=400&h=400&f=jpeg&s=63250" class="avatar" />
</div>

@keyframes spin {
	from {
		transform: 
				   translateY(150px) translateY(-50%)
				   rotate(0turn)
		           translateY(-150px) translateY(50%)
		           rotate(1turn)
	}
	to {
		transform: 
				   translateY(150px) translateY(-50%)
				   rotate(1turn)
		           translateY(-150px) translateY(50%)
		           rotate(0turn);
	}
}

.avatar {
	animation: spin 3s infinite linear;
}

/* Anything below this is just styling */

.avatar {
	margin: 0 auto;
	display: block;
	width: 50px;
	border-radius: 50%;
	overflow: hidden;
}

.path {
	width: 300px; height: 300px;
	padding: 20px;
	border-radius: 50%;
	background: #fb3;
}
複製程式碼

總結 總結正文

相關文章