【CSS】 ---- CSS 实现图片随鼠标移动局部放大特效

news/2025/1/18 20:14:10/

1. 效果【京东商品放大特效】

输入图片说明

2. 实现方法

2.1 JS 实现
  1. 创建原图片的盒子,并放入原图片;
  2. 创建需要放大区域的遮罩块;
  3. 创建显示放大后图片显示的盒子和盒子内放大的图片;
  4. 给原图绑定移出移入和鼠标移动的监听事件;
  5. 移入和移出控制放大区域和放大后盒子的显示隐藏;
  6. 鼠标移动函数里边计算放大区域的位置坐标和,放大后图片的坐标;
  7. 这是原来我们常使用的方法,由于最近我在学习CSS的变量和函数,因此简化了这个实现。
2.2 CSS 实现
  1. 创建一个原图为背景的盒子;
  2. 给盒子绑定鼠标的移动和移出事件;
  3. 获取鼠标在盒子的位置,将位置坐标通过CSS变量传入CSS样式中;
  4. 同时移动和移出控制放大区域和放大后图片的展示使用透明度控制展示和隐藏。

3. 全局 CSS 变量

  1. –content-w 原图片的大小;
  2. –mask-w 放大块的大小;
  3. –result-w 放大块可移动的最大值;
  4. –mult 图片放大倍数;
  5. 这样方便封装为组件控制显示原图和放大区域等。
: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 注意
  1. 通过 --url 这个变量获取了原图片的路径,这样就不要多地方设置图片路径;
  2. 通过 var(–content-w) 设置原图片盒子的宽度;
  3. 通过 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 注意
  1. 放大区域并没有创建新的 DOM 元素,而是使用 ::before 伪元素,直接作为放大区域的盒子使用;
  2. 使用 var, calc, clamp 三个 CSS 函数配合计算出当前放大区域所在的位置;
  3. 使用 var(–area-op, 0) 计算盒子的透明度来控制显示还是隐藏;
  4. 特别注意:需要设置盒子的 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 注意
  1. 显示器并没有创建新的 DOM 元素,而是使用 ::after 伪元素,直接作为显示器的盒子使用;
  2. 使用 var, calc, clamp 三个 CSS 函数配合计算出当前显示器背景图的坐标位置;
  3. 使用 var, calc 计算图片放大后的大小;
  4. 使用 var, calc 计算放大后图片的位置;
  5. 使用 var, calc 计算图片放大后超出边界的位置;
  6. 使用 var, clamp 计算放大后的位置的区间值;
  7. 使用 var(–bg-op, 0) 控制显示器的显示和隐藏;
  8. 使用 var(–url) 获取显示器的图片;
  9. 注意:需要给显示器添加 pointer-events: none,防止鼠标移动到显示器,没有执行移出效果。

7. 最终效果

输入图片说明

8. 放大六倍调整

输入图片说明

9. 总结

  1. 使用伪元素配合 CSS 函数计算,减少 DOM 的创建和控制;
  2. 减少了 JS 的计算量,只用单纯的监听位置和移出,其他计算都交给 CSS 的函数完成,原生 JS 直接减少到 11 行代码,如果使用 vue 或者 react 库 JS 的监听代码量更少;
  3. 熟练的使用 CSS 一些函数,能够使我们更加便捷的实现很多以前需要 JS 才能实现的复杂特效,所以细学 CSS 还是很有必要的,不断学习前进。

http://www.ppmy.cn/news/1564230.html

相关文章

【华为OD-E卷 - 数组连续和 100分(python、java、c++、js、c)】

【华为OD-E卷 - 数组连续和 100分&#xff08;python、java、c、js、c&#xff09;】 题目 给定一个含有N个正整数的数组, 求出有多少个连续区间&#xff08;包括单个正整数&#xff09;, 它们的和大于等于x 输入描述 第一行两个整数N x&#xff08;0 < N < 100000, …

Centos 宝塔安装

yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 安装成功界面 宝塔说明文档 https://www.bt.cn/admin/servers#wcu 或者可以注册宝塔账号 1 快速部署 安装docker 之后 2 需要在usr/bin下下载do…

5 分钟复刻你的声音,一键实现 GPT-Sovits 模型部署

想象一下&#xff0c;只需简单几步操作&#xff0c;就能生成逼真的语音效果&#xff0c;无论是为客户服务还是为游戏角色配音&#xff0c;都能轻松实现。GPT-Sovits 模型&#xff0c;其高效的语音生成能力为实现自然、流畅的语音交互提供了强有力的技术支持。本文将详细介绍如何…

C++实现设计模式---迭代器模式 (Iterator)

迭代器模式 (Iterator) 迭代器模式 是一种行为型设计模式&#xff0c;它提供了一种方法&#xff0c;顺序访问一个聚合对象中的各个元素&#xff0c;而又不需要暴露该对象的内部表示。 意图 提供一种方法&#xff0c;可以顺序访问一个容器对象中的元素&#xff0c;而无需暴露其…

MyBatis缓存原理及插件实现

目录 MyBatis缓存原理 缓存的工作机制 一级缓存&#xff1a; 二级缓存&#xff1a; MyBatis插件实现 MyBatis缓存原理 缓存的工作机制 如果会话查询了一条数据&#xff0c;此数据会存入一级缓存&#xff1b;若会话被关闭或提交&#xff0c;则&#xff0c;其数据转存入二级缓…

Nacos: 一个动态服务发现与配置管理平台

Nacos: 一个动态服务发现与配置管理平台 引言 在微服务架构日益普及的今天&#xff0c;服务之间的调用和配置管理变得越来越复杂。为了简化这一过程并提高开发效率&#xff0c;阿里巴巴推出了Nacos——一个易于使用的动态服务发现、配置管理和服务管理平台。 Nacos是什么&am…

C#图表性能的巅峰之选:LightningChart®.NET

C#图表性能的巅峰之选&#xff1a;LightningChart.NET 引言 在现代数据可视化中&#xff0c;性能是选择图表控件的关键因素。无论是实时数据监控、海量数据分析还是复杂 3D 可视化&#xff0c;LightningChart.NET 都以其卓越的性能成为市场上的佼佼者。 本文将深入探讨 Ligh…

渗透笔记1

第一天 工具&#xff1a;cs cobalt strike 4.9 / msf kali &#xff08;自带 Ubuntu&#xff09; cs cobalt strike 4.9&#xff1a;server-client server部署在云服务器上&#xff0c;client分别在各地&#xff0c;与server相连接&#xff1b;连接上后就可以共享上线主机。…