上圖是「QQ截圖」選擇區域時的畫面,能夠看到除了中間框選的部分,其餘區域被一層半透明層覆蓋(backdrop),這種效果不知道專業叫法,這裏稱呼它「鏤空遮蓋層」。實際業務需求中卻是很少見,比較常見的是「頁面上的新手引導」,「視頻網站的關燈模式」等用到這種效果,通用簡單的作法是將內容元素的z-index
設置大於遮蓋層的,使該元素顯示在遮蓋層上面。接下來分享下其餘的方法,可能對某些特殊場景有用。網站
如下介紹的方法有:經過多個DIV
拼接,單個DIV
利用CSS的屬性border
, outline
, box-shadow
和混合模式mix-blend-mode
來實現,下面分別從視覺和動做來講明。spa
首先,先用樣式實現內容上覆蓋一層半透明遮蓋,其中某個區域鏤空。
.net
最原始的方法,圍着鏤空區域拼接4個div
,拼接的方式不少,好比上面的圖中用了不一樣顏色來表示4個div
。3d
<div class="box"> <div class="text"></div> <div class="item-1"></div> <div class="item-2"></div> <div class="item-3"></div> <div class="item-4"></div> </div> <style> .item-1, .item-2, .item-3, .item-4 { position: absolute; } .item-1 { top: 0; left: 0; background: rgba(0, 0, 0, 0.5); width: 450; height: 100px; } .item-2 { top: 0; left: 450; right: 0; height: 300px; background: rgba(0, 0, 0, 0.5); } .item-3 { top: 300px; left: 150px; bottom: 0; right: 0; background: rgba(0, 0, 0, 0.5); } .item-4 { top:100px; left: 0; bottom: 0; width: 150px; background: rgba(0, 0, 0, 0.5); } </style>
實例:https://jsfiddle.net/0ast5u2j/code
優勢是兼容性好,缺點是要用多個DOM元素去構造遮蓋層,計算麻煩,而且鏤空區域只能是矩形。視頻
盒模型包括了content
和border
,能夠用content
表示鏤空區域,用border
表示遮蓋層,而且經過border-width
來定位鏤空區域的位置。和上面的方法有類似之處。blog
<div class="box"> <div class="text"></div> <div class="rect-border"></div> </div> <style> .rect-border { position: fixed; top: 0; left: 0; width: 300px; height: 200px; border-style: solid; border-color: rgba(0, 0, 0, 0.5); border-top-width: 100px; border-right-width: calc(100vw - 450px); border-bottom-width: calc(100vh - 300px); border-left-width: 150px; } </style>
實例:https://jsfiddle.net/708vngj1/事件
用這種方法須要計算,有些狀況還須要用到JS,而且鏤空區域只能是矩形(固然在不使用漸變的狀況下)。圖片
outline
不佔據空間,不影響自己元素和其餘元素,能夠經過對它設置足夠大的值來做爲遮蓋層。ip
<div class="box"> <div class="text"></div> <div class="rect-outline"></div> </div> <style> .rect-outline { position: absolute; left: 150px; top: 100px; width: 300px; height: 200px; outline: 3000px solid rgba(0, 0, 0, 0.5); }
實例:https://jsfiddle.net/rujLkg78/
優勢簡單方便,但鏤空區域一樣只能是矩形。
與outline
相似,box-shadow
一樣不影響元素的大小位置。
<div class="box"> <div class="text"></div> <div class="rect-shadow"></div> </div> <style> .rect-shadow { position: absolute; left: 150px; top: 100px; width: 300px; height: 200px; border-radius: 10px; box-shadow: 0 0 0 3000px rgba(0, 0, 0, 0.5); } </style>
實例:https://jsfiddle.net/8561js9L/
比上面一種方法好的地方是元素設置border-radius
是有效的,因此鏤空區域能夠是圓角矩形、橢圓、圓形等。
這是在網站https://momodel.cn/ 上看到的,利用混合模式,可使元素與父元素疊加部分透明,擺脫了單個元素限制,使鏤空區域能夠更自由,作更復雜的圖形,好比對話氣泡框。
<div class="box"> <div class="text"></div> <div class="overlay"> <div class="spoltlight"> </div> </div> </div> <style> .overlay { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 99999; background-color: rgba(0, 0, 0, 0.5); mix-blend-mode: hard-light; pointer-events: auto; } .spoltlight { position: absolute; left: 150px; top: 100px; width: 300px; height: 200px; border-radius: 10px; background-color: gray; } .spoltlight::after { content: ""; position: absolute; top: 100%; right: 50px; border: 15px solid transparent; border-top-color: gray; } </style>
實例:https://jsfiddle.net/bxjo306z/
其餘好比使用Canvas
和SVG
比較麻煩,就不過多介紹了。
Canvas實例:https://jsfiddle.net/3dbcvLp2/
SVG實例:https://jsfiddle.net/6wvdja2h/
不少場景下,還須要對鏤空區域下的DOM進行點擊、選擇等操做。
用DIV拼接的方法,鏤空區域原本就是空的,因此能夠直接對下面的DOM操做。
其餘方法,由於有真實DOM覆蓋在內容上面,因此就要用到pointer-events:none
,這樣鼠標事件能夠「穿透」該元素做用於下面的內容上。
大多數場景須要阻止操做遮蓋部分下面的DOM,只對鏤空部分進行「穿透」,因此不能直接對鏤空遮蓋層設置pointer-events:none
,應該在鼠標移動到鏤空區域時設置pointer-events:none
,離開鏤空區域設置pointer-events:auto
。注意的是不能在鏤空遮蓋層上監聽mosuemove
,由於當它被設置爲pointer-events:none
時,就沒法監聽了。
https://jsfiddle.net/02e64ndr/
對於outline和box-shadow,由於它們自己就不佔據空間,鼠標事件對它們是沒有效果的,自帶「穿透」效果,因此除了要對鏤空遮罩層設置pointer-events:none
,還須要再覆蓋一層透明的遮蓋層,一樣監聽父級容器的mousemove
事件,動態的對該透明層設置pointer-events
https://jsfiddle.net/4dfagcmr/
混合模式的方法,原覺得經過監聽鏤空元素的mouseenter
和mouseleave
來控制pointer-events
就能夠了,但一樣當pointer-events:none
時沒法監聽鼠標事件,因此也只能經過鼠標座標來判斷。
https://jsfiddle.net/c1aoe0dg/
某些場景下,如仿Snipaste截圖效果,須要對遮蓋層下的全部元素監聽鼠標進出事件,這時候對整個鏤空遮罩層設置pointer-events:none
就好了。
語焉不詳,敬請諒解。