年榮譽之路活動已經開啟了,和去年一樣,沒達到2級榮譽并沒有被鎖的玩家可以通過完成任務來恢復至2級榮譽,2級至4級的玩家可以提升一級榮譽,5級榮譽則可以領取魔法引擎。而恢復至2級榮譽并在單雙或靈活排位達到黃金及以上玩家能獲得勝利女神瑟莊妮,達到5級榮譽可以獲得三大榮譽瑪爾扎哈。
活動時間:2022年11月25日-2023年1月8日
活動鏈接:
?https://lol.qq.com/act/a20221125roadtohonor/index.html?e_code=508038&exchangeType=1
目前有三種情況:
①恢復2級榮譽,適用0級和1級的,這個恢復也是用來給剛剛結束的S12賽季單雙或靈活排位達到黃金及以上段位的玩家領勝利女神瑟莊妮的。
②提升1檔榮譽,給2-4級的玩家用的,能提升一檔榮譽,因為每一級榮譽有三個里程碑點,我建議盡可能把等級升高點和剛升榮譽等級的時候用,比如剛升4級,再到這里申請就可以直達5級。可以用來領三大榮譽瑪爾扎哈的皮膚。
③榮譽5級獎勵。5級榮譽玩家可以領一個魔法引擎,這個引擎也沒啥好東西,就是一些鑰匙和守衛皮膚碎片等。
要注意的是,這三個只能選擇一個參與。
你選擇從3級升到4級,以后哪怕再達到5級也不能選擇領取魔法引擎。或者你恢復到了2級,也不能再選擇提升一檔榮譽了。
所以這個活動可以晚點參與。
游戲任務:
?都是登錄7天游戲并每天完成一場對局,由于時間比較長肯定做的完。
恢復2級榮譽需要手打“我承諾...”也就是“認罪書”。對皮膚無所謂的也不用參加這玩意。
關于獎勵
?之前的賽季結算公告有提過會在11.17以后發放獎勵,并在12月完成所有賬號發放。現在基本都還沒領到,慢慢等就行。
?當然瑪爾扎哈的皮膚只要在1月8日23:59之前達到5級榮譽都能獲得。
最后覺得有用可以點個關注、分享啥的,有關英雄聯盟、云頂之弈的皮膚、資訊、活動、白嫖福利都會發。
章來源:https://www.cnblogs.com/jackson0714/p/TSQLFundamentals_08.html
作者:公眾號:悟空聊架構
本篇主要是對SQL中事務和并發的詳細講解。
回到頂部
為單個工作單元而執行的一系列操作。如查詢、修改數據、修改數據定義。
(1)顯示定義事務的開始、提交
1 2 3 4 | BEGIN TRAN INSERT INTO b(t1) VALUES(1) INSERT INTO b(t1) VALUES(2) COMMIT TRAN |
(2)隱式定義
如果不顯示定義事務的邊界,則SQL Server會默認把每個單獨的語句作為一個事務,即在執行完每個語句之后就會自動提交事務。
(1)原子性Atomicity
1.事務必須是原子工作單元。事務中進行的修改,要么全部執行,要么全都不執行;
2.在事務完成之前(提交指令被記錄到事務日志之前),系統出現故障或重新啟動,SQL Server將會撤銷在事務中進行的所有修改;
3.事務在處理中遇到錯誤,SQL Server通常會自動回滾事務;
4.少數不太嚴重的錯誤不會引發事務的自動回滾,如主鍵沖突、鎖超時等;
5.可以使用錯誤處理來捕獲第4點提到的錯誤,并采取某種操作,如把錯誤記錄在日志中,再回滾事務;
6.SELECT @@TRANCOUNT可用在代碼的任何位置來判斷當前使用SELECT @@TRANCOUNT的地方是否位于一個打開的事務當中,如果不在任何打開的事務范圍內,則該函數返回0;如果在某個打開的事務返回范圍內,則返回一個大于0的值。打開一個事務,@@TRANCOUNT=@@TRANCOUNT+1;提交一個事務,@@TRANCOUNT-1。
(2)一致性Consiitency
1.同時發生的事務在修改和查詢數據時不發生沖突;
2.一致性取決于應用程序的需要。后面會講到一致性級別,以及如何對一致性進行控制。
(3)隔離性Isolation
1.用于控制數據訪問,確保事務只訪問處于期望的一致性級別下的數據;
2.使用鎖對各個事務之間正在修改和查詢的數據進行隔離。
(4)持久性Durability
1.在將數據修改寫入到磁盤上數據庫的數據分區之前會把這些修改寫入到磁盤上數據庫的事務日志中,把提交指令記錄到磁盤的事務日志中以后,及時數據修改還沒有應用到磁盤的數據分區,也可以認為事務時持久化的。
2.系統重新啟動(正常啟動或在發生系統故障之后啟動),SQL Server會每個數據庫的事務日志,進行回復處理。
3.恢復處理包含兩個階段:重做階段和撤銷階段。
4.前滾:在重做階段,對于提交指令已經寫入到日志的事務,但數據修改還沒有應用到數據分區的事務,數據庫引擎會重做這些食物所做的所有修改。
5.回滾:在撤銷階段,對于提交指令沒有寫入到日志中的事務,數據庫引擎會撤銷這些事務所做的修改。(這句話需要research,可能是不正確的。因為提交指令沒有寫入到數據分區,撤銷修改是指撤銷哪些修改呢???)
回到頂部
(1)SQL Server使用鎖來實現事務的隔離。
(2)事務獲取鎖這種控制資源,用于保護數據資源,防止其他事務對數據進行沖突的或不兼容的訪問。
(1)排他鎖
a.當試圖修改數據時,事務只能為所依賴的數據資源請求排他鎖。
b.持有排他鎖時間:一旦某個事務得到了排他鎖,則這個事務將一直持有排他鎖直到事務完成。
c.排他鎖和其他任何類型的鎖在多事務中不能在同一階段作用于同一個資源。
如:當前事務獲得了某個資源的排他鎖,則其他事務不能獲得該資源的任何其他類型的鎖。其他事務獲得了某個資源的任何其他類型的鎖,則當前事務不能獲得該資源的排他鎖。
(2)共享鎖
a.當試圖讀取數據時,事務默認會為所依賴的數據資源請求共享鎖。
b.持有共享鎖時間:從事務得到共享鎖到讀操作完成。
c.多個事務可以在同一階段用共享鎖作用于同一數據資源。
d.在讀取數據時,可以對如何處理鎖定進行控制。后面隔離級別會講到如何對鎖定進行控制。
(1)如果數據正在由一個事務進行修改,則其他事務既不能修改該數據,也不能讀取(至少默認不能)該數據,直到第一個事務完成。
(2)如果數據正在由一個事務讀取,則其他事務不能修改該數據(至少默認不能)。
RID、KEY(行)、PAGE(頁)、對象(例如表)、數據庫、EXTENT(區)、分配單元(ALLOCATION_UNIT)、堆(HEAP)、以及B樹(B-tree)。
RID: 標識頁上的特定行
格式: fileid: pagenumber: rid (1:109:0 )
其中fileid標識包含頁的文件, pagenumber標識包含行的頁,rid標識頁上的特定行。
fileid與sys.databases_files 目錄視圖中的file_id列相匹配
例子:
在查詢視圖sys.dm_tran_locks的時候有一行的resource_description列顯示RID 是1:109:0 而status列顯示wait,
表示第1個數據文件上的第109頁上的第0行上的鎖資源。
SQL Server可以先獲得細粒度的鎖(例如行或頁),在某些情況下將細粒度鎖升級為更粗粒度的鎖(例如,表)。
例如單個語句獲得至少5000個鎖,就會觸發鎖升級,如果由于鎖沖突而導致無法升級鎖,則SQL Server每當獲取1250個新鎖時出發鎖升級。
回到頂部
當多個事務都需要對某一資源進行鎖定時,默認情況下會發生阻塞。被阻塞的請求會一直等待,直到原來的事務釋放相關的鎖。鎖定超時期限可以限制,這樣就可以限制被阻塞的請求在超時之前要等待的時間。
階段1:事務A請求資源S1,事務不對資源S1進行操作
階段2:事務A用鎖A鎖定資源S1,事務B請求對資源S1進行不兼容的鎖定(鎖B),鎖B的請求被阻塞,事務B將進入等待狀態
階段3:事務A正在釋放鎖A,事務B等待鎖A釋放,
階段4:事務A的鎖A已釋放,事務B用鎖B鎖定資源S1
例子:
(1)準備工作:
1.準備測試數據
1 2 3 4 5 6 7 8 | --先創建一張表Product作為測試。id為表的主鍵,price為product的價格 CREATE TABLE [dbo].[myProduct]( [id] [int] NOT NULL, [price] [money] NOT NULL ) ON [PRIMARY] GO --插入一條數據,id=1,price=10 INSERT INTO [TSQLFundamentals2008].[dbo].[myProduct]([id],[price])VALUES(1,10) |
2.模擬阻塞發生的情況
在SQL Server中打開三個查詢窗口Connection1、Connection2、Connection3,分別按順序執行表格中的執行語句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | --Connection1 BEGIN TRAN UPDATE dbo.myProduct SET price=price + 1 WHERE id=1 --Connection2 SELECT * FROM dbo.myProduct WHERE id=1 --Connection3 SELECT request_session_id AS 會話id , resource_type AS 請求鎖定的資源類型 , resource_description AS 描述 , request_mode AS 模式 , request_status AS 狀態 FROM sys.dm_tran_locks |
查詢窗口 | 服務器進程標識符SPID | 執行語句 | 結果 | 說明 | ||
Connection1 | 52 |
| 為了更新id=1這一行數據,會話必須先獲得一個排他鎖。事務處于一直打開狀態,沒有提交,所以事務一直持有排他鎖,直到事務提交并完成。 | |||
Connection2 | 56 |
| 事務為了讀取數據,需要請求一個共享鎖,但是這一行已經被其他會話持有的排他鎖鎖定,而且共享鎖和排他鎖不是兼容的,所以會話被阻塞,進入等待狀態 | |||
Connection3 | 57 |
| 會話56: |
(2)分析阻塞
★ 1.sys.dm_tran_locks 視圖
(1)該動態視圖可以查詢出哪些資源被哪個進程ID鎖了
(2)查詢出對資源授予或正在等待的鎖模式
(3)查詢出被鎖定資源的類型
上面的查詢語句3已經用到了這個視圖,可以參考上圖中的分析說明。
★ 2.sys.dm_exec_connections 視圖
(1)查詢出該動態視圖可以查詢出進程相關的信息
(2)查詢出最后一次發生讀操作和寫操作的時間last_read,last_write
(3)查詢出進程執行的最后一個SQL批處理的二進制標記most_recent_sql_handle
查詢窗口 | 服務器進程標識符SPID | 執行語句 | 結果 | 說明 | ||
Connection3 | 57 |
| 會話52: |
★ 3.sys.dm_exec_sql_text 表函數
(1)該函數可以將二進制標記most_recent_sql_handle作為參數,然后返回SQL代碼。
(2)阻塞進程在不斷地運行,所以在代碼中看到的最后一個操作不一定是導致問題的語句。在本例中最后一條執行語句是導致阻塞的語句。
查詢窗口 | 服務器進程標識符SPID | 執行語句 | 結果 | 說明 | ||||||
Connection3 | 57 |
| 會話52:
|
★ 4.sys.dm_exec_sessions 視圖
(1)會話建立的時間login_time
(2)特定于會話的客戶端工作站名稱host_name
(3)初始化會話的客戶端程序的名稱program_name
(4)會話所使用的SQL Server登錄名login_name
(5)最近一次會話請求的開始時間last_request_start_time
(6)最近一次會話請求的完成時間last_request_end_time
查詢窗口 | 服務器進程標識符SPID | 執行語句 | 結果 | 說明 | ||
Connection3 | 57 |
|
★ 5.sys.dm_exec_requests 視圖
(1)識別出阻塞鏈涉及到的會話、爭用的資源、被阻塞會話等待了多長時間
查詢窗口 | 服務器進程標識符SPID | 執行語句 | 結果 | 說明 | ||
Connection3 | 57 |
| 會話56: |
★ 6.Lock_TIMEOUT 選項
(1)設置會話等待鎖釋放的超時期限
(2)默認情況下會話不會設置等待鎖釋放的超時期限
(3)設置會話超時期限為5秒, SET Lock_TIMEOUT 5000
(4)鎖定如果超時,不會引發事務回滾
(5)取消會話超時鎖定的設置,SET LOCK_TIMEOUT -1
如果超時,將顯示以下錯誤:
★7.KILL <spid> 命令
(1)殺掉會話52,KILL 52
(2)殺掉會話,會引起事務回滾,同時釋放排他鎖
回到頂部
(1)隔離級別用來做什么
a.隔離級別用于決定如何控制并發用戶讀寫數據的操作
(2)寫操作
a.任何對表做出修改的語句
b.使用排他鎖
c.不能修改讀操作獲得的鎖和鎖的持續時間
(3)讀操作:
a.任何檢索數據的語句
b.默認使用共享鎖
c.使用隔離級別來控制讀操作的處理方式
(1)未提交讀 (READ UNCOMMITTED)
(2)已提交讀(READ COMMITTED)(默認值)
(3)可重復讀(REPEATABLE READ)
(4)可序列化(SERIALIZABLE)
(5)快照(SNAPSHOT)
(6)已經提交讀快照(READ_COMMITTED_SNAPSHOT)
(1)設置整個會話的隔離級別
1 | SET TRANSACTION ISOLATION LEVEL <isolation name>; |
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
(2)用表提示設置查詢的隔離級別
1 2 | SELECT ... FROM <table> WITH (<isolation name>);<br> SELECT * FROM dbo.myProduct WITH (READCOMMITTED); |
注意:
1.設置會話選項的隔離級別時,隔離級別中的每個單詞之間需要用空格分隔
2.用表提示的隔離級別時,隔離級別中的每個單詞之間不需要用空格分隔
3.表提示的隔離級別有同義詞,如:NOLOCK->READUNCOMMITTED,HOLDLOCK->REPEATABLEREAD
4.隔離級別的嚴格性:1.未提交讀<2.已提交讀<3.可重復讀<4.可序列化
5.隔離級別越高,一致性越高,并發性越低
6.基于快照的隔離級別,SQL Server將提交過的行保存到tempdb數據庫中,當讀操作發現行的當前版本和它們預期的不一致時,可以立即得到行的以前版本,從而不用請求共享鎖也能取得預期的一致性。
★ 1.未提交讀 (READ UNCOMMITTED)
打開兩個查詢窗口,Connetion1,connection2
Step1: 執行Connection1的階段2的SQL 語句,然后執行connection2的SQL語句
Step2: 執行Connection1的階段3的SQL 語句,執行connection2的SQL語句
Step3: 執行Connection1的階段4的SQL 語句,執行connection2的SQL語句
查詢窗口 | 事務 | 執行語句 | ||
Connetion1 | A |
| ||
Connection2 | B |
|
兩個事務的流程圖:
階段1:Price=10,事務A對myProduct表請求排他鎖
階段2:事務A對myProduct表使用了排他鎖,更新price=price + 1,然后事務A查詢price的價格: price=11。事務B不請求任何鎖,事務B在A更新Price之后進行查詢,price=11
階段3:事務A更新price=price + 5,然后事務A查詢price的價格,price=16。事務B查詢price的價格: price=16
階段4:事務A釋放排他鎖
階段5:事務A中查詢price的價格:price=16。事務B查詢price的價格: price=16
大家可以看到事務B有兩種結果,這就是“未提交讀 (READ UNCOMMITTED)”隔離級別的含義:
(1)讀操作可以讀取未提交的修改(也稱為臟讀)。
(2)讀操作不會妨礙寫操作請求排他鎖,其他事務正在進行讀操作時,寫操作可以同時對這些數據進行修改。
(3)事務A進行了多次修改,事務B在不同階段進行查詢時可能會有不同的結果。
★ 2.已提交讀(READ COMMITTED)(默認值)
打開兩個查詢窗口,Connetion1,connection2
Step1: 執行Connection1的SQL 語句
Step2: 執行Connection2的SQL 語句
執行語句 | 執行語句 | |||
Connetion1 | A |
| ||
Connection2 | B |
|
兩個事務的流程圖:
階段1:Price=10,事務A對myProduct表請求排他鎖
階段2:事務A對myProduct表使用了排他鎖,更新price=price + 1,然后事務A查詢price的價格: price=11。然后事務B請求共享鎖進行讀操作,查詢price,
由于在當前隔離級別下,事務A的排他鎖和事務B的共享鎖存在沖突,所以事務B需要等待事務A釋放排他鎖后才能讀取數據。
階段3:事務A提交事務(COMMIT TRAN)
階段4:事務A提交完事務后,釋放排他鎖
階段5:事務B獲得了共享鎖,進行讀操作,price=11
“已提交讀 (READ UNCOMMITTED)”隔離級別的含義:
(1)必須獲得共享鎖才能進行讀操作,其他事務如果對該資源持有排他鎖,則共享鎖必須等待排他鎖釋放。
(2)讀操作不能讀取未提交的修改,讀操作讀取到的數據是提交過的修改。
(3)讀操作不會在事務持續期間內保留共享鎖,其他事務可以在兩個讀操作之間更改數據資源,讀操作因而可能每次得到不同的取值。這種現象稱為“不可重復讀”
★ 3.可重復讀(REPEATABLE READ)
打開兩個查詢窗口,Connetion1,connection2
Step1: 執行Connection1的SQL 語句
Step2: 執行Connection2的SQL 語句
執行語句 | 事務 | 執行語句 | ||
Connetion1 | A |
| ||
Connection2 | B |
|
兩個事務的流程圖:
階段1:Price=10,事務A對myProduct表請求共享鎖
階段2:事務A對myProduct表使用了共享鎖,事務A查詢price的價格: price=10,事務A一直持有共享鎖直到事務A完成為止。然后事務B請求排他鎖進行寫操作price=price+1,
由于在當前隔離級別下,事務A的共享鎖和事務B請求的排他鎖存在沖突,所以事務B需要等待事務A釋放共享鎖后才能修改數據。
階段3:事務A查詢price, price=10, 說明事務B的更新操作被阻塞了,更新操作沒有被執行。然后事務A提交事務(COMMIT TRAN)
階段4:事務A提交完事務后,釋放共享鎖
階段5:事務B獲得了排他鎖,進行寫操作,price=11
“可重復讀 (REPEATABLE READ)”隔離級別的含義:
(1)必須獲得共享鎖才能進行讀操作,獲得的共享鎖將一直保持直到事務完成之止。
(2)在獲得共享鎖的事務完成之前,沒有其他事務能夠獲得排他鎖修改這一數據資源,這樣可以保證實現可重復的讀取。
(3)兩個事務在第一次讀操作之后都將保留它們獲得的共享鎖,所以任何一個事務都不能獲得為了更新數據而需要的排他鎖,這種情況將會導致死鎖(deadlock),不過卻避免了更新沖突。
★ 4.可序列化(SERIALIZABLE)
打開兩個查詢窗口,Connetion1,connection2
Step1: 執行Connection1的SQL 語句
Step2: 執行Connection2的SQL 語句
執行語句 | 事務 |
| ||
Connetion1 | A |
| ||
Connection2 | B |
|
兩個事務的流程圖:
階段1:Price=10,事務A對myProduct表請求共享鎖
階段2:事務A對myProduct表使用了共享鎖,事務A查詢id=1的price的價格:1行記錄,price=10,事務A一直持有共享鎖直到事務A完成為止。然后事務B請求排他鎖進行插入操作id=1,price=20,
由于在當前隔離級別下,事務B試圖增加能夠滿足事務A的讀操作的查詢搜索條件的新行,所以事務A的共享鎖和事務B請求的排他鎖存在沖突,事務B需要等待事務A釋放共享鎖后才能插入數據。
階段3:事務A查詢出id=1的數據只有1行,說明事務B的插入操作被阻塞了,插入操作沒有被執行。然后事務A提交事務(COMMIT TRAN)
階段4:事務A提交完事務后,釋放共享鎖
階段5:事務B獲得了排他鎖,進行插入操作,插入成功,查詢出id=1的數據有兩條
“可序列化(SERIALIZABLE)”隔離級別的含義:
(1)必須獲得共享鎖才能進行讀操作,獲得的共享鎖將一直保持直到事務完成之止。
(2)在獲得共享鎖的事務完成之前,沒有其他事務能夠獲得排他鎖修改這一數據資源,且當其他事務增加能夠滿足當前事務的讀操作的查詢搜索條件的新行時,其他事務將會被阻塞,直到當前事務完成然后釋放共享鎖,其他事務才能獲得排他鎖進行插入操作。
(3)事務中的讀操作在任何情況下讀取到的數據是一致的,不會出現幻影行(幻讀)。
(4)范圍鎖:讀操作鎖定滿足查詢搜索條件范圍的鎖
臟讀:讀取未提交的更改。
不可重復讀:讀操作不會在事務持續期間內保留共享鎖,其他事務可以在兩個讀操作之間更改數據資源,讀操作因而可能每次得到不同的取值。
丟失更新:兩個事務進行讀操作,獲得資源上的共享鎖,讀取完數據后,不再持有資源上的任何鎖,兩個事務都能更新這個值,
最后進行更新的事務將會覆蓋其他事務做的更改,導致其他事務更改的數據丟失。
幻讀:第一次和第二次讀取到的數據行數不一致。
范圍鎖:讀操作鎖定滿足查詢搜索條件范圍的鎖
隔離級別 | 是否讀取未提交的行 | 是否不可重復讀 | 是否丟失更新 | 是否幻讀 | 共享鎖持續時間 | 是否持有范圍鎖 |
未提交讀 READ UNCOMMITTED | Y | Y | Y | Y | 當前語句 | N |
已提交讀 READ COMMITTED | N | Y | Y | Y | 當前語句 | N |
可重復讀REPEATABLE READ | N | N | N | Y | 事務開始到事務完成 | N |
可序列化SERIALZABLE | N | N | N | N | 事務開始到事務完成 | Y |
死鎖是指一種進程之間互相永久阻塞的狀態,可能涉及兩個或更多的進程。
打開兩個查詢窗口,Connetion1,connection2
Step1: 執行Connection1的SQL 語句
Step2: 執行Connection2的SQL 語句
執行語句 | 事務 | 執行語句 | ||
Connetion1 | A |
| ||
Connection2 | B |
|
兩個事務的流程圖:
階段1:Price=10,事務A對myProduct表請求排他鎖。Customer=aaa,事務B對myOrder請求排他鎖
階段2:事務A對myProduct表使用了排他鎖,更新price=price + 1。然后事務B對myOrder表使用了排他鎖,更新customer=ddd。
階段3:事務A查詢myOrder表,對myOrder表請求共享鎖,因為事務A的請求的共享鎖與事務B的排他鎖沖突,所以事務A被阻塞。然后事務B查詢myProduct表,對myProduct表請求共享鎖,因為事務B的請求的共享鎖與事務A的排他鎖沖突,所以事務B被阻塞。
階段4:事務A等待事務B的排他鎖釋放,事務B等待事務A的排他鎖釋放,導致死鎖。事務A和事務B都被阻塞了。
階段5:SQL Server在幾秒之內檢測到死鎖,會選擇一個事務作為死鎖的犧牲品,終止這個事務,并回滾這個事務所做的操作。在這個例子中,事務A被終止,提示信息:事務(進程 ID 53)與另一個進程被死鎖在 鎖 資源上,并且已被選作死鎖犧牲品。請重新運行該事務。
“死鎖 (Dead Lock)”的一些注意事項:
(1)如果兩個事務沒有設置死鎖優先級,且兩個事務進行的工作量也差不多一樣時,任何一個事務都有可能被終止。
(2)解除死鎖要付出一定的系統開銷,因為這個過程會涉及撤銷已經執行過的處理。
(3)事務處理的時間時間越長,持有鎖的時間就越長,死鎖的可能性也就越大,應該盡可能保持事務簡短,把邏輯上可以不屬于同一個工作單元的操作移到事務以外。
(4)上面的例子中,事務A和事務B以相反順序訪問資源,所以發生了死鎖。如果兩個事務按同樣的順序來訪問資源,則不會發生這種類型的死鎖。在不改變程序的邏輯情況下,可以通過交換順序來解決死鎖的問題。
/ 阿里淘系 F(x) Team - 大貘
前幾天在 F(x) Team.午夜識堂 和大家聊了一下 CSS 方面的話題,即 CSS 新特性。
在這個話題中主要整理了有關于 CSS 方面的特性,并且盡可能的整理了一些大家現在能用或過不了多久就能用的屬性。另外,雖然標題是“新特性”,但其中有蠻多特性并不是“新”,可能已經出現在你的項目中,或者你已經看過,只是不了解而以。接下來,就和大家一起來簡單地回顧一下這些性,希望大家能喜歡,也希望對大家平時工作有所幫助。
CSS 等比縮放一般指的是 “容器高度按比例根據寬度改變”,很多時候也稱為寬高比或縱寬比。 眾所周知,我們開發 Web 頁面要面對的終端更復雜的了,而這些終端的寬高比都不一樣。常見的比例有:?
特別是在做媒體相關開發的同學,比如視頻、圖像等,這方面的需求會更多,比如 Facebook 上的圖片,視頻展示:?
CSS 在還沒有 _aspect-ratio_ 之前,常使用一些 Hacck 手段來實現實類似的效果,即使用 padding-top 或 padding-bottom 來實現:?
<aspectratio-container>
<aspectratio-content></aspectratio-content>
</aspectratio-container>
<style>
.aspectratio-container {
width: 50vmin; /* 用戶根據自己需要設置相應的值 */
/* 布局方案可以調整 */
display: flex;
justify-content: center;
align-items: center;
}
/* 用來撐開aspectratio-container高度 */
.aspectratio-container::after {
content: "";
width: 1px;
padding-bottom: 56.25%;
/*元素的寬高比*/
margin: -1px;
z-index: -1;
}
</style>
?
有了 CSS 自定義屬性之后,可以結合 calc() 函數來實現容器等比縮放的效果:?
.container {
--ratio: 16/9;
height: calc(var(--width) * 1 / (var(--ratio)));
width: 100%;
}
?
雖然比padding-top 這樣的Hack 手段簡單,但相比原生的aspect-ratio還是要復雜的多。即:?
.container {
width: 100%;
aspect-ratio: 16 / 9;
}
下面這個示例演示了這三種不同方案實現寬比的效果:
Demo: https://codepen.io/airen/full/ExWjeZr
?
還可以通過 @media 讓元素在不同的終端上按不同的比例進行縮放:?
.transition-it {
aspect-ratio: 1/1;
transition: aspect-ratio .5s ease;
@media (orientation: landscape) { & {
aspect-ratio: 16/9;
}}
}
在 Web 布局中,時常會碰到內容溢出容器的現狀,如果 overflow 設置為 auto 或 scroll 時容器會出現水平或垂直滾動條:?
為了給用戶提供更好的滾動體驗,CSS 提供了一些優化滾動體驗的 CSS 特性,其中滾動捕捉就是其中之一。CSS 的滾動捕捉有點類似于 Flexbox 和 Grid 布局的特性,分類可用于滾動容器的屬性和滾動項目的屬性:?
有了滾動捕捉特性,我們要實現類似下圖的效果就可以不需要依賴任何 JavaScript 庫或腳本:?
就是每次滾動時,圖片的中心位置和容器中心位置對齊(想象一下 Swiper 的效果)。關鍵代碼就下面這幾行:?
.container {
scroll-behavior: smooth;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scroll-snap-type: x mandatory;
scroll-padding: 20px;
}
img {
scroll-snap-align: center;
scroll-snap-stop: always;
}
Demo: https://codepen.io/airen/full/mdRpboo
利用該特性,還可以實現類似 iOS的一些原生交互效果:
Demo: https://codepen.io/airen/full/PoWQPvN
要是再利用一點點JavaScript腳本,還可以實現沉浸式講故事的交互效果:?
Demo: https://codepen.io/airen/full/qBRxNOo
CSS 的 gap 屬性的出現,幫助我們解決了以前一直比較麻煩的布局效果:?
正如上圖所示,設計師期望的一個效果是,緊鄰容器邊緣沒有任何間距,但相鄰項目之間(水平或垂直方向)都有一定的間距。在沒有 gap 屬性之前使用 margin 是很煩人的,特別是多行多列的時候更麻煩。有了 gap 僅需要一行代碼即可。?
CSS 的 gap 屬性是一個簡寫屬性,分為 row-gap 和 column-gap :?
該屬性 gap 到目前為止只能運用于多列布局,Flexbox布局和網格布局的容器上:?
// 多列布局
.multi__column {
gap: 5ch
}
// Flexbox布局
.flexbox {
display: flex;
gap: 20px
}
// Grid布局
.grid {
display: grid;
gap: 10vh 20%
}
gap 屬性可以是一個值,也可以是兩個值:?
.gap {
gap: 10px;
}
// 等同于
.gap {
row-gap: 10px;
column-gap: 10px
}
.gap {
gap: 20px 30px;
}
// 等同于
.gap {
row-gap: 20px;
column-gap: 30px;
}
如果 gap 僅有一個值時,表示 row-gap 和 column-gap 相同。?
國內大多數 Web 開發者面對的場景相對來說比較單一,這里所說的場景指的是書寫模式或排版的閱讀模式。一般都是 LTR (Left To Right)。但有開發過國際業務的,比如阿拉伯國家的業務,就會碰到 RTL (Right To Left) 的場景。比如你打開 Facebook ,查看中文和阿拉伯文兩種語言下的 UI 效果:?
在沒見有邏輯屬性之前,一般都會在 <html> 或 <body> 上設置 dir 屬性,中文是 ltr ,阿拉伯語是 rtl ,然后針對不同的場景運用不同的 CSS 樣式:?
其實,閱讀方式除了水平方向(ltr 或 trl)之外,還會有垂直方向的閱讀方式:?
?
為了讓 Web 開發者能更好的針對不同的閱讀模式提供不同的排版效果,在CSS新增邏輯屬性。有了邏輯屬性之后,以前很多概念都有所變化了。比如我們以前熟悉的坐標軸,x 軸和 y 軸就變成了 inline 軸 和 block 軸,而且這兩個軸也會隨著書寫模式做出調整:?
除此之外,我們熟悉的 CSS 盒模型也分物理盒模型和邏輯盒模型:?
你可能感知到了,只要是以前帶有 top、right 、bottom 和 left 方向的物理屬性都有了相應的 inline-start 、 inline-end 、block-start 和 block-end 的邏輯屬性:?
我根據 W3C 規范,把物理屬性和邏輯屬性映射關系整了一份更詳細的表:?
?
回到實際生產中來:?
如果不使用邏輯屬性的話,要實現類似上圖這樣的效果,我們需要這樣來編寫 CSS:?
.avatar {
margin-right: 1rem;
}
html[dir="rtl"] .avatar {
margin-right: 0;
margin-left: 1rem;
}
有了 CSS 邏輯屬性之后,僅一行 CSS 代碼即可實現:?
.avatar {
margin-inline-end: 1rem;
}
簡單多了吧,特別是有國際化需求的開發者,簡直就是一種福音。
CSS 媒體查詢 @media 又稱為 CSS 條件查詢。在 Level 5 版本中提供了一些新的媒體查詢特性,可以查詢到用戶在設備上的喜好設置:
比如:?
?
使用的方式和以往我們熟悉的 @media 是相似。比如 prefers-color-scheme 實現暗黑查式的皮膚切換效果:?
// 代碼源于: https://codepen.io/airen/full/ProgLL
// dark & light mode
:root {
/* Light theme */
--c-text: #333;
--c-background: #fff;
}
body {
color: var(--c-text);
background-color: var(--c-background);
}
@media (prefers-color-scheme: dark) {
:root {
/* Dark theme */
--c-text: #fff;
--c-background: #333;
}
}
?
還可以根據網格數據設置來控制資源的加載:?
@media (prefers-reduced-data: reduce) {
header {
background-image: url(/grunge.avif);
}
}
@media (prefers-reduced-data: no-preference) {
@font-face {
font-family: 'Radness';
src: url(megafile.woff2);
}
}
其他的使用方式和效果就不一一演示了。不過在未來,CSS 的 @media 在編寫方式上會變得更簡單:?
@media (width <=320px) {
body {
padding-block: var(--sm-space);
}
}
@custom-media --motionOK (prefers-reduced-motion: no-preference);
@media (--motionOK) {
.card {
transition: transform .2s ease;
}
}
.card {
@media (--motionOK) { & {
transition: transform .2s ease;
}}
}
@media (1024px >=width >=320px) {
body {
padding-block: 1rem;
}
}
?
特別聲明,該示例代碼來自于 @argyleink 的 PPT 。
?
自從折疊屏設備的出現,給 Web 開發者帶來新的挑戰:?
值得慶幸的是,微軟和三星的團隊就針對折疊屏幕設備提供了不同的 媒體查詢判斷。?
上圖是帶有物理分隔線的雙屏幕設備:
main {
display: grid;
gap: env(fold-width);
grid-template-columns: env(fold-left) 1fr;
}
@media (spanning: single-fold-vertical) {
aside {
flex: 1 1 env(fold-left);
}
}
無縫的折疊設備:?
@media (screen-fold-posture: laptop){
body {
display: flex;
flex-flow: column nowrap;
}
.videocall-area,
.videocall-controls {
flex: 1 1 env(fold-bottom);
}
}
?
CSS 的比較函數是指 min() 、max() 和 clamp() ,我們可以給這幾個函數傳入值(多個)或表達式,它們會對傳入的值進行比較,然后返回最合適的值。另外,這幾個和我們熟悉的 calc() 類似,也可以幫助我們在 CSS 中做動態計算。?
先看 min() 和 max() ,它們之間的差異只是返回值的不同:?
下圖展示了 min(50vw, 500px) 在瀏覽器視窗寬度改變時,返回的值的變化:?
Demo: https://codepen.io/airen/full/mdeLMoZ
?
把上面的示例的 min() 換成 max() 函數,即 max(50vw, 500px),它的返回值是:?
Demo: https://codepen.io/airen/full/oNjdGyv
clamp() 和 min() 以及 max()略有不同,它將返回一個區間值,即 在定義的最小值和最大值之間的數值范圍內的一個中間值。該函數接受三個參數:?
?
clamp(MIN, VAL, MAX),這三個值之間的關系(或者說取值的方式):?
?
比如下面這個示例:?
.element {
/**
* MIN=100px
* VAL=50vw ? 根據視窗的寬度計算
* MAX=500px
**/
width: clamp(100px, 50vw, 500px);
}
?
就這個示例而言,clamp() 函數的計算會經歷以下幾個步驟:?
.element {
width: clamp(100px, 50vw, 500px);
/* 50vw相當于視窗寬度的一半,如果視窗寬度是760px的話,那么50vw相當等于380px*/
width: clamp(100px, 380px, 500px);
/* 用min()和max()描述*/
width: max(100px, min(380px, 500px))
/*min(380px, 500px)返回的值是380px*/
width: max(100px, 380px)
/*max(100px, 380px)返回的值是380px*/
width: 380px;
}
示例效果如下:
Demo: https://codepen.io/airen/full/pojVpJv
?
簡單地說,clamp() 、min() 和 max() 函數都可以隨著瀏覽器視窗寬度的縮放對值進行調整,但它們的計算的值取決于上下文。
我們來看一個比較函數中 clamp() 的典型案例。假設我們需要在不同的屏幕(或者說終端場景)運用不同大小的 font-size :?
在還沒有 CSS 比較函數之前,使用了一個叫 CSS 鎖(CSS Locks)的概念來實現類似的效果:?
需要做一些數學計算:?
Demo: https://codepen.io/airen/full/bGqdOma
?
使用 clamp() 之后,只需要一行代碼就可以實現:?
/** minf: 20px (min font-size)
* maxf: 40px (max font-size)
* current vw: 100vw
* minw: 320px (min viewport's width)
* maxw: 960px (max viewport's width)
*/
h1 {
font-size: clamp(20px, 1rem + 3vw, 40px);
}
?
使用這方面的技術,我們就可以輕易實現類似下圖這樣的效果:?
注,上圖來自《Use CSS Clamp to create a more flexible wrapper utility》一文。
CSS 內容可見性,說要是指 content-visibilit 和 contain-intrinsic-size 兩個屬性,目前隸屬于 W3C 的 CSS Containment Module Level 2 模塊,主要功能是可以用來提高頁面的渲染性能。
一般來說,大多數Web應用都有復雜的UI元素,而且有的內容會在設備可視區域之外(內容超出了用戶瀏覽器可視區域),比如下圖中紅色區域就在手機設備屏幕可視區域之外:?
在這種場合下,我們可以使用CSS的 content-visibility 來跳過屏幕外的內容渲染。也就是說,如果你有大量的離屏內容(Off-screen Content),這將會大幅減少頁面渲染時間。?
Google Chrome 團隊有工程師對 content-visibility 做過相關的測試:?
使用了 CSS 的 `content-visibility` 屬性,瀏覽器的渲染過程就變得更加容易。本質上,這個屬性 改變了一個元素的可見性,并管理其渲染狀態。?
而 contain-intrinsic-size 屬性控制由 content-visibility 指定的元素的自然尺寸。它的意思是,content-visibility 會將分配給它的元素的高度(height)視為 0,瀏覽器在渲染之前會將這個元素的高度變為 0,從而使我們的頁面高度和滾動變得混亂。但如果已經為元素或其子元素顯式設置了高度,那這種行為就會被覆蓋。如果你的元素中沒顯式設置高度,并且因為顯式設置 height可能會帶來一定的副作用而沒設置,那么我們可以使用contain-intrinsic-size來確保元素的正確渲染,同時也保留延遲渲染的好處。?
換句話說,contain-intrinsic-size 和 content-visibility 是一般是形影不離的出現:?
section {
content-visibility: auto;
contain-intrinsic-size: 1000px;
}
如果你使用瀏覽器開發者工具審查代碼時,將鼠標放到一個 <img> 標簽上,你會看到類似下圖這樣的:?
<img> 的 src 路徑上浮出來的圖片底下有一行對圖像的尺寸的描述,即252 x 158 px (intrinsic: 800 x 533 px) ,其實現這表述圖片尺寸中兩個重要信息:?
?
其實在 CSS 中給一個元素框設置大小時,有的是根據元素框內在的內容來決定,有的是根據上下文來決定的。根據該特性,CSS的尺寸也分為內部(內在)尺寸和外部(外在)尺寸。?
?
通過一個簡單的示例來向大家演示 CSS 內在尺寸的特性,即 min-content 、max-content 和 fit-content 的特性。?
<h1>CSS is Awesome</h1>
<style>
h1 {
width: auto;
}
</style>
?
先來看 h1 的 width 取值為 auto 和 min-content 的差異:?
// 外在尺寸
h1 {
width: auto; // 根據容器變化
}
// 內在尺寸
h1 {
width: min-content; // 根據內容變化
}
Demo: https://codepen.io/airen/full/zYZvGrY
?
從上圖中不難發現,width 取值為 min-content 時,h1 的寬度始終是單詞“Awesome”長度(大約是144.52px)。它的寬度和容器寬度變化并無任何關系,但它受排版內相關的屬性的影響,比如font-size、font-family 等。?
再來看max-content :?
Demo: https://codepen.io/airen/full/zYZvGrY
?
當h1 的 width 取值為 max-content 時,它的寬度是h1 所在行所有內容的寬度。最后來看 fit-content :?
?
Demo: https://codepen.io/airen/full/zYZvGrY
?
相對而言,fit-content 要比 min-content 和 max-content 復雜地多:?
h1 {
width: fit-content;
}
// 等同于
h1 {
width: auto;
min-width: min-content;
max-width: max-content;
}
簡單地說,fit-content 相當于 min-content 和 max-content,其 取值:?
?
使用下圖來描述它們之間的關系:?
min-content、max-content 和 fit-content 被稱之個內在尺寸,它可以運用于設置容器尺寸的屬性上,比如width 、height 以及 inline-size 和 block-size 等。但有些屬性上使用的話則會無效:?
?
在布局上使用 min-content 、max-content 或 fit-content 可以幫助我們設計內在布局,另外在構建一些自適應的布局也非常靈活。特別是和 CSS 的 Grid 和 Shapes 相關特性結合,還能構建一些具有創意的布局。?
最后有一點需要特別聲明,fit-content 和 fit-content()函數不是相同的兩個東東,使用的時候需要區別對待。?
display 對于大家而言并不陌生,主要用來格式化上下文,這里特別拿出來和大家說的是因為 display 也有一些變化。其中之一就是 display 未來可以支持多個值:?
據最新的消息,Sarafi 瀏覽器已經把display 設置兩個值已進入實驗性屬性。display 取兩個值的含義大致如下:?
另外單獨要說的是,display 新增了 contennts 屬性值,** W3C規范是這樣描述的**:?
大致意思是說:?
設置了 display: contents 的元素自身將不會產生任何盒子,但是它的子元素能正常展示。
?
比如:?
<div class="outer">
I'm, some content
<div class="inner">I'm some inner content </div>
</div>
<style>
.outer {
border: 2px solid lightcoral;
background-color: lightpink;
padding: 20px;
}
.innter {
background-color: #ffdb3a;
padding: 20px;
}
</style>
?
上面這個簡單地示例代碼,你將看到的效果如下:?
如果我們在.outer 元素上顯式設置 display: contents ,該元素本身不會被渲染,但子元素能夠正常渲染:?
Demo: https://codepen.io/airen/full/abJvyoj
?
在某些布局中,特別是不希望調整 HTML 的結構的時候,我們就可以使用該特性。比如在 Flexbox 或 Grid 中,希望把其他后代元素變成網格項目或 Flex項目,那就可以這樣做:?
Demo: https://codepen.io/airen/full/zYZvdJb
?
display: contents 在規范討論階段和 display: subgrid 的討論中是非常的激烈,最終是 display: contents 獲勝了。你現在在Grid的布局中,也沒有單獨的display: subgrid ,而是將subgrid 移入到 grid-template-columns 和 grid-template-rows 中。?
另外還有一個比較大的爭執就是 display: contents 和 Web 可訪問性方面的。有關于這方面的討論,你要是感興趣的話,可以閱讀:?
?
CSS 中的 @ 規則有很多種,但大家比較熟悉的應該是 @import 、@media 和 @supports 之類的。今天給大家簡單的提幾個不常見的,比如:?
?
使用過 CSS 處理器的同學,應該用過嵌套來組織自己的代碼,比如 SCSS:?
// SCSS
foo {
color: red;
& bar {
color: green;
}
}
上面的代碼經過編譯之后:?
// CSS
foo {
color: red;
}
foo bar {
color: green;
}
慶幸的是,W3C 也在討論和定義CSS中的嵌套規則。目前兩種規則:?
foo {
color: red;
@nest bar {
color: green;
}
}
// 或者
foo {
color: red;
& bar {
color: green;
}
}
// 都等同于
foo {
color: red;
}
foo bar {
color: green;
}
也可以和媒體查詢 @media 相互嵌套:?
article {
color: darkgray;
& > a {
color: var(--link-color);
}
}
code > pre {
@media (hover) {
&:hover {
color: hotpink;
}
}
}
code > pre {
@media (hover) {
@nest &:hover {
color: hotpink;
}
}
}
article {
@nest section:focus-within > & {
color: hotpink;
}
}
main {
padding: var(--space-sm);
@media (width >=540px) { & {
padding: var(--space-lg);
}}
}
除了 @nest 之外還有 @apply 。你可能在一些前端的框架或構建器中看到過 @apply:?
如果你在 Chrome Canary 瀏覽器“實驗性屬性” 就可以直接體驗 @apply :?
?
簡單地說,它有點類似于 SCSS 中的混合宏 @mixin 和 @extend :?
:root {
--brand-color: red;
--heading-style: {
color: var(--brand-color);
font-family: cursive;
font-weight: 700;
}
}
h1 {
--brand-color: green;
@apply --heading-style;
}
@property 是用來注冊一個變量的,該變量是一個 CSS Houdini 中的變量,但它的使用和 CSS 中的自定義屬性(CSS變量)是一樣的,不同的是注冊方式:?
// Chrome 78+
// 需要在 JavaScript腳本中注冊
CSS.registerProperty({
'name': '--custom-property-name',
'syntax': '<color>',
'initialValue': 'black',
'inherits': false
})
// Chrome 85+
// 在CSS文件中注冊
@property --custom-property-name {
'syntax': '<color>',
'initialValue': 'black',
'inherits': false
}
他的最大特色之一就是可以指定已注冊的 CSS 變量的類型、初始值,是否可繼承:?
上圖截取于 Maxi 在推特上發的推文。
?
雖然它的使用方式和 CSS 的自定義屬性相似,但它要更強大,特別是在動效方面的使用,能增強 CSS 的動效能力,甚至實現一些以前 CSS 無法實現的動效。比如?
@property --hue {
initial-value: 0;
inherits: false;
syntax: '<number>';
}
@keyframes rainbow {
to {
--hue: 360;
}
}
@property --milliseconds {
syntax: '<integer>';
initial-value: 0;
inherits: false;
}
.counter {
counter-reset: ms var(--milliseconds);
animation: count 1s steps(100) infinite;
}
@keyframes count { to {
--milliseconds: 100;
}}
把它和 CSS Houdini 的 Paint API 結合起來,可做的事情更多:?
更多這方向的效果可以在 houdini.how 網站上查閱:
Una Kravets 在 Google I/O 開發大會上就分享了容器查詢 @container ,她把它稱為新的響式布局所需特性之一:?
那么容器查詢 @container 可以做什么呢?假設你的設計師給你提供了一份像下圖這樣的設計稿:?
你可能首先會想到的是 @media (在沒有容器查詢之前,似乎也只有這樣的方式),而有了@container 之后,就可以換過一種姿勢:?
這兩張圖上來自于 @shadeed9 的 《CSS Container Queries For Designers》一文,他的另一篇文章《Say Hello To CSS Container Queries》也是介紹容器查詢的。
看上去非常強大,事實上也很強大,并且它的使用和 @meida 非常相似:?
// Demo: https://codepen.io/una/pen/mdOgyVL
.product {
contain: layout inline-size;
}
@container (min-width: 350px) {
.card-container {
padding: 0.5rem 0 0;
display: flex;
}
.card-container button {
/* ... */
}
}
Demo: https://codepen.io/una/pen/mdOgyVL
?
對于 @container 特性,有叫好的,也有不同的,比如 Kenton de Jong 在他的新博文《Why I am not a fan of CSS container queries》闡述了自己不喜歡該t特性:?
就我個人而言,我是很喜歡這個特性,后面會花一定的時間深入了解和學習 @container。當然有討論是一件好事,這樣會讓該特性更成熟,如果你也想參與進來討論的話,可以點擊這里加入。?
我以前只看到過 @scope 規則,主要是用來處理 CSS 中樣式規則作用域相關的,但并沒有深入了解過。Una Kravets 在 Google I/O 開發大會分享上再次看到了 @scope :?
上圖是 Miriam Suzanne 繪制的!
?
@scope 內的樣式允許穿透和特定組件的樣式,以避免命名沖突,許多框架和插件(如CSS模塊)已經使我們能夠在框架內做到這一點。現在,這個規范將允許我們為我們的組件編寫具有可讀性的CSS的本地封裝樣式,而不需要調整標記。?
/* @scope (<root>#) [to (<boundary>#)]? { … } */
@scope (.tabs) to (.panel) {
:scope { /* targeting the scope root */ }
.light-theme :scope .tab { /* contextual styles */ }
}
怎么看上去和 Web Componed中的 Scope 那么的相似呢??
對于 @layer ,我第一見:?
@layer reset {
* { box-sizing: border-box; }
body { margin: 0; }
}
// ...
@layer reset { /* add more later */ }
@import url(headings.css) layer(default);
@import url(links.css) layer(default);
@layer default;
@layer theme;
@layer components;
@import url(theme.css) layer(theme);
@layer default, theme, components;
@import url(theme.css) layer(theme);
@layer framework.theme {
p {
color: rebeccapurple;
}
}
@layer framework {
@layer theme {
p { color: cyan; }
}
}
上面代碼表示啥意思,我也還沒整明白,只知道 @layer 被稱為層疊層(Cascade Layers)。該特性是 什么** W3C 層疊和繼承規范 Level5** 中新提出來的。?
在我分享結束沒多久,正在整理這篇文章的時候,發現我的偶像 @argyleink 也分享了一個相似的話題《Hover:CSS! What's New in 2021?》,分享了 31 個 CSS 相關的特性,并且按風險級別分為高、中、低三檔:?
你會發現,和我整理的特性有很多吻合之處。如果你聽過他去年在倫敦CSS大會分享的《London CSS: What‘s New in 2020?》,你會發現 2021 年的是 2020 年的升級版。?
在 2020 年聽完 分享之后,我也整理了一份中文版本的《2020年你不應該錯過的 CSS 新特性》,并在淘系前端團隊 微信公眾號發過。
?
文章很長,能閱讀到這里,說明你也是 CSS 的真愛。感謝大家的閱讀,在未來我將繼續為大家服務。把 CSS 方面最新、最有意思的一面與大家共享!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。