你還在用圖片做引導蒙層?

  • 2019 年 12 月 16 日
  • 筆記

首先認識一下引導蒙層,如下圖頁面是一個蒙層,會在某個局部位置高亮我們需要重點突出的內容:

蒙層有兩個核心元素,引導內容區域(即需要重點突出的內容元素)和半透明蒙層元素。

都9012年了,如果還在用圖片做蒙層,是不是太low了。

圖片引導蒙層有幾大缺點:

  1. 圖片大,影響載入
  2. 圖片的內容都是假的,和真實的底部內容沒對上
  3. 全螢幕蒙層圖片,圖片的寬高和螢幕寬高不一致,顯示兩邊留黑,或者有壓縮的效果。
  4. 圖片的引導位置不能點擊。
  5. low ?not cool ?

本文講述六種思路來實現引導蒙層

  • z-index實現蒙層
  • 動態opacity實現
  • border實現
  • box-shadow實現
  • 節點複製實現
  • canvas實現

以上六種引導蒙層實現思路,在一定情況下都能滿足業務需求,從不同角度來實現了引導蒙層。z-index最簡單,canvas最靈活,就個人而言,更加喜歡骨架屏式的動態opacity蒙層實現,更有趣更酷!!!

思路一:使用z-index

  • 新增一個div,設置為半透明區域,大小覆蓋整個頁面
  • 半透明蒙層區域z-index大於頁面元素
  • 引導內容區域大於半透明蒙層區域z-index

這個好理解,頁面元素都是有層級的,我們只需要把引導內容區域設置為最頂層的層級,在引導內容區域之下設置一個遮罩層,其他內容元素的z-index都地域這個遮罩層即可。我們來看一個簡單例子。

.z1{    position:absolute;    left:50px;    top:50px;    width:50px;    height:50px;    background:blue;    z-index:1;  }  .z2{    position:absolute;    left:60px;    top:60px;    width:50px;    height:50px;    background:red;    z-index:2;  }  .z3{    position:absolute;    left:70px;    top:70px;    width:50px;    height:50px;    background:yellow;    z-index:3;  }

我們修改一下z2的樣式。

.z2{    position:absolute;    left:50px;    top:50px;    width:50px;    height:50px;    background:black;    opacity:0.5;    z-index:2;    animation:z_index 2s linear infinite alternate;  }  @keyframes z_index {      from {        left:50px;        top:50px;        width:50px;        height:50px;      }      to {        left:0px;        top:0px;        width:200px;        height:200px;      }    }

只要在布局頁面元素的時候,把需要做蒙層的元素確定好,配合js,動態的設置元素的z-index + opacity,就可以很好的做到頁面的引導蒙層效果。

思路二:使用opacity將非蒙層元素半透明

  • 引導內容區域無需改動
  • 頁面其他節點元素半透明

我們不再新增蒙層,而是完全操作頁面節點,將需要遮罩的節點都設置為半透明,引導蒙層顯現內容則完全顯示出來。頁面的效果和蒙層不太一樣,對於空白地方,我們仍然是完全顯示,只是將有內容的元素給半透明,類似骨架屏的效果。 為了演示效果,我們看如下例子: 頁面設置6個元素。

<div class="wrap">      <div class="z z1"></div>      <div class="z z2"></div>      <div class="z z3"></div>      <div class="z z4"></div>      <div class="z z5"></div>      <div class="z z6"></div>    </div>

將元素內容用flex並排布局。

.wrap{    display:flex;    flex-wrap:wrap;    width:150px;  }  .z{    width:50px;    height:50px;    transition:all 1s;  }  .z1{    background:blue;  }  .z2{    background:black;  }  .z3{    background:yellow;  }  .z4{    background:red;  }  .z5{    background:green;  }  .z6{    background:orange;  }

使用js操作,依次半透明其他元素,顯示當前元素來模擬蒙層。

let arry = Array.from(document.querySelectorAll(".z"));  let index = -1;  let direct = 1;  setInterval(()=>{    if(index>=5) direct = -1;    else if(index<=0) direct = 1;    index = index+direct;    arry.forEach((d,i)=>{      d.style.opacity = 1;    });    setTimeout(()=>{      arry.forEach((d,i)=>{        if(i==index) return;        d.style.opacity = 0.1;      });    },1000);  },2000)

看了這個例子,我們清晰的看到這個引導蒙層的實現過程。這種引導蒙層其實更好玩有趣,有點類似當前流行的骨架屏,其他已有元素需要遮罩的內容就是骨架屏的灰色部分,需要顯現的就是重點的蒙層內容。 有趣!!!

思路三:使用border的方式來實現

沒錯,就是普遍不能在普遍的border了,且看如下:

