<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          CSS mask 實現(xiàn)鼠標跟隨鏤空效果

          共 10568字,需瀏覽 22分鐘

           ·

          2021-11-27 21:40

          作者:XboxYan

          簡介:偏用戶體驗的前端

          來源:SegmentFault  思否社區(qū)


          偶然在某思看到這樣一個問題,如何使一個div的部分區(qū)域變透明而其他部分模糊掉?,最后實現(xiàn)效果是這樣的:


          進一步,還能實現(xiàn)任意形狀的鏤空效果:


          鼠標經(jīng)過的地方清晰可見,其他地方則是模糊的。

          可能一開始無從下手,不要急,可以先從簡單的、類似的效果開始,一步一步嘗試,一起看看吧。

          一、普通半透明的效果


          比如平時開發(fā)中碰到更多的可能是一個半透明的效果,有點類似于探照燈(鼠標外面的地方是半透明遮罩,看起來會暗一點)。如下:


          那先從這種效果開始吧,假設(shè)有這樣一個布局:

          <div class="wrap" id="img">
              <img class="prew" src="https://tva1.sinaimg.cn/large/008i3skNgy1gubr2sbyqdj60xa0m6tey02.jpg">
          </div>

          那么如何繪制一個鏤空的圓呢?先介紹一種方法。

          其實很簡單,只需要一個足夠大的投影就可以了,原理如下:


          這里可以用偽元素::before來繪制,結(jié)構(gòu)更加精簡。用代碼實現(xiàn)就是:

          .wrap::before{
            content:'';
            position: absolute;
            width: 100px;
            height: 100px;
            border-radius: 50%;
            left: 50%;
            top: 50%;
            transform: translate(-50%,-50%); /*默認居中*/
            box-shadow: 0 0 0 999vw rgba(0, 0, 0, .5); /*足夠大的投影*/
          }

          可以得到這樣的效果:


          二、借助 CSS 變量傳遞鼠標位置


          按照以往的經(jīng)驗,可能會在 js 中直接修改元素的 style 屬性,類似這樣

          img.addEventListener('mousemove', (ev) => {
              img.style.left = '...';
              img.style.top = '...';
          })

          但是這樣交互與業(yè)務(wù)邏輯混雜在一起,不利于后期維護。其實,我們只需要鼠標的坐標,在 CSS 中也能完全實現(xiàn)跟隨的效果。

          這里借助 CSS 變量,那一切就好辦了!假設(shè)鼠標的坐標是 [--x,--y](范圍是[0, 1]),那么遮罩的坐標就可以使用 calc計算了。

          .wrap::before{
            left: calc(var(--x) * 100%);
            top: calc(var(--y) * 100%);
          }

          然后鼠標坐標的獲取可以使用 JS 來計算,也比較容易,如下:

          img.addEventListener('mousemove', (ev) => {
              img.style.setProperty('--x', ev.offsetX / ev.target.offsetWidth);
              img.style.setProperty('--y', ev.offsetY / ev.target.offsetHeight);
          })

          這樣,半透明效果的鏤空效果就完成了。


          完整代碼可以訪問:https://codepen.io/xboxyan/pen/VwzRaNZ

          三、漸變也能實現(xiàn)半透明的效果


          除了上述陰影擴展的方式,CSS 徑向漸變也能實現(xiàn)這樣的效果。

          繪制一個從透明到半透明的漸變,如下:

          .wrap::before{
              content: '';
              position: absolute;
              width: 100%;
              height: 100%;
              left: 0;
              top: 0;
              background: radial-gradient( circle at center, transparent 50px, rgba(0,0,0,.5) 51px);
          }

          可以得到這樣的效果:


          然后,把鼠標坐標映射上去就可以了。從這里就可以看出 CSS 變量的好處,無需修改 JS,只需要在CSS中修改漸變中心點的位置就可以實現(xiàn)了

          .wrap::before{
            background: radial-gradient( circle at calc(var(--x) * 100% )  calc(var(--y) * 100% ), transparent 50px, rgba(0,0,0,.5) 51px);
          }


          四、背景模糊的效果嘗試


          CSS 中有一個專門針對背景(元素后面區(qū)域)的屬性:backdrop-filter。

          backdrop-filter鏈接:https://developer.mozilla.org/zh-CN/docs/Web/CSS/backdrop-filter

          使用方式和 filter完全一致!

          backdrop-filter: blur(10px);

          下面是 MDN 中的一個示意效果:


          backdrop-filter是讓當前元素所在區(qū)域后面的內(nèi)容模糊,要想看到效果,需要元素本身半透明或者完全透明;而filter是讓當前元素自身模糊。

          有興趣的可以查看這篇文章: CSS backdrop-filter簡介與蘋果iOS毛玻璃效果 ? 張鑫旭-鑫空間-鑫生活 (zhangxinxu.com)

          文章鏈接:https://www.zhangxinxu.com/wordpress/2019/11/css-backdrop-filter/

          需要注意的是,這種模糊與背景的半透明度沒有任何關(guān)系,哪怕元素本身是透明的,仍然會有效果。例如下面是去除背景后的效果 ,整塊都是模糊的。


          如果直接運用到上面的例子會怎么樣呢?


          1. 陰影實現(xiàn)


          在上面第一個例子中添加 backdrop-filter

          .wrap::before{
            content:'';
            position: absolute;
            width: 100px;
            height: 100px;
            border-radius: 50%;
            left: 50%;
            top: 50%;
            transform: translate(-50%,-50%); /*默認居中*/
            box-shadow: 0 0 0 999vw rgba(0, 0, 0, .5); /*足夠大的投影*/
            backdrop-filter: blur(5px)
          }

          得到效果如下:


          可以看到圓形區(qū)域是模糊的,正好和希望的效果相反。其實也好理解,只有圓形區(qū)域才是真實的結(jié)構(gòu),外面都是陰影,所以最后作用的范圍也只有圓形部分。

          2. 漸變實現(xiàn)


          現(xiàn)在在第二個例子中添加 backdrop-filter

          .wrap::before{
              content: '';
              position: absolute;
              width: 100%;
              height: 100%;
              left: 0;
              top: 0;
              background: radial-gradient( circle at calc(var(--x) * 100% )  calc(var(--y) * 100% ), transparent 50px, rgba(0,0,0,.5) 51px);
                backdrop-filter: blur(5px)
          }`

          效果如下:


          已經(jīng)全部都模糊了,只是圓形區(qū)域外暗一些。由于::before的尺寸占據(jù)整個容器,所以整個背后都變模糊了,圓形外部比較暗是因為半透明漸變的影響。

          總之還是不能滿足我們的需求,需要尋求新的解決方式。

          五、CSS MASK 實現(xiàn)鏤空


          與其說是讓圓形區(qū)域不模糊,還不如說是把那塊區(qū)域給鏤空了。就好比之前是一整塊磨砂玻璃,然后通過 CSS MASK 打了一個圓孔,這樣透過圓孔看到后面肯定是清晰的。

          可以對第二個例子稍作修改,通過徑向漸變繪制一個透明圓,剩余部分都是純色的遮罩層,示意如下:


          用代碼實現(xiàn)就是

          .wrap::before{
              content: '';
              position: absolute;
              width: 100%;
              height: 100%;
              left: 0;
              top: 0;
              -webkit-mask: radial-gradient( circle at calc(var(--x, .5) * 100% )  calc(var(--y, .5) * 100% ), transparent 50px, #000 51px);
                background: rgba(0,0,0,.3);
                backdrop-filter: blur(5px)
          }

          這樣就實現(xiàn)了文章開頭的效果:


          完整代碼可以查看:https://codepen.io/xboxyan/pen/porpoXJ

          六、CSS MASK COMPOSITE 實現(xiàn)更豐富的鏤空效果


          除了使用徑向漸變繪制遮罩層以外,還可以通過 CSS MASK COMPOSITE(遮罩合成)的方式來實現(xiàn)。

          CSS MASK COMPOSITE 鏈接:https://developer.mozilla.org/en-US/docs/Web/CSS/mask-composite

          標準關(guān)鍵值如下(firefox支持):

          /* Keyword values */
          mask-composite: add; /* 疊加(默認) */
          mask-composite: subtract; /* 減去,排除掉上層的區(qū)域 */
          mask-composite: intersect; /* 相交,只顯示重合的地方 */
          mask-composite: exclude; /* 排除,只顯示不重合的地方 */

          遮罩合成是什么意思呢?可以類比 photoshop 中的形狀合成,幾乎是一一對應(yīng)的。


          -webkit-mask-composite 與標準下的值有所不同,屬性值非常多,如下(chorme 、safari 支持)

          -webkit-mask-composite 鏈接:https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-composite

          -webkit-mask-composite: clear; /*清除,不顯示任何遮罩*/
          -webkit-mask-composite: copy; /*只顯示上方遮罩,不顯示下方遮罩*/
          -webkit-mask-composite: source-over; 
          -webkit-mask-composite: source-in; /*只顯示重合的地方*/
          -webkit-mask-composite: source-out; /*只顯示上方遮罩,重合的地方不顯示*/
          -webkit-mask-composite: source-atop;
          -webkit-mask-composite: destination-over;
          -webkit-mask-composite: destination-in; /*只顯示重合的地方*/
          -webkit-mask-composite: destination-out;/*只顯示下方遮罩,重合的地方不顯示*/
          -webkit-mask-composite: destination-atop;
          -webkit-mask-composite: xor; /*只顯示不重合的地方*/

          是不是一臉懵?這里做了一個對應(yīng)的效果圖,如果不太熟練,使用的時候知道有這樣一個功能,然后對著找就行了。


          回到這里,可以繪制一整塊背景和一個圓形背景,然后通過遮罩合成排除mask-composite: exclude打一個孔就行了,實現(xiàn)如下:

          .wrap::before{
              content: '';
              position: absolute;
              width: 100%;
              height: 100%;
              left: 0;
              top: 0;
              -webkit-mask: url("data:image/svg+xml,%3Csvg width='50' height='50' viewBox='0 0 50 50' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='25' cy='25' r='25' fill='%23C4C4C4'/%3E%3C/svg%3E"), linear-gradient(red, red);
                -webkit-mask-size: 50px, 100%;
                -webkit-mask-repeat: no-repeat;
                -webkit-mask-position: calc(var(--x, .5) * 100% + var(--x, .5) * 100px - 50px )  calc(var(--y, .5) * 100% + var(--y, .5) * 100px - 50px ), 0;
                -webkit-mask-composite: xor;   /*只顯示不重合的地方, chorem 、safari 支持*/
                mask-composite: exclude; /* 排除,只顯示不重合的地方, firefox 支持 */
                background: rgba(0,0,0,.3);
                backdrop-filter: blur(5px)
          }

          需要注意-webkit-mask-position中的計算,這樣也能很好的實現(xiàn)這個效果:


          完整代碼可以查看:https://codepen.io/xboxyan/pen/ExvMpQB

          你可能已經(jīng)發(fā)現(xiàn),上述例子中的圓是通過 svg 繪制的,還用到了遮罩合成,看著好像更加繁瑣了。其實呢,這是一種更加萬能的解決方式,可以帶來無限的可能性。比如我需要一個星星??的鏤空效果,很簡單,先通過一個繪制軟件畫一個。


          然后把這段 svg 代碼轉(zhuǎn)義一下,這里推薦使用張鑫旭老師的SVG在線壓縮合并工具。

          鏈接:https://www.zhangxinxu.com/sp/svgo/


          替換到剛才的例子中就可以了。

          .wrap::before{
              content: '';
              position: absolute;
              width: 100%;
              height: 100%;
              left: 0;
              top: 0;
              -webkit-mask: url("data:image/svg+xml,%3Csvg width='96' height='91' viewBox='0 0 96 91' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M48 0l11.226 34.55h36.327l-29.39 21.352L77.39 90.45 48 69.098 18.61 90.451 29.837 55.9.447 34.55h36.327L48 0z' fill='%23C4C4C4'/%3E%3C/svg%3E"), linear-gradient(red, red);
                -webkit-mask-size: 50px, 100%;
                -webkit-mask-repeat: no-repeat;
                -webkit-mask-position: calc(var(--x, .5) * 100% + var(--x, .5) * 100px - 50px )  calc(var(--y, .5) * 100% + var(--y, .5) * 100px - 50px ), 0;
                -webkit-mask-composite: xor;   /*只顯示不重合的地方, chorem 、safari 支持*/
                mask-composite: exclude; /* 排除,只顯示不重合的地方, firefox 支持 */
                background: rgba(0,0,0,.3);
                backdrop-filter: blur(5px)
          }

          星星鏤空實現(xiàn)效果如下:


          完整代碼可以查看:https://codepen.io/xboxyan/pen/vYJPaVy

          再比如一個心形?,實現(xiàn)效果如下:


          完整代碼可以查看:https://codepen.io/xboxyan/pen/KKvEBjb

          只有想不到,沒有做不到


          七、總結(jié)和說明


          以上實現(xiàn)了一個鼠標跟隨鏤空的效果,從簡單到復(fù)雜,從單一到通用,雖然借助了一點點 JS ,但是僅僅是“工具人”的角色,交互邏輯全部都由 CSS 完成,下面總結(jié)一下:

          1. 足夠大的陰影是一個實現(xiàn)圓形鏤空效果的小技巧
          2. CSS 漸變也能輕易的繪制出圓形鏤空背景
          3. 借助 CSS 變量可以很方便的利用鼠標位置實現(xiàn)想要的效果
          4. backdrop-filter 可以想象成磨砂玻璃的功能
          5. CSS Mask 可以給磨砂玻璃打孔,實現(xiàn)鏤空的效果
          6. 借助遮罩合成特性和SVG,可以實現(xiàn)任意形狀的鏤空效果

          CSS MASK 還是非常強大的,有必要還是多掌握一下。最后,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉(zhuǎn)發(fā)。



          點擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開更多互動和交流,掃描下方”二維碼“或在“公眾號后臺回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

          - END -


          瀏覽 75
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美内射视频 | 亚洲成人app | 国产三级在线免费观看 | 黄视频在线观看免费 | 日本精品在线播放 |