現代網頁設計中,動畫和過渡是提升用戶體驗的重要手段。通過使用 CSS,我們可以在不影響頁面性能的前提下,實現平滑和吸引人的視覺效果。本文將介紹 CSS 動畫和過渡的基礎知識,并通過幾個例子展示如何在你的網站中應用它們。
CSS 過渡允許你在 CSS 屬性值之間創建平滑的動畫效果。當一個元素的屬性值改變時,過渡效果會在一定時間內平滑地過渡到新的屬性值。
transition: property duration timing-function delay;
img:hover {
transform: scale(1.2);
transition: transform 0.3s ease-in-out;
}
這個例子中,當鼠標懸停在圖片上時,圖片會在0.3秒內放大到原來的1.2倍大小,過渡效果為ease-in-out。
CSS 動畫提供了更強大的控制,允許你創建復雜的動畫序列,通過定義關鍵幀(keyframes)來控制動畫的中間狀態。
@keyframes animation-name {
from {
/* 初始狀態 */
}
to {
/* 結束狀態 */
}
}
或者使用百分比來定義多個關鍵幀:
@keyframes animation-name {
0% { /* 初始狀態 */ }
50% { /* 中間狀態 */ }
100% { /* 結束狀態 */ }
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.icon-spin {
animation: spin 2s linear infinite;
}
這個例子創建了一個名為spin的動畫,使得圖標無限期地旋轉。
接下來,我們將通過幾個實戰例子來展示 CSS 動畫和過渡的具體應用。
.button {
position: relative;
overflow: hidden;
transition: background-color 0.3s;
}
.button:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 5px;
height: 5px;
background: rgba(255, 255, 255, 0.7);
opacity: 0;
border-radius: 100%;
transform: scale(1, 1) translate(-50%);
transform-origin: 50% 50%;
}
.button:active:after {
width: 300px;
height: 300px;
opacity: 1;
transition: width 0.5s, height 0.5s, opacity 0s 0.5s;
}
在這個例子中,當按鈕被點擊時,會產生一個波紋效果,模擬水波紋擴散。
.fade-in {
animation: fadeIn 1s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-out {
animation: fadeOut 1s ease-in-out;
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
這個例子中定義了兩個動畫,一個用于元素的淡入,另一個用于元素的淡出。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS Animation and Transition Example</title>
<style>
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 400% 400%;
animation: gradientBG 15s ease infinite;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
min-height: 100vh;
}
@keyframes gradientBG {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.logo {
font-size: 2em;
color: #007bff;
margin-bottom: 20px;
animation: spin 3s linear infinite;
}
.scrolling-text {
margin: 20px 0;
background-color: #333;
color: #fff;
padding: 10px;
white-space: nowrap;
overflow: hidden;
position: relative;
}
.scrolling-text p {
position: absolute;
width: 100%;
height: 100%;
margin: 0;
line-height: 50px;
text-align: center;
/* Starting position */
transform: translateX(100%);
/* Apply animation to this element */
animation: scroll-text 10s linear infinite;
}
@keyframes scroll-text {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
.interactive-card {
background-color: #fff;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
padding: 20px;
margin: 20px;
border-radius: 10px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.interactive-card:hover {
transform: translateY(-10px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.color-block {
width: 100px;
height: 100px;
background-color: #17a2b8;
margin: 20px;
border-radius: 50%;
transition: background-color 0.5s ease, transform 0.5s ease;
}
.color-block:hover {
background-color: #28a745;
transform: rotate(180deg);
}
</style>
</head>
<body>
<div class="logo">
<i class="fas fa-sync-alt"></i> Animated Logo
</div>
<div class="scrolling-text">
<p>This text scrolls infinitely. Pay attention to how it moves smoothly from right to left.</p>
</div>
<div class="interactive-card">
<h3>Interactive Card</h3>
<p>Hover over this card to see it move. It's a simple yet effective way to add interactivity to your design.</p>
</div>
<div class="color-block"></div>
</body>
</html>
CSS 動畫和過渡是前端開發者的強大工具,它們可以在不犧牲性能的情況下為用戶提供流暢、引人注目的界面交互。通過掌握這些技術,你可以創造出更加動態和生動的網頁體驗。記住,動畫應該用來增強用戶體驗,而不是分散用戶的注意力,適量而恰當地使用動畫效果是關鍵。
多大公司面試喜歡問這樣一道面試題,輸入URL到看見頁面發生了什么? 簡單來說,共有以下幾個過程:
DNS解析
DNS解析實際上就是尋找你所需要的資源的過程。假設你輸入www.baidu.com,而這個網址并不是百度的真實地址,互聯網中每一臺機器都有唯一標識的IP地址,這個才是關鍵,但是它不好記,亂七八糟一串數字誰記得住啊,所以就需要一個網址和IP地址的轉換,也就是DNS解析。下面看看具體的解析過程
具體解析
DNS解析其實是一個遞歸的過程
輸入www.google.com網址后,首先在本地的域名服務器中查找,沒找到去根域名服務器查找,沒有再去com頂級域名服務器查找,,如此的類推下去,直到找到IP地址,然后把它記錄在本地,供下次使用。大致過程就是.-> .com ->google.com. -> www.google.com。 (你可能覺得我多寫 .,并木有,這個.對應的就是根域名服務器,默認情況下所有的網址的最后一位都是.,既然是默認情況下,為了方便用戶,通常都會省略,瀏覽器在請求DNS的時候會自動加上)DNS優化
既然已經懂得了解析的具體過程,我們可以看到上述一共經過了N個過程,每個過程有一定的消耗和時間的等待,因此我們得想辦法解決一下這個問題!
DNS緩存
DNS存在著多級緩存,從離瀏覽器的距離排序的話,有以下幾種: 瀏覽器緩存,系統緩存,路由器緩存,IPS服務器緩存,根域名服務器緩存,頂級域名服務器緩存,主域名服務器緩存。
DNS負載均衡
不知道你們有沒有注意這樣一件事,你訪問baidu.com的時候,每次響應的并非是同一個服務器(IP地址不同),一般大公司都有成百上千臺服務器來支撐訪問,假設只有一個服務器,那它的性能和存儲量要多大才能支撐這樣大量的訪問呢?DNS可以返回一個合適的機器的IP給用戶,例如可以根據每臺機器的負載量,該機器離用戶地理位置的距離等等,這種過程就是DNS負載均衡
發起TCP連接
TCP提供一種可靠的傳輸,這個過程涉及到三次握手,四次揮手,下面我們詳細看看 TCP提供一種面向連接的,可靠的字節流服務。 其首部的數據格式如下
字段分析
TCP報頭中的源端口號和目的端口號同IP數據報中的源IP與目的IP唯一確定一條TCP連接。
需要注意的是: (A)不要將確認序號Ack與標志位中的ACK搞混了。 (B)確認方Ack=發起方Req+1,兩端配對。
第一次握手:
客戶端發送syn包(Seq=x)到服務器,并進入SYN_SEND狀態,等待服務器確認;
第二次握手:
服務器收到syn包,必須確認客戶的SYN(ack=x+1),同時自己也發送一個SYN包(Seq=y),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
第三次握手:
客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=y+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
握手過程中傳送的包里不包含數據,三次握手完畢后,客戶端與服務器才正式開始傳送數據。理想狀態下,TCP連接一旦建立,在通信雙方中的任何一方主動關閉連接之前,TCP 連接都將被一直保持下去。
為什么會采用三次握手,若采用二次握手可以嗎? 四次呢?
建立連接的過程是利用客戶服務器模式,假設主機A為客戶端,主機B為服務器端。
采用三次握手是為了防止失效的連接請求報文段突然又傳送到主機B,因而產生錯誤。失效的連接請求報文段是指:主機A發出的連接請求沒有收到主機B的確認,于是經過一段時間后,主機A又重新向主機B發送連接請求,且建立成功,順序完成數據傳輸。考慮這樣一種特殊情況,主機A第一次發送的連接請求并沒有丟失,而是因為網絡節點導致延遲達到主機B,主機B以為是主機A又發起的新連接,于是主機B同意連接,并向主機A發回確認,但是此時主機A根本不會理會,主機B就一直在等待主機A發送數據,導致主機B的資源浪費。
采用兩次握手不行,原因就是上面說的失效的連接請求的特殊情況。而在三次握手中, client和server都有一個發syn和收ack的過程, 雙方都是發后能收, 表明通信則準備工作OK.
為什么不是四次握手呢? 大家應該知道通信中著名的藍軍紅軍約定, 這個例子說明, 通信不可能100%可靠, 而上面的三次握手已經做好了通信的準備工作, 再增加握手, 并不能顯著提高可靠性, 而且也沒有必要。
數據傳輸完畢后,雙方都可釋放連接。最開始的時候,客戶端和服務器都是處于ESTABLISHED狀態,假設客戶端主動關閉,服務器被動關閉。
第一次揮手:
客戶端發送一個FIN,用來關閉客戶端到服務器的數據傳送,也就是客戶端告訴服務器:我已經不會再給你發數據了(當然,在fin包之前發送出去的數據,如果沒有收到對應的ack確認報文,客戶端依然會重發這些數據),但是,此時客戶端還可以接受數據。 FIN=1,其序列號為seq=u(等于前面已經傳送過來的數據的最后一個字節的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態。 TCP規定,FIN報文段即使不攜帶數據,也要消耗一個序號。
第二次揮手:
服務器收到FIN包后,發送一個ACK給對方并且帶上自己的序列號seq,確認序號為收到序號+1(與SYN相同,一個FIN占用一個序號)。此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態。TCP服務器通知高層的應用進程,客戶端向服務器的方向就釋放了,這時候處于半關閉狀態,即客戶端已經沒有數據要發送了,但是服務器若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。
此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送連接釋放報文(在這之前還需要接受服務器發送的最后的數據)。
第三次揮手:
服務器發送一個FIN,用來關閉服務器到客戶端的數據傳送,也就是告訴客戶端,我的數據也發送完了,不會再給你發數據了。由于在半關閉狀態,服務器很可能又發送了一些數據,假定此時的序列號為seq=w,此時,服務器就進入了LAST-ACK(最后確認)狀態,等待客戶端的確認。
第四次揮手:
主動關閉方收到FIN后,發送一個ACK給被動關閉方,確認序號為收到序號+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態。注意此時TCP連接還沒有釋放,必須經過2?MSL(最長報文段壽命)的時間后,當客戶端撤銷相應的TCB后,才進入CLOSED狀態。
服務器只要收到了客戶端發出的確認,立即進入CLOSED狀態。同樣,撤銷TCB后,就結束了這次的TCP連接。可以看到,服務器結束TCP連接的時間要比客戶端早一些。
至此,完成四次揮手。
為什么客戶端最后還要等待2MSL?
MSL(Maximum Segment Lifetime),TCP允許不同的實現可以設置不同的MSL值。
第一,保證客戶端發送的最后一個ACK報文能夠到達服務器,因為這個ACK報文可能丟失,站在服務器的角度看來,我已經發送了FIN+ACK報文請求斷開了,客戶端還沒有給我回應,應該是我發送的請求斷開報文它沒有收到,于是服務器又會重新發送一次,而客戶端就能在這個2MSL時間段內收到這個重傳的報文,接著給出回應報文,并且會重啟2MSL計時器。
第二,防止類似與“三次握手”中提到了的“已經失效的連接請求報文段”出現在本連接中。客戶端發送完最后一個確認報文后,在這個2MSL時間中,就可以使本連接持續的時間內所產生的所有報文段都從網絡中消失。這樣新的連接中不會出現舊連接的請求報文。
為什么建立連接是三次握手,關閉連接確是四次揮手呢?
建立連接的時候, 服務器在LISTEN狀態下,收到建立連接請求的SYN報文后,把ACK和SYN放在一個報文里發送給客戶端。 而關閉連接時,服務器收到對方的FIN報文時,僅僅表示對方不再發送數據了但是還能接收數據,而自己也未必全部數據都發送給對方了,所以己方可以立即關閉,也可以發送一些數據給對方后,再發送FIN報文給對方來表示同意現在關閉連接,因此,己方ACK和FIN一般都會分開發送,從而導致多了一次。
發送HTTP請求
首先科補一個小知識,HTTP的端口為80/8080,而HTTPS的端口為443
發送HTTP請求的過程就是構建HTTP請求報文并通過TCP協議中發送到服務器指定端口 請求報文由請求行,請求報頭,請求正文組成。
請求行
請求行的格式為Method Request-URL HTTP-Version CRLF eg: GET index.html HTTP/1.1 常用的方法有: GET,POST, PUT, DELETE, OPTIONS, HEAD。
常見的請求方法區別
這里主要展示POST和GET的區別
常見的區別
注意一點你也可以在GET里面藏body,POST里面帶參數
重點區別
GET會產生一個TCP數據包,而POST會產生兩個TCP數據包。
詳細的說就是:
注意一點,并不是所有的瀏覽器都會發送兩次數據包,Firefox就發送一次
請求報頭
請求報頭允許客戶端向服務器傳遞請求的附加信息和客戶端自身的信息。
從圖中可以看出,請求報頭中使用了Accept, Accept-Encoding, Accept-Language, Cache-Control, Connection, Cookie等字段。Accept用于指定客戶端用于接受哪些類型的信息,Accept-Encoding與Accept類似,它用于指定接受的編碼方式。Connection設置為Keep-alive用于告訴客戶端本次HTTP請求結束之后并不需要關閉TCP連接,這樣可以使下次HTTP請求使用相同的TCP通道,節省TCP連接建立的時間。
請求正文
當使用POST, PUT等方法時,通常需要客戶端向服務器傳遞數據。這些數據就儲存在請求正文中。在請求包頭中有一些與請求正文相關的信息,例如: 現在的Web應用通常采用Rest架構,請求的數據格式一般為json。這時就需要設置Content-Type: application/json。
HTTP屬于客戶端緩存,我們常認為瀏覽器有一個緩存數據庫,用來保存一些靜態文件,下面我們分為以下幾個方面來簡單介紹HTTP緩存
緩存的規則
緩存規則分為強制緩存和協商緩存
強制緩存
當緩存數據庫中有客戶端需要的數據,客戶端直接將數據從其中拿出來使用(如果數據未失效),當緩存服務器沒有需要的數據時,客戶端才會向服務端請求。
協商緩存
又稱對比緩存。客戶端會先從緩存數據庫拿到一個緩存的標識,然后向服務端驗證標識是否失效,如果沒有失效服務端會返回304,這樣客戶端可以直接去緩存數據庫拿出數據,如果失效,服務端會返回新的數據
強制緩存的優先級高于協商緩存,若兩種緩存皆存在,且強制緩存命中目標,則協商緩存不再驗證標識。
緩存的方案
上面的內容讓我們大概了解了緩存機制是怎樣運行的,但是,服務器是如何判斷緩存是否失效呢?我們知道瀏覽器和服務器進行交互的時候會發送一些請求數據和響應數據,我們稱之為HTTP報文。報文中包含首部header和主體部分body。與緩存相關的規則信息就包含在header中。boby中的內容是HTTP請求真正要傳輸的部分。舉個HTTP報文header部分的例子如下:
我們依舊分為強制緩存和協商緩存來分析。
強制緩存
對于強制緩存,服務器響應的header中會用兩個字段來表明——Expires和Cache-Control。
Expires
Exprires的值為服務端返回的數據到期時間。當再次請求時的請求時間小于返回的此時間,則直接使用緩存數據。但由于服務端時間和客戶端時間可能有誤差,這也將導致緩存命中的誤差,另一方面,Expires是HTTP1.0的產物,故現在大多數使用Cache-Control替代。
Cache-Control
Cache-Control有很多屬性,不同的屬性代表的意義也不同。
協商緩存
協商緩存需要進行對比判斷是否可以使用緩存。瀏覽器第一次請求數據時,服務器會將緩存標識與數據一起響應給客戶端,客戶端將它們備份至緩存中。再次請求時,客戶端會將緩存中的標識發送給服務器,服務器根據此標識判斷。若未失效,返回304狀態碼,瀏覽器拿到此狀態碼就可以直接使用緩存數據了。
對于協商緩存來說,緩存標識我們需要著重理解一下,下面我們將著重介紹它的兩種緩存方案。
Last-Modified
Last-Modified:服務器在響應請求時,會告訴瀏覽器資源的最后修改時間。
這兩個的區別是一個是修改了才下載一個是沒修改才下載。
Last-Modified 說好卻也不是特別好,因為如果在服務器上,一個資源被修改了,但其實際內容根本沒發生改變,會因為Last-Modified時間匹配不上而返回了整個實體給客戶端(即使客戶端緩存里有個一模一樣的資源)。為了解決這個問題,HTTP1.1推出了Etag。
Etag
Etag:服務器響應請求時,通過此字段告訴瀏覽器當前資源在服務器生成的唯一標識(生成規則由服務器決定)
但是實際應用中由于Etag的計算是使用算法來得出的,而算法會占用服務端計算的資源,所有服務端的資源都是寶貴的,所以就很少使用Etag了。
緩存的優點
不同刷新的請求執行過程
瀏覽器地址欄中寫入URL,回車
F5
Ctrl+F5
它會對TCP連接進行處理,對HTTP協議進行解析,并按照報文格式進一步封裝成HTTP Request對象,供上層使用。這一部分工作一般是由Web服務器去進行,我使用過的Web服務器有Tomcat, Nginx和Apache等等 HTTP報文也分成三份,狀態碼 ,響應報頭和響應報文
狀態碼
狀態碼是由3位數組成,第一個數字定義了響應的類別,且有五種可能取值:
常見狀態碼區別
200 成功
請求成功,通常服務器提供了需要的資源。
204 無內容
服務器成功處理了請求,但沒有返回任何內容。
301 永久移動
請求的網頁已永久移動到新位置。 服務器返回此響應(對 GET 或 HEAD 請求的響應)時,會自動將請求者轉到新位置。
302 臨時移動
服務器目前從不同位置的網頁響應請求,但請求者應繼續使用原有位置來進行以后的請求。
304 未修改
自從上次請求后,請求的網頁未修改過。 服務器返回此響應時,不會返回網頁內容。
400 錯誤請求
服務器不理解請求的語法。
401 未授權
請求要求身份驗證。 對于需要登錄的網頁,服務器可能返回此響應。
403 禁止
服務器拒絕請求。
404 未找到
服務器找不到請求的網頁。
422 無法處理
請求格式正確,但是由于含有語義錯誤,無法響應
500 服務器內部錯誤
服務器遇到錯誤,無法完成請求。
響應報頭
常見的響應報頭字段有: Server, Connection...。
響應報文
你從服務器請求的HTML,CSS,JS文件就放在這里面
性能優化之回流重繪
回流
當Render Tree中部分或全部元素的尺寸、結構、或某些屬性發生改變時,瀏覽器重新渲染部分或全部文檔的過程稱為回流。
會導致回流的操作:
一些常用且會導致回流的屬性和方法:
重繪
當頁面中元素樣式的改變并不影響它在文檔流中的位置時(例如:color、background-color、visibility等),瀏覽器會將新樣式賦予給元素并重新繪制它,這個過程稱為重繪。
CSS
JavaScript
<style>
a {
text-decoration: none;
color: #8c7ae6;
font-size: 24px;
box-shadow: inset 0 0 0 #8c7ae6;
transition: all 300ms ease-in-out;
}
a:hover {
box-shadow: inset 180px 0 0 0 #8c7ae6;
color: white;
}
</style>
<a href="#">Hover this link</a>
<style>
a {
overflow: hidden;
position: relative;
display: inline-block;
}
a::before,
a::after {
content: "";
position: absolute;
width: 100%;
left: 0;
}
a::before {
background-color: #54b3d6;
height: 2px;
bottom: 0;
transform-origin: 100% 50%;
transform: scaleX(0);
transition: transform 0.3s ease-in-out;
}
a::after {
content: attr(data-replace);
height: 100%;
top: 0;
transform-origin: 100% 50%;
transform: translate3d(200%, 0, 0);
transition: transform 0.3s ease-in-out;
color: #54b3d6;
}
a:hover::before {
transform-origin: 0% 50%;
transform: scaleX(1);
}
a:hover::after {
transform: translate3d(0, 0, 0);
}
a span {
display: inline-block;
transition: transform 0.3s ease-in-out;
}
a:hover span {
transform: translate3d(-200%, 0, 0);
}
body {
display: grid;
font-size: 27px;
height: 100vh;
place-items: center;
}
a {
text-decoration: none;
color: #18272f;
font-weight: 700;
vertical-align: top;
}
</style>
<p>Hover <a href="#" id="style-2" data-replace="this link">
<span>this link</span>
</a></p>
<style>
a {
text-decoration: none;
color: #18272f;
font-weight: 700;
position: relative;
}
a::before {
content: "";
background-color: #00a8ff;
position: absolute;
left: 0;
bottom: 3px;
width: 100%;
height: 8px;
z-index: -1;
transition: all 300ms ease-in-out;
}
a:hover::before {
bottom: 0;
height: 100%;
}
body {
display: grid;
font-size: 27px;
line-height: 1.5;
height: 100vh;
place-items: center;
}
</style>
<p>Hover this <a href="#">cool</a> link.</p>
<style>
a {
background-image: linear-gradient(to right, #54b3d6, #54b3d6 50%, #000 50%);
background-size: 200% 100%;
background-position: -100%;
display: inline-block;
padding: 5px 0;
position: relative;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
transition: all 300ms ease-in-out;
}
a:before {
content: "";
background: #54b3d6;
display: block;
position: absolute;
bottom: -3px;
left: 0;
width: 0;
height: 3px;
transition: all 300ms ease-in-out;
}
a:hover {
background-position: 0;
}
a:hover::before {
width: 100%;
}
body {
display: grid;
font-size: 27px;
height: 100vh;
place-items: center;
}
</style>
<a href="">Hover This Link</a>
<style>
a {
color: black;
text-decoration: none;
background: linear-gradient(to right, #64c8c8, #64c8c8),
linear-gradient(to right, #ff0000, #ff00b4, #0064c8);
background-size: 100% 3px, 0 3px;
background-position: 100% 100%, 0 100%;
background-repeat: no-repeat;
transition: background-size 400ms;
}
a:hover {
background-size: 0 3px, 100% 3px;
}
body {
display: grid;
font-size: 27px;
font-weight: 700;
height: 100vh;
place-items: center;
}
</style>
<a href="">Hover This Link</a>
原文地址:https://css-tricks.com/css-link-hover-effects/
*請認真填寫需求信息,我們會在24小時內與您取得聯系。