之前在项目中做了一个图片对比的工具,演示如下
有一些有趣实用的小细节,一起看看如何实现的吧
一、布局
布局比较简单,两张图片上下重叠在一起就行了
<div class="wrap">
<img class="img" src="img1" >
<img class="img" src="img2">
</div>
这里可以只给第一个图片设置绝对定位,有几个好处
第1张图片层级自动就高了
第1张图片仍在原处,也无需设置 left、top
第1张图片不占空间,父级高度就由第2张图片决定了
.img:first-of-type{
position: absolute
}
示意如下
更多有关绝对定位的小技巧可以参考之前这篇文章:你可能不知道的绝对定位(跳转公众号)[1]
二、滑动图片
这里有个滑动的操作,如果直接使用 JS
来实现的话可能是这样(实际还有更多细节)
wrap.onmousedown = () => {}
document.onmousemove = () => {}
document.onmouseup = () => {}
其实在这里大可不必这么麻烦,完全可以借助「原生标签」的能力。提到"滑动",是不是可以想到 input range
呢?
<input type="range">
显然这个效果与实际相差甚远,不过完全可以用CSS
定制一下,主要是去除背景色
[type=range]{
margin: 0;
-webkit-appearance: none;
position: absolute;
height: 100%;
max-width: 100%;
background: none;
overflow: hidden;
z-index: 2;
}
::-webkit-slider-runnable-track {
background-color: transparent; /*去除背景*/
height: 100%;
cursor: ew-resize;
}
::-webkit-slider-thumb {
-webkit-appearance: none;
width: 4px;
height: 100%;
background-color: #18a0fb;
}
这样就变成了一个「背景透明,只剩下滑块」的滑动条了,并且整个范围都是可以滑动的
然后把滑动条覆盖在图片之上就行了
<div class="wrap">
<img class="img" src="img1" >
<input type="range">
<img class="img" src="img2">
</div>
三、裁切图片
现在需要在滑动过程中,动态裁剪上面的图片,可以通过 input
的 oninput
事件监听当前的进度,这里可以通过 CSS
变量记录在父级
input.oninput = () => {
this.parentNode.style.setProperty('--pos', this.value / 100);
}
有了这个 CSS 变量,很多种方式都可以实现裁剪效果了,想了想至少有以下几种方式
1. 直接改变width
如果是普通的 div
标签,可以直接通过 overflow: hidden
来裁剪内容,这里是图片,没有单独的父级,只能直接改变图片的宽高
.img:first-child{
width: calc( var(--pos, .5) * 100% );
height: 100%
}
但是这样很明显会有一个问题,图片被拉伸变形了
怎么解决呢?其实通过图片的 「object-」* 属性就可以完美解决了
object-fit - CSS:层叠样式表 | MDN (mozilla.org)[2]
object-position - CSS:层叠样式表 | MDN (mozilla.org)[3]
这里用cover
可以满足我们的需求
.img:first-child{
width: calc( var(--pos, .5) * 100% );
height: 100%;
object-fit: cover;
object-position: left;
}
这样就正常了
2. clip-path裁剪
可以直接利用 clip-path
中的 inset
函数裁剪一个矩形。inset
的四个参数分别表示距离上
、右
、下
、左
的距离,示意如下
用代码实现就是
.img:first-child{
clip-path: inset( 0 calc( 100% - var(--pos, .5) * 100% ) 0 0 )
}
这种实现简单快速,也很好理解
3. mask遮罩
还可以通过 mask遮罩 实现,具体做法就是绘制一个矩形,然后改变遮罩的尺寸mask-size
用代码实现就是
.img:first-child{
-webkit-mask: linear-gradient(red,red) left center no-repeat; /*渐变绘制一个矩形*/
-webkit-mask-size: calc( var(--pos, 0.5) * 100% ) 100%;
}
同样能得到这样的效果
你也可以查看以下任意链接:
img-diff (juejin.cn)[4]
img-diff (codepen.io)[5]
img-diff (runjs.work)[6]
四、总结一下
以上实现了一个图片对比的小交互,主要特点是通过 input range
的原生特性,省去了大量鼠标交互逻辑
接着是 CSS
变量的运用,JS
只是一个媒介,很多交互就可以直接在 CSS 中完成了
然后在裁剪图片中用到了3种方式,3种不同的思路相信可以带来不一样的思维空间,可以视情况自行选择,如果还有新的想法也可以和我交流讨论。
最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤
最近建了第一个群,欢迎加入😘
参考链接
[1]你可能不知道的绝对定位: https://juejin.cn/post/7204633786934607929
[2]object-fit - CSS:层叠样式表 | MDN (mozilla.org): https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-fit
[3]object-position - CSS:层叠样式表 | MDN (mozilla.org): https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-position
[4]img-diff (juejin.cn): https://code.juejin.cn/pen/7255942145469579319
[5]img-diff (codepen.io): https://codepen.io/xboxyan/pen/XWgMLxg
[6]img-diff (runjs.work): https://runjs.work/projects/f62ed9adee7f426b