美文网首页
前端制作遮罩与蒙版

前端制作遮罩与蒙版

作者: 永恒君_9b95 | 来源:发表于2018-04-25 16:38 被阅读0次
    -1
    • 遮罩: 有色则显示,无色抠取,半透明则半透明
    • 蒙版: 黑色则抠除,白色显示,灰色则半透明

    概念上两者非常容易混淆,但完成的效果是一样的,需记住哪个是无色抠取,哪个是黑色抠除。
    再者还有个裁剪,只是做裁切,没有对半透明情况的处理。
    这样一说就知道,本文阅读起来可能是会有点乱的。

    那么前端方法中 如何实现,又各 有哪些应用场景 呢?

    • mask(css) (遮罩)
    • mask(svg)(蒙版)
    • background-clip(css)(裁切)
    • clip(canvas)(裁切)
    • globalCompositeOperation(canvas)(遮罩)
    • clip-path(css, svg)(裁切)
    • 其他旁门左道

    mask(css)

    比较容易搜到的,也是用得最多的,强得一批。
    现在是只有遮罩功能的,mask 指定的是下层形状,本元素及其所有子级为上层图案。
    <small>以后的发展可能会通过 mask-composite 实现蒙版,小期待一下吧。</small>

    遮罩嘛,即有色就显示,无色则隐藏。
    rgba(0,0,0,0)、tranpsarent,png 图片中的透明 或 无色 就抠除。

    mask 和 background 的设置非常类似,也可以缩写:
    mask-image / mask-repeat / mask-position / mask-size / mask-origin / mask-clip
    mask-image 也和 background-image 一样支持 url, gradient,image-set,element 等等。

    举几个栗子:

    /* 滚动容器底部带点效果 */
    .scroller-mask {
      -webkit-mask: linear-gradient(#000 calc(100% - 5em), transparent);
      mask: linear-gradient(#000 calc(100% - 5em), transparent);
    }
    /* 当然用 linear-gradient + pointer-events:none 也是不错的方法 */
    
    image
    /* 这个难理解一点,你看哪个有遮罩,哪块是透明的,唔,最好手写一下试试 */
    .mask {
      -webkit-mask-image: url(img/flower.png) center / 0 0 no-repeat;
      mask-image: url(img/flower.png) center / 0 0 no-repeat;
      animation: mask 2s;
    }
    @keyframes mask {
      0% {-webkit-mask-size: 0 0;mask-size: 0 0}
      100% {-webkit-mask-size: 100% 100%;mask-size: 100% 100%}
    }
    
    image
    DEMO:https://foreverz133.github.io/demos/works/mask/ (网速有点慢)

    至于剩下的 mask-mode / mask-type / mask-composite 浏览器支持还不太妙,暂可以不考虑。
    但功能上却是强大,需要更多了解还请自行翻阅 文档

    PS:兼容性 方面虽然一片红,IE 什么的抛弃掉,实验下来其实还不错。写上 -webkit-mask 基本都能用。
    PPS:firefox 中动画时 mask-size 小于 100% 会不显示,但定值可以,原因不知。

    mask(svg)

    个人有点莫名的习惯,不管做什么效果,都会往 SVG 上想一想,可能源于它强大的功能吧。
    相比 html+css 多了很多特性,如路径/线条的设置/诸多滤镜/视图限定等;
    相比 canvas 多了一些 dom 上的便捷操作,如事件。

    SVG 可以用 mask 来实现 蒙版,用 clipPath 来实现 裁剪(下文会讲)。

    区分一下,svg mask 为蒙版,白色为显示;css mask 为遮罩,有色为显示。

    <svg width="300" height="250" viewBox="0 0 300 250" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <path id="triangle" d="M50 0 L100 100 L0 100 Z" />
        <rect id="rect" width="100" height="100" fill="red" />
        <mask id="mask">
          <use xlink:href="#triangle" fill="rgba(255,255,255,0.5)" />
          <!-- 白色半透明的三角形蒙版 -->
        </mask>
      </defs>
      <use xlink:href="#rect" x="10" y="10" mask="url(#mask)" />
      <!-- 本来是方形,显示出来是粉色半透明的三角 -->
    </svg>
    
    • 如果 mask 的颜色 fill 不填或为 none 表示无色,则不显示
    • 如果有色但非黑白色,则按色值计算透明度,如 red 为 rgb(255,0,0) 相当于 opacity: 0.3333;
    • 其中 rgba(0,0,0,.5) 并不会显示半透明,因为它是黑色的,挺奇怪

    mask 蒙版内可以包裹透明图片或文字。

    但使用蒙版的元素,却莫名不能是 image,这就很完蛋呀,有待研究。

    background-clip(css)

    如果 css 的 mask 适用于图片和渐变等的话,那 background-clip:text 就适用于文字。
    字面意思,将背景裁切成文字范围。

    另外,background-clip 还可以设 content-box,也是不错的功能,
    默认 padding-box,border-box 有上边框不被修改的 BUG。

    注:兼容性 上,明文规定要加 -webkit-。顺便抛弃 IE。

    .demo {
      background-image: linear-gradient(red, #000);
      -webkit-background-clip: text;
      color: transparent; /* 不见得非要用 text-fill-color */
    }
    

    很多文章误以为是 text-fill-color 实现了遮罩功能,其实是 background-clip:text 呀!

    clip(canvas)

    clip 在 canvas 中本来的作用是切一块画布独立出来。
    拿来做遮罩效果也是可以的,但并非真的遮罩,只是裁剪,因为它不是按有色无色来判断显示的。

    var cv = document.querySelector('#canvas');
    var img = document.querySelector('img');
    var w = cv.width = window.innerWidth, h = cv.height = window.innerHeight;
    var ctx = cv.getContext('2d');
    
    ctx.save();
    ctx.arc(60, 60, 50, 0, 2*Math.PI);
    ctx.clip();  // 切一个圆形画布出来
    ctx.drawImage(img, 0, 0, img.width, img.height);
    ctx.restore();
    

    还可以用 beginPath, lineTo 等线条操作来形成图形。

    注:fillRect 和 strokeRect 是无法被切出来的,要用 rect。
    注:为了避免影响其他地方,用 save 和 restore 包起来就行了。
    注:文字遮罩用 clip 是无法实现的。

    globalCompositeOperation(canvas)

    修改 canvas 的渲染规则。比如后写的盖住前面的,改成后写的放到低层之类的。

    这些规则中有一个 source-in,就能实现 遮罩(按黑白色来判断显隐)。

    ctx.fillRect(10, 10, 200, 200);
    ctx.globalCompositeOperation = "source-atop"; // 改为前者区域绘制后者
    ctx.drawImage(img, 50, 50, img.width, img.height);
    ctx.globalCompositeOperation = "source-out";
    

    如果你用的 strokeRect 和 fillText 那绘制出来的也是相应效果哟。
    如果前者是半透明的,覆盖的后者渲染出来也会是半透明的。
    如果前者是半透明的 PNG 图片,覆盖的后者出来的也会是半透明,强无敌。

    注:globalCompositeOperation 的默认值是 source-over,用完了别忘了改回来,不然会影响后续操作。

    全部规则效果一览:https://foreverz133.github.io/demos/single/globalCompositeOperation.html
    其中有一些可以拿出来提一下,挺好玩的。
    source-in:交叉的部分渲染后者
    destination-in:交叉的部分渲染前者
    destination-out:去掉交叉的部分
    destination-over:后者放至下层

    clip-path(svg)

    主要还是以裁剪为主,裁剪当然是不会根据形状的颜色什么的来判断显隐的咯。

    <svg width="300" height="200" viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <path id="triangle" d="M50 0 L100 100 L0 100 Z" />
        <rect id="rect" width="100" height="100" fill="red" />
        <clipPath id="clip">
          <use xlink:href="#triangle" />
        </clipPath>
      </defs>
      <use xlink:href="#rect" x="10" y="10" clip-path="url(#clip)" />
    </svg>
    

    clip-path(css)

    css 的 clip-path 是老版属性 clip 的改良版,clip 必须绝对定位,且只有矩形还只能 px。
    clip-path 则支持方形/圆形/椭圆形/多边形,单位也更丰富。

    // 方形,上右下左距边框距离 round 圆角
    clip-path: inset(1px 10% 1em 1vw round 2px 4px 6px 8px);
    // 圆形,半径 at 位置
    clip-path: circle(15px at 20px 20px);
    // 椭圆,半轴长 at 位置
    clip-path: ellipse(50% 30% at 50% 50%);
    // 多边形
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
    

    我觉得 clip-path 和 border-radius 一样,改个图片或者盒子的样式又方便又爽。
    但也不一样,因为是裁剪,像 border 呀子级内容呀什么的也是会被剪掉的,hover 也还是原来的尺寸。

    其他旁门左道

    background

    比如盖一层镂空的五角星显示背景色呀,盖一层镂空的字呀什么的
    假 DEMO:https://foreverz133.github.io/demos/single/star.html

    border

    这应该就是名副其实的遮挡层了吧,与本文其实毫无关系。
    但可能你会在你不了解 mask 或需要兼容时用到。
    例子:http://www.zhangxinxu.com/wordpress/2016/03/better-black-mask-guide-overlay-method/

    除此之外,radial-gradient 可以完成部分类似功能,比如圆形的镂空,位置和大小设置相较也更方便。

    shape-outside

    shape-outside 仅能算作是高级版 float 扩展,也与本文毫无关系。
    只是因为既然写了 clip-path 那 shape-outside 就提一下,避免有理解错误。

    注:shape-outside 得是浮动元素时才有效。
    注:它能设的值和 clip-path 基本一致

    它并不会改变本身什么东西,形状不会变,border 等也还是原来的样子,还得结合 clip-path 来用。
    它只是让其他与其贴边的元素有了一个不一样的贴边效果。

    .box {
      width: 100px;
      height: 100px;
      float: left;
      background: pink;
      border: 3px solid #333;
      box-shadow: 0 0 10px;
      margin-right: 20px;
      clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
      shape-outside: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
    }
    
    tim 20171115110340

    PS:兼容性 吧,怎么说呢,回退到方形影响应该不大。

    虽然 clip-path 又不像 border-radius 可以加边框阴影什么的,但其实 polygon 多边形可以有高级玩法,
    比如:https://codepen.io/airen/pen/VPKQxb

    文档 显示以后会支持 url 和 element 等,那就很方便了呀。顺便再期待一下 shape-inside 的出现。

    你思考一下 css 的 mask / background-clip / clip-path 和 shape-outside 的使用场景,这其实很有意思。

    结语

    遮罩是有色的部分显示图案,蒙版是白色的部分显示图案,裁剪只是裁成这个形状,三者的实际妙用在本文中并没有深入书写,仅算是梳理其功能和明确其区别。
    还请大佬们多多分享此方面的巧妙案例咯,让小弟也开开眼。

    相关文章

      网友评论

          本文标题:前端制作遮罩与蒙版

          本文链接:https://www.haomeiwen.com/subject/lueylftx.html