鏤空遮蓋層效果的研究

圖片描述
上圖是「QQ截圖」選擇區域時的畫面,能夠看到除了中間框選的部分,其餘區域被一層半透明層覆蓋(backdrop),這種效果不知道專業叫法,這裏稱呼它「鏤空遮蓋層」。實際業務需求中卻是很少見,比較常見的是「頁面上的新手引導」,「視頻網站的關燈模式」等用到這種效果,通用簡單的作法是將內容元素的z-index設置大於遮蓋層的,使該元素顯示在遮蓋層上面。接下來分享下其餘的方法,可能對某些特殊場景有用。網站

如下介紹的方法有:經過多個DIV拼接,單個DIV利用CSS的屬性border, outline, box-shadow和混合模式mix-blend-mode來實現,下面分別從視覺動做來講明。spa

視覺

首先,先用樣式實現內容上覆蓋一層半透明遮蓋,其中某個區域鏤空。
圖片描述.net

DIV拼接

最原始的方法,圍着鏤空區域拼接4個div,拼接的方式不少,好比上面的圖中用了不一樣顏色來表示4個div3d

<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元素去構造遮蓋層,計算麻煩,而且鏤空區域只能是矩形。視頻

border

盒模型包括了contentborder,能夠用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

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/

優勢簡單方便,但鏤空區域一樣只能是矩形。

box-shadow

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是有效的,因此鏤空區域能夠是圓角矩形、橢圓、圓形等。

mix-blend-mode

這是在網站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/

其餘

其餘好比使用CanvasSVG比較麻煩,就不過多介紹了。
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/

對於outlinebox-shadow,由於它們自己就不佔據空間,鼠標事件對它們是沒有效果的,自帶「穿透」效果,因此除了要對鏤空遮罩層設置pointer-events:none,還須要再覆蓋一層透明的遮蓋層,一樣監聽父級容器的mousemove事件,動態的對該透明層設置pointer-events
https://jsfiddle.net/4dfagcmr/

混合模式的方法,原覺得經過監聽鏤空元素的mouseentermouseleave來控制pointer-events就能夠了,但一樣當pointer-events:none時沒法監聽鼠標事件,因此也只能經過鼠標座標來判斷。
https://jsfiddle.net/c1aoe0dg/

某些場景下,如仿Snipaste截圖效果,須要對遮蓋層下的全部元素監聽鼠標進出事件,這時候對整個鏤空遮罩層設置pointer-events:none就好了。
圖片描述

語焉不詳,敬請諒解。

相關文章
相關標籤/搜索