div {      border:1px solid #red;  }

那用border怎麼實現引導蒙層呢?

1、先了解下三角形

先看一個簡單的例子:

<div class="border_1"></div>
.border_1{      width: 100px;      height: 100px;      border-top:50px solid red;      border-right: 50px solid transparent;      border-bottom: 50px solid transparent;      border-left: 50px solid transparent;      box-sizing:border-box;  }

實現了一個倒三角,這個應用場景是不是就比較多了,很多tips的指引,標註等都會用到。我就看到過這種倒三角使用一張圖片代替的做法。 仔細看這段程式碼,主要有實現了三點:

  1. 四邊都設置了邊框
  2. 寬高都為100px,即上下、左右表框之和,其實小於等於這個值都行。
  3. 只有頂部邊框是紅色,其他邊框是透明的。

為了理解上面的實現,我們來看下如下程式碼:

.border_2{      width: 100px;      height: 100px;      background-color:green;      border-style:solid;      border-color:red yellow blue black;      border-width:50px;      animation:border_ani 2s linear infinite alternate;      box-sizing:border-box;  }  @keyframes border_ani {      from {          border-width:50px;      }      to {        border-width:0;      }    }

從圖中我們可以清晰的看到,隨著border-width的變化,整個div的綠色背景在跟隨變化。

  • 當border-width=0的時候,整個頁面只有綠色背景,即都是內容的大小
  • 當border-width=50的時候,整個div的大小都被border給充滿了,上下左右均分1/4,就是四個倒三角。

這樣我們就清晰的能得到:

當border-right,border-left,border-bottom都transparent透明,border-top是紅色的時候,所看到的就是一個倒三角。

同理我們還可以設置邊框的大小不一致,可以實現斜三角:

.border_3{      width: 0;      height: 0;      border-top:30px solid red;      border-right: 10px solid transparent;      border-bottom: 20px solid transparent;      border-left: 100px solid transparent;      box-sizing:border-box;  }

還可以實現工作中經常碰到的梯形:

.border_4{      width: 150px;      height: 150px;      border-top:50px solid red;      border-right: 50px solid transparent;      border-bottom: 50px solid transparent;      border-left: 50px solid transparent;      box-sizing:border-box;  }

好了,這裡不累贅了,感興趣的可以各種嘗試。遇到這種簡單邊線圖,就不要動不動使用圖片了。

2、再看實現引導蒙層

  • 新增一個div,作為蒙層元素
  • div中間大小和引導內容元素大小完全一致,且位置恰好重疊
  • div的border設置為半透明且無限放大

了解了上面的三角形的實現之後,估計你也能想出怎麼做引導蒙層了。一個div有四個邊框,如果我們把邊框都設置成半透明,然後中間的區域(上面border_2的green)設置成全透明會不就可以實現區域引導蒙層了嗎?然後再把邊框設置成超過螢幕的大小呢,就是全景引導蒙層了!

.border_5{      width: 150px;      height: 150px;      border-top:50px solid rgba(0,0,0,.5);      border-right: 50px solid rgba(0,0,0,.5);      border-bottom: 50px solid rgba(0,0,0,.5);      border-left: 50px solid rgba(0,0,0,.5);      box-sizing:border-box;  }

這是一個150px的區域蒙層,我們看下如下示例就能很明白了:

.border_6{      width: 20px;      height: 20px;      border-style:solid;      border-color:rgba(0,0,0,.5);      border-width:20px;      animation:border_ani 2s linear infinite alternate;      box-sizing:content-box;  }  @keyframes border_ani {      from {          border-width:20px;      }      to {        border-width:100px;      }    }

當然,我們還可以設置border-radius來實現圓形的蒙層區域,如下:

當然,這裡的邊框大小值都是寫死的,具體實現需要根據頁面內容修改或者動態修改即可。

如果是橢圓呢?

總結:

border可以實現各種邊線的形狀,可以實現引導蒙層,頁面指定區域透明,之外的都半透明來實現即可。

思路四、使用box-shadow來實現

  • 新增一個div,作為蒙層元素
  • div大小和內容元素大小完全一致,且位置恰好重疊
  • div的box-shadow的陰影尺寸設置為半透明且設置為比較大的約2000px大小

box-shadow,大夥都不陌生,就是盒子的陰影,我們先來了解下它的基本用法:

.boxshadow_1{      width:50px;      height:50px;      background:blue;      box-shadow: 10px 10px 5px 4px #000;  }

在寬高為50px的div,它的陰影水平和垂直都是10px,陰影模糊距離是5px,陰影的尺寸是4px,陰影是#000的顏色(這裡給body增加了一個yellow的背景色以便於區分)。

首先我們把陰影透明:

.boxshadow_2{      width:50px;      height:50px;      background:blue;      box-shadow: 10px 10px 5px 4px rgba(0,0,0,.5);  }

那怎麼讓陰影遮蓋整個頁面呢?

  • 陰影的水平和垂直距離是指距離原dev的距離,這個調整達不到效果,只會讓陰影更多的偏離元素。
  • 陰影的模糊距離指陰影的邊緣漸變模糊的距離,距離越長,只會讓漸變模糊加長,蒙層大小不會變。
  • 陰影的尺寸,這個是指多大的陰影,那我們將陰影尺寸設置很大呢?是的,就是這個了

看如下的例子,我們調整陰影的尺寸:

.boxshadow_3 {    width:50px;    height:50px;    background:blue;    box-shadow: 0px 0px 5px 0px rgba(0,0,0,.5);    animation:box_ani 2s linear infinite alternate;  }  @keyframes box_ani {      from {          box-shadow: 10px 10px 5px 0px rgba(0,0,0,.5);      }      to {          box-shadow: 10px 10px 5px 100px rgba(0,0,0,.5);      }    }

如上,我們只需要把陰影尺寸加大就可以實現引導蒙層了。 如果需要引導蒙層狀態下還能響應事件呢?只需要加一個pointer-events屬性即可。

box-shadow的陰影距離切勿盲目設置過大,經過測試這個值如果過大,比如4000px,在部分手機上陰影無法顯示出來。經過實踐,設置為2000px為佳。

思路五:使用頁面節點複製

  • 新增兩個div,一個半透明蒙層元素和一個蒙層內容區域
  • 將頁面節點引導內容拷貝到蒙層內容區域
  • 將蒙層內容區域的大小和位置與原節點引導內容完全重合

頁面內容已經做好了,我們需要引導蒙層來顯示某個元素,那麼將元素複製到最外層,頂層增加一層蒙層來實現,需要突出的引導內容在蒙層之上即可實現。

<div class="content one">我是第一個div,我是第一個div</div>  <div class="content two">我是第二個div,我是第二個div</div>  <div class="content three">我是第三個div,我是第三個div</div>  <div class="content four">我是第四個div,我是第四個div</div>  <div class="mask"></div>  <div id="maskContent"></div>

這裡設置了一個固定蒙層,和一個固定的蒙層內容元素,我們只需要填充即可。

.content{      padding:10px;      z-index:0;  }  .mask{      position:fixed;      left:0;      top:0;      width:100%;      height:100%;      background:rgba(0,0,0,.8);      z-index:900    }    #maskContent{      position:fixed;      z-index:999;      display:inline-block;      background-color: #fff;    }

這裡內容區域都是0,然後mask是900,我們的蒙層元素是999,就是最上層了。

function renderContent(cls){      let targetNode = document.querySelector(`.${cls}`);      let maskContent = document.getElementById("maskContent");      maskContent.innerHTML = targetNode.outerHTML;      let pos = targetNode.getBoundingClientRect();      maskContent.style.top=pos.top+"px";      maskContent.style.left=pos.left+"px";      maskContent.style.width=pos.width+"px";      maskContent.style.height=pos.height+"px";   }  let i = 0;  setInterval(()=>{      renderContent(['one','two','three','four'][i]);      if(++i>=4) i = 0;  },1000)

這裡為了演示效果,增加了一個定時器改變不同的遮罩層。易於理解,看下效果:

思路六:使用canvas實現

  • 新增一個canvas,繪製兩次圖形
  • 第一次:繪製一個全螢幕的半透明陰影
  • 第二次:使用xor繪製一個和引導內容區域的大小位置完全重合的區域

第二次繪製的內容區域和第一次重疊,使用xor,所以會透明,該引導內容區域就會完全顯示出來,這就是我們想要的效果了。

使用canvas的globalCompositeOperation屬性來實現,內容參考http://www.tutorialspoint.com/html5/canvas_composition.htm

重點看xor:Shapes are made transparent where both overlap and drawn normal everywhere else. 翻譯:canvas繪製的形狀在重疊處都會變成透明的,非重疊處的其他任何地方都正常繪製內容。

所以我們就可以在canvas裡面繪製一個canvas蒙層,然後在蒙層中需要顯示的內容用xor來繪製重疊,然後重疊內容就會被透明,那麼這個透明區域的內容就是我們想要的引導蒙層突出內容區域。具體看實例:

<div class="content one">我是第一個div,我是第一個div</div>  <div class="content two">我是第二個div,我是第二個div</div>  <div class="content three">我是第三個div,我是第三個div</div>  <div class="conteent four">我是第四個div,我是第四個div</div>  <canvas id="mask"></canvas>

頁面增加一個canvas節點。將canvas整體設置成半透明,然後再用xor來實現內容的繪製。

function mask(cls){      let targetNode = document.querySelector(`.${cls}`);      let pos = targetNode.getBoundingClientRect();      let canvas = document.getElementById("mask");      let width = window.innerWidth;      let height = window.innerHeight;;      canvas.setAttribute("width", width);      canvas.setAttribute("height",height);      var ctx = canvas.getContext("2d");      ctx.globalCompositeOperation = 'source-over';      ctx.fillStyle ='rgba(255, 255, 255, 0.9)';      ctx.fillRect(0, 0, width, height);      ctx.fill();      ctx.fillStyle ='white';      ctx.globalCompositeOperation="xor";      ctx.fillRect(pos.left,pos.top,pos.width,pos.height);      ctx.fill();   }  let array = ['one','two','three','four'];  let i = 0;  setInterval(()=>{      mask(array[i]);      i++;      if(i>=4) i = 0;  },1000)

看完以上實現,你最喜歡哪種實現方式呢?

Tags: