利用css mask实现图片选中动画效果

369 阅读4分钟

效果预览

imgPointer.gif

mask详解

mask属性为一系列mask相关属性的缩写,具体如下

在本文中,主要用到以下属性

  1. mask-image
  2. mask-mode
  3. mask-repeat
  4. mask-size

mask-image

mask-image允许我们为元素添加一张图片作为元素的遮罩层,该图片的透明度(alpha)或亮度(luminance)会影响到元素的可见性。默认情况下,元素对应遮罩层透明部分会变得不可见,该行为可以通过mask-mode改变。

mask-mode

通过该属性改变遮罩层透明度或亮度对元素可见性的影响。取值如下

  1. alpha

    遮罩层透明部分会使得元素对应区域不可见。

  2. luminance

    遮罩图像的亮度值会影响元素内容的可见性。遮罩图像中较暗的部分会导致相应的元素内容变得较暗或透明,较亮的部分则保持不受影响。

  3. match-source

    如果mask-image的类型为<mask-source>,则表现为luminance。如果mask-image的类型为<image>则表现为alpha

mask-origin

该属性用来设置遮罩层的起点,常用取值如下

  1. content-box mask-position: 0 0在内容区域左上角
  2. padding-box mask-position: 0 0在内边距区域左上角
  3. border-box mask-position: 0 0在边框区域左上角。该值为默认值。

mask-position

该属性用来设置遮罩层相对mask-origin的位置,取值可为1到2个值,当取两个值时分别表示相对mask-origin水平位置和垂直位置的距离。当有缺省值时,默认为center。如

.maskDiv{
 mask-position: top; // 相当于mask-position:top center;
}

mask-repeat

当遮罩层大小比元素本身大小小时,可以通过mask-repeat设置遮罩层的重复方式。取值如下

  1. repeat(相当于repeat repeat) 默认值,遮罩层会被重复以覆盖绘制区域,直到没有更多空间时,最后一个图像将被裁剪掉。
  2. repeat-x 遮罩层在x轴方向重复。
  3. repeat-y 遮罩层在x轴方向重复。
  4. no-repeat 遮罩层不重复
  5. space(相当于space space) 图像会尽可能地重复,直到没有更多空间时才会裁剪。第一个和最后一个图像会固定在元素的两侧,图像之间的空白会均匀分布。这里借助background-repeat的图来方便理解

1691116459909.png

  1. round(感觉效果和repeat类似,我不是很理解)(相当于round round)

    随着允许的空间增加,重复的图像会被拉伸(没有间隙),直到有足够的空间(剩余空间大于等于图像宽度的一半)可以添加另一个图像。当添加下一个图像时,所有当前的图像会被压缩,以腾出空间。例如:一个原始宽度为260像素的图像,重复三次,可能会被拉伸,直到每个重复的宽度为300像素,然后再添加另一个图像。然后它们会压缩到225像素。

这里给出background-repeat文档地址,方便大家查看效果

background-repeat文档

mask-size

设置遮罩层的大小,用法类似background-size

实现选中图片效果思路图解

image.png

如上图,蓝色填充区域的大小其实就是我们选中样式的长宽,红色框框为重复的mask-image。利用mask-mode: alpha,遮罩层非透明的位置可见,透明位置不可见,我们只要设置红色填充区域为透明,即可实现选中样式。

完整代码

html

  <div class="container imgContainer">
    <div>
      <img src="../img/img1.png"/>
    </div>
    <div>
      <img src="../img/img2.png"/>
    </div>
    <div>
      <img src="../img/img3.png"/>
    </div>
    <div>
      <img src="../img/img4.png"/>
    </div>
    <div class="imgCursor"></div>
  </div>
html,
body{
  padding: 0;
  margin: 0;
  height: 100%;
  width: 100%;
  background: #84a3af;;
}

*{
  box-sizing: border-box;
}

.container{
  --padding-length: 35px;
  --pointer-size: 50px;
  padding: var(--padding-length);
  display: grid;
  width: 100%;
  grid-template-columns: repeat(4,1fr); //创建4列布局,每列占容器的4分之一
  gap: var(--padding-length);
  position: relative;
  div{
    cursor: pointer;
    img{
      width: 100%;
      height: 100%;
    }
  }
  .imgCursor{
    position: absolute;
    transition: top 1s,left 1s;
    -webkit-mask: conic-gradient(at var(--pointer-size) var(--pointer-size),transparent 75%,blue 75% 100%) 0 0 / calc(100% - var(--pointer-size)) calc(100% - var(--pointer-size));
    mask: conic-gradient(at var(--pointer-size) var(--pointer-size),transparent 75%,blue 75% 100%) 0 0 / calc(100% - var(--pointer-size)) calc(100% - var(--pointer-size));
  }
 
}
  const imgs = document.querySelectorAll('.imgContainer img');
    const imgCursor = document.querySelector('.imgContainer .imgCursor');
    imgs.forEach((item)=>{
      item.addEventListener('mouseenter',(e) => {
        const cursorGap = 5;
        const cursorSize = 5;
        const img = e.target;
        const imgCursorWidth = img.clientWidth  + cursorSize * 2 + 2 *cursorGap;
        const imgCursorHeight = img.clientHeight + cursorSize * 2 + 2 * cursorGap;
        imgCursor.style.setProperty('width',imgCursorWidth + 'px');
        imgCursor.style.setProperty('height',imgCursorHeight + 'px');
        const left = img.offsetLeft - cursorSize - cursorGap;
        const top = img.offsetTop - cursorSize - cursorGap; 
        imgCursor.style.setProperty('left',left + 'px');
        imgCursor.style.setProperty('top',top + 'px');
        imgCursor.style.setProperty('border',`${cursorSize}px solid #fff`);
        
      })
    })