如何通过css自定义不同形状的遮罩

2,559 阅读3分钟

前言

动画1.gif

需求要求 实现类似的图片预览效果,ui给出的图片预览周围是会渐隐的,并且图片可以拖动。

一开始的想法是背景图中间这一部分是渐渐透明的,然后图片作为底层放在背景图的下面,然后点击事件进行穿透,图片照样能够拖动,但是ui不给切,那就没办法了,只能通过研究一下css能否解决

实现思路

了解过 ps 的可能会比较清楚,再 ps 当中存在蒙版这个概念,也就是定义一个蒙版,将这个蒙版覆盖在一张图片上面,只有蒙版不为透明的部分,这张图片才是可见的。比方说一张图片长这样:

Pasted image 20230627110015.png

在我们为他添加了这样的蒙版以后

Pasted image 20230627110045.png

再ps蒙版中黑色部分表示隐藏图片,白色部分代表展示图片,我们再给他添加一个白底,最后的效果为:

Pasted image 20230627110045.png

这个效果是不是就和我们想要实现的效果有一点点接近,我们只需要画出一个由黑到白的渐变蒙版

Pasted image 20230627110359.png

Pasted image 20230627110404.png

这样边缘部分就会展现底下的白底,也就实现了渐隐的效果。

通过css实现蒙版

那么再css的属性当中,有没有类似于蒙版的属性呢,答案是有的,来了解一下 mask-image (遮罩) 属性

所谓遮罩(mask-image),就是原始图片只显示遮罩图片非透明的部分,在PS中称为“蒙版”。类似于现实世界中一张A4卡纸剪了个洞,我们可以通过洞看卡纸后面的物体,这里卡纸相当于遮罩层,只不过洞是遮罩层不透明的部分,其他部分是遮罩层透明的部分,与我们想象中的正好相反。

mask-image 的 值可以取各种渐变色,或者图片,使用的方法和ps蒙版是相同的,存在颜色的部分会被展示,透明的部分会被隐藏

我们可以使用渐变色或者png图片来实现遮罩的效果,比方说存在一张图片

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title></title>
  <style type="text/css">
    body {
      display: flex;
      position: relative;
      align-items: center;
      justify-content: center;
      background-color: antiquewhite;
    }
    #box1{
      position: relative;
      width: 1000px;
      height: 1000px;      
      -webkit-mask-image: radial-gradient(#FFF 5%, transparent 50%);      
      -webkit-mask-size: 100% 100%;
    }
    #box2{
      width: 1000px;
      height: 1000px;
      background: url('./img/pet.jpg');
      background-size: 100% 100%;
      position: absolute;
    }
  </style>
</head>
<body>
  <div id="box1">
    <div id="box2">
    </div>
  </div>
</body>
</html>

使用 radial-gradient(#FFF 5%, transparent 50%); 就可以构造一个渐隐的圆,当然你也可以使用线性渐变或者其他渐变属性,这些都是一样的,但是最终遵守的就是根据 mask-image 的特点,透明部分将不会展示,白色(有颜色)部分就会展示,最后得到:

Pasted image 20230629144918.png

当然也可以使用 png 图片,我们都知道,png 格式的图片是支持存在透明的部分的,将这个特点用在 mask-image 这个属性上面,就可以自定义需要隐藏的部分了。

我现在自己画了一张这样的 png 图片

Pasted image 20230629145109.png

利用这张图片就可以实现这样的效果

-webkit-mask-image: url('./img/zz2.png');

Pasted image 20230629145205.png

我们会发现,上面我们所有的 mask-image 属性都是作用在 box1 上的,这样就实现了无论内部的 box2 怎么移动,对应的部分就是会被隐藏,我们可以利用dom操作给box2加上拖拽试试。

动画1 1.gif

这样就成功实现了我们想要的效果。

完整代码如下

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title></title>
	<style type="text/css">
		body {
      display: flex;
      position: relative;
      align-items: center;
      justify-content: center;
      background-color: antiquewhite;
      /* background: url('./img/bg.jpeg'); */
      background-size: 100% 100%;
    }
		.aa {
			position: absolute;
			top: 20px;
			left: 20px;
		}
		.bb {
			position: absolute;
			top: 20px;
			left: 20px;
		}
		#box1{
      position: relative;
			width: 1000px;
			height: 1000px;
      /* -webkit-mask-image: linear-gradient(
        90deg,
        rgb(227,227,227),
        90%,
        transparent);
      -webkit-mask-image: linear-gradient(
        0deg,
        rgb(227,227,227),
        90%,
        transparent); */
      mask: radial-gradient(#000 5%, transparent 70%);
      -webkit-mask-image: radial-gradient(#FFF 5%, transparent 50%);
      -webkit-mask-image: url('./img/zz2.png');
			-webkit-mask-size: 100% 100%;
		}
		#box2{
			width: 1000px;
			height: 1000px;
      background: url('./img/pet.jpg');
      background-size: 100% 100%;
			position: absolute;
		}
	</style>
	
	<script type="text/javascript">
		
		window.onload = function(){
			/*
			 * 拖拽box1的元素
			 *  - 拖拽的流程
			 *  	1.当鼠标在被拖拽的元素上按下时开始拖拽 onmousedown
			 * 		2.当鼠标移动时被拖拽的元素跟随鼠标移动 onmousemove
			 * 		3.当鼠标松开时被拖拽的对象固定到当前位置 onmouseup
			 */
			var img01 = document.getElementById("box2")
			drag(img01);
		};
			
			/*
			 * 提取一个专门用来设置拖拽的函数
			 * 参数,开启拖拽的元素
			 */
			
			function drag(obj){
				obj.onmousedown = function(event){
				
				//设置box1捕获所有鼠标按下的事件
				/*
				 * setCapture()
				 *  - 只有IE支持,但是在火狐中调用时不会报错
				 * 		而如果使用chrome调用,会报错
				 */
                 obj.setCapture && obj.setCapture();
				
				
				event = event ||window.event
				//div的偏移量,鼠标.clientX-元素.offsetLeft
				
				//div的偏移量,鼠标.clientY-元素.offsetTop
				
				var ol = event.clientX -obj.offsetLeft;
				
				var ot = event.clientY - obj.offsetTop;
				//为document绑定一个onmousemove事件
				
				document.onmousemove = function(event){
					
					event = event ||window.event
					//当鼠标移动时被拖拽的元素跟随鼠标移动 onmousemove
					
					//获取鼠标的坐标
					var left = event.clientX-ol;
					var top = event.clientY-ot;
					
					//修改box1的位置
					obj.style.left = left+"px";
					obj.style.top = top+"px";
					
				};
				
				
				//为元素绑定一个鼠标松开事件
				document.onmouseup = function(){
					//当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
					//取消document的onmousemove事件
					
					document.onmousemove = null;
					document.onmouseup = null;
					//当鼠标松开时,取消对事件的捕获
					obj.releaseCapture && obj.releaseCapture();
				};
				/*
				 * 当我们拖拽一个网页的内容时,浏览器会默认去搜索引擎中搜索内容
				 *   此时会导致拖拽功能的异常,这是浏览器提供的默认行为
				 * 	 如果不希望发生这个行为,则可以通过return false来取消默认行为
				 */
				return false;
				};
			};
			
	</script>
</head>
<body>
	<div id="box1">
    <div id="box2">
    </div>
	</div>
</body>
</html>