图片放大镜效果是前端开发中非常实用的交互效果,在CSS初级项目实战里,我们可以不依赖复杂的JavaScript逻辑,仅通过CSS的基础属性和伪元素就能实现完整的功能。该效果的核心逻辑是当鼠标悬停在目标图片上时,在图片旁边展示一个放大后的区域,并且放大区域的内容会跟随鼠标移动同步变化。

实现思路梳理
整个效果的实现可以分为三个核心部分:
- 搭建基础布局,包含原始图片容器和放大区域容器
- 通过伪元素实现放大镜的遮罩层,跟随鼠标移动
- 利用
transform属性实现图片的放大效果,并且让放大区域的内容和遮罩层位置对应
基础HTML结构
首先我们需要准备基础的HTML结构,包含原始图片和放大区域的容器:
<div class="magnifier-container">
<div class="origin-img">
<img src="https://picsum.photos/400/300?random=2" alt="原始展示图片">
</div>
<div class="magnified-area"></div>
</div>
核心CSS样式实现
容器基础样式
先给外层容器和原始图片设置基础样式,固定原始图片的尺寸,方便后续计算放大比例:
.magnifier-container {
position: relative;
width: 400px;
height: 300px;
}
.origin-img {
width: 100%;
height: 100%;
overflow: hidden;
cursor: crosshair;
}
.origin-img img {
width: 100%;
height: 100%;
object-fit: cover;
}
放大镜遮罩层实现
通过::after伪元素实现跟随鼠标的遮罩层,这里需要使用mousemove相关的CSS变量来动态计算位置,不过初级实现可以先通过固定遮罩尺寸,后续再优化跟随逻辑:
.origin-img::after {
content: '';
position: absolute;
width: 100px;
height: 100px;
background-color: rgba(255, 255, 255, 0.5);
border: 1px solid #ccc;
display: none;
pointer-events: none;
}
.origin-img:hover::after {
display: block;
}
放大区域样式与跟随逻辑
放大区域需要展示原始图片放大后的内容,这里我们使用background-image来承载放大后的图片,通过background-position来同步遮罩层的位置:
.magnified-area {
position: absolute;
left: 420px;
top: 0;
width: 300px;
height: 300px;
border: 1px solid #ccc;
background-image: url(https://picsum.photos/800/600?random=2);
background-size: 800px 600px;
background-position: 0 0;
display: none;
pointer-events: none;
}
.origin-img:hover + .magnified-area {
display: block;
}
鼠标跟随效果优化
如果需要实现遮罩层完全跟随鼠标移动,我们可以结合少量JavaScript来计算鼠标位置,不过如果是纯CSS初级练习,也可以先使用:hover配合transform的位移来模拟简单跟随:
.origin-img:hover::after {
display: block;
transform: translate(calc(var(--mouse-x, 0px) - 50px), calc(var(--mouse-y, 0px) - 50px));
}
配合简单的JS设置CSS变量即可实现完整跟随:
const originImg = document.querySelector('.origin-img');
originImg.addEventListener('mousemove', (e) => {
const rect = originImg.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
originImg.style.setProperty('--mouse-x', x + 'px');
originImg.style.setProperty('--mouse-y', y + 'px');
// 同步放大区域的背景位置
const magnifiedArea = document.querySelector('.magnified-area');
const bgX = -(x * 2 - 50);
const bgY = -(y * 2 - 50);
magnifiedArea.style.backgroundPosition = `${bgX}px ${bgY}px`;
});
效果调整注意事项
在实际调整效果时,需要注意几个参数:
- 遮罩层的尺寸和放大区域的尺寸比例需要和图片放大比例匹配,比如遮罩层是100px,放大区域是300px,那么放大比例就是3倍
- 放大区域的
background-size需要是原始图片尺寸乘以放大比例,保证放大后的内容清晰 - 如果原始图片尺寸不固定,需要动态计算相关参数,避免放大区域出现空白或者内容溢出
完整可运行示例
以下是整合了所有逻辑的完整代码,可以直接复制到HTML文件中运行查看效果:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS图片放大镜效果</title>
<style>
.magnifier-container {
position: relative;
width: 400px;
height: 300px;
}
.origin-img {
width: 100%;
height: 100%;
overflow: hidden;
cursor: crosshair;
position: relative;
}
.origin-img img {
width: 100%;
height: 100%;
object-fit: cover;
}
.origin-img::after {
content: '';
position: absolute;
width: 100px;
height: 100px;
background-color: rgba(255, 255, 255, 0.5);
border: 1px solid #ccc;
display: none;
pointer-events: none;
}
.magnified-area {
position: absolute;
left: 420px;
top: 0;
width: 300px;
height: 300px;
border: 1px solid #ccc;
background-image: url(https://picsum.photos/800/600?random=2);
background-size: 800px 600px;
background-position: 0 0;
display: none;
pointer-events: none;
}
.origin-img:hover::after {
display: block;
}
.origin-img:hover + .magnified-area {
display: block;
}
</style>
</head>
<body>
<div class="magnifier-container">
<div class="origin-img" id="originImg">
<img src="https://picsum.photos/400/300?random=2" alt="原始展示图片">
</div>
<div class="magnified-area" id="magnifiedArea"></div>
</div>
<script>
const originImg = document.getElementById('originImg');
const magnifiedArea = document.getElementById('magnifiedArea');
const afterEl = window.getComputedStyle(originImg, '::after');
originImg.addEventListener('mousemove', (e) => {
const rect = originImg.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 限制遮罩层不超出图片范围
const clampX = Math.max(50, Math.min(x, 350));
const clampY = Math.max(50, Math.min(y, 250));
originImg.style.setProperty('--mouse-x', clampX + 'px');
originImg.style.setProperty('--mouse-y', clampY + 'px');
// 同步遮罩层位置
originImg.querySelector('img').style.setProperty('--ax', (clampX - 50) + 'px');
originImg.querySelector('img').style.setProperty('--ay', (clampY - 50) + 'px');
// 同步放大区域背景位置
const bgX = -(clampX * 2 - 50);
const bgY = -(clampY * 2 - 50);
magnifiedArea.style.backgroundPosition = `${bgX}px ${bgY}px`;
});
</script>
</body>
</html>