【CSS】 ---- CSS 实现图片随鼠标移动局部放大特效
1. 效果【京东商品放大特效】
2. 实现方法
2.1 JS 实现
- 创建原图片的盒子,并放入原图片;
- 创建需要放大区域的遮罩块;
- 创建显示放大后图片显示的盒子和盒子内放大的图片;
- 给原图绑定移出移入和鼠标移动的监听事件;
- 移入和移出控制放大区域和放大后盒子的显示隐藏;
- 鼠标移动函数里边计算放大区域的位置坐标和,放大后图片的坐标;
- 这是原来我们常使用的方法,由于最近我在学习CSS的变量和函数,因此简化了这个实现。
2.2 CSS 实现
- 创建一个原图为背景的盒子;
- 给盒子绑定鼠标的移动和移出事件;
- 获取鼠标在盒子的位置,将位置坐标通过CSS变量传入CSS样式中;
- 同时移动和移出控制放大区域和放大后图片的展示使用透明度控制展示和隐藏。
3. 全局 CSS 变量
- –content-w 原图片的大小;
- –mask-w 放大块的大小;
- –result-w 放大块可移动的最大值;
- –mult 图片放大倍数;
- 这样方便封装为组件控制显示原图和放大区域等。
:root {
--content-w: 300px; /* 原图片的大小 */
--mask-w: 100px; /* 放大块的大小 */
--result-w: calc(var(--content-w) - var(--mask-w)); /* 放大块可移动的最大值 */
--mult: 3; /* 图片放大倍数 calc(var(--content-w) / var(--mask-w)),但是由于 calc(var(--content-w) / var(--mask-w)) 计算的结果不是倍数,因此倍数设置需要自己计算 */
}
4. 创建原图
4.1 原图盒子
<div class="rui-content" id="currentImage" style="--url: url('./static/car5.jpg')"></div>
4.2 原图样式
.rui-content {
width: var(--content-w);
aspect-ratio: 1;
position: relative;
background-image: var(--url);
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
4.3 效果
4.4 注意
- 通过 --url 这个变量获取了原图片的路径,这样就不要多地方设置图片路径;
- 通过 var(–content-w) 设置原图片盒子的宽度;
- 通过 aspect-ratio: 1 设置原图片盒子的宽高比。
4.5 监听事件绑定
let currentImage = document.getElementById('currentImage')
currentImage.addEventListener('mousemove', function (e) {
currentImage.style.setProperty('--area-op', 0.3)
currentImage.style.setProperty('--area-top', `${e.y}px`)
currentImage.style.setProperty('--area-left', `${e.x}px`)
currentImage.style.setProperty('--bg-op', 1)
})
currentImage.addEventListener('mouseout', function (e) {
currentImage.style.setProperty('--area-op', 0)
currentImage.style.setProperty('--bg-op', 0)
})
5. 创建放大区域
5.1 放大区域样式
.rui-content::before {
/* 计算放大块的位置 */
/* 当前位置的坐标 - 放大块的大小 / 2,计算出放大块的位置 */
/* 限制放大块的移动位置在 0 到 --result-w 之间,因此使用 css 的 clamp 函数获取最终值,其实就类似与 min(max(value, min), max) */
/* 使用 opacity 控制放大块的透明度来控制显示隐藏 */
--top: clamp(0px, calc(var(--area-top, 0) - var(--mask-w) / 2), var(--result-w));
--left: clamp(0px, calc(var(--area-left, 0) - var(--mask-w) / 2), var(--result-w));
content: '';
display: block;
width: var(--mask-w);
aspect-ratio: 1;
pointer-events: none;
background-color: red;
opacity: var(--area-op, 0);
position: absolute;
top: var(--top, 0);
left: var(--left, 0);
}
5.2 放大区域效果
5.3 注意
- 放大区域并没有创建新的 DOM 元素,而是使用 ::before 伪元素,直接作为放大区域的盒子使用;
- 使用 var, calc, clamp 三个 CSS 函数配合计算出当前放大区域所在的位置;
- 使用 var(–area-op, 0) 计算盒子的透明度来控制显示还是隐藏;
- 特别注意:需要设置盒子的 pointer-events 为 none,否则鼠标在放大区域显示的时候回丢失移入效果,就会出现不断闪动的效果。
6. 创建放大显示器
6.1 显示器样式
.rui-content::after {
/* 计算图片放大后的大小 */
--bg-size: calc(var(--content-w) * var(--mult));
/* 计算放大后图片的位置 */
--cur-top: calc(0px - (var(--area-top, 0) - var(--mask-w) / 2) * var(--mult));
--cur-left: calc(0px - (var(--area-left, 0) - var(--mask-w) / 2) * var(--mult));
/* 计算图片放大后超出边界的位置 */
--init-val: calc(0px - var(--result-w) * var(--mult));
/* 计算放大后的区间值 */
--top: clamp(var(--init-val), var(--cur-top), 0px);
--left: clamp(var(--init-val), var(--cur-left), 0px);
content: '';
display: block;
pointer-events: none;
width: var(--content-w);
aspect-ratio: 1;
opacity: var(--bg-op, 0);
background-image: var(--url);
background-size: var(--bg-size) var(--bg-size);
background-repeat: no-repeat;
background-position: var(--left, 0) var(--top, 0);
position: absolute;
top: 0;
left: calc(var(--content-w) + 10px);
}
6.2 显示器效果
6.3 注意
- 显示器并没有创建新的 DOM 元素,而是使用 ::after 伪元素,直接作为显示器的盒子使用;
- 使用 var, calc, clamp 三个 CSS 函数配合计算出当前显示器背景图的坐标位置;
- 使用 var, calc 计算图片放大后的大小;
- 使用 var, calc 计算放大后图片的位置;
- 使用 var, calc 计算图片放大后超出边界的位置;
- 使用 var, clamp 计算放大后的位置的区间值;
- 使用 var(–bg-op, 0) 控制显示器的显示和隐藏;
- 使用 var(–url) 获取显示器的图片;
- 注意:需要给显示器添加 pointer-events: none,防止鼠标移动到显示器,没有执行移出效果。
7. 最终效果
8. 放大六倍调整
9. 总结
- 使用伪元素配合 CSS 函数计算,减少 DOM 的创建和控制;
- 减少了 JS 的计算量,只用单纯的监听位置和移出,其他计算都交给 CSS 的函数完成,原生 JS 直接减少到 11 行代码,如果使用 vue 或者 react 库 JS 的监听代码量更少;
- 熟练的使用 CSS 一些函数,能够使我们更加便捷的实现很多以前需要 JS 才能实现的复杂特效,所以细学 CSS 还是很有必要的,不断学习前进。
原文地址:https://blog.csdn.net/m0_38082783/article/details/145155943
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!