商品图片放大效果实现指南
本文摘要
本文介绍了实现商品图片放大镜效果的HTML/CSS/JavaScript方案。通过左右两个等比例容器,左侧显示原图并添加半透明遮罩层(mask),右侧显示放大图。当鼠标在左侧移动时,mask跟随鼠标位置,右侧图片相应移动展示放大区域。主要技术点包括:
1)使用transform使mask中心对准鼠标;
2)计算边界范围防止mask溢出;
3)通过坐标转换实现放大图同步移动。
该方案利用事件监听和CSS定位,实现了电商网站常见的商品细节展示功能。
在电商网站中,常见一种交互效果:当鼠标悬停在商品主图上时,右侧会同步显示放大后的商品细节。实现这一效果需要三个核心元素:
-
两个等比例的1:1矩形框,分别位于页面左右两侧
-
左侧矩形框中嵌套一个较小的矩形框(用于鼠标追踪)
-
一张1:1比例的商品图片作为展示内容
当用户在左侧商品图中移动浅色追踪框时,右侧展示区域会自动同步显示对应的放大细节。
1.图片交互效果说明
1.1HTML结构
-
左侧图片容器:
leftbox
-
右侧图片容器:
rightbox
-
遮罩层:
mask
(浅色矩形)
1.2交互逻辑
-
鼠标移入事件
-
为
leftbox
添加mouseover
事件 -
触发时,将
mask
的display
属性从none
改为block
-
-
遮罩跟随鼠标
-
为
mask
绑定mousemove
事件 -
计算
mask
位置:-
left = pageX - leftbox.clientWidth
-
top = pageY - leftbox.clientHeight
-
-
-
边界处理
-
左侧/顶部边界:
-
当
left
或top
小于mask
宽度一半时,设为0
-
-
右侧/底部边界:
-
当
left + mask宽度/2 > leftbox宽度
时,left = leftbox宽度 - mask宽度/2
-
当
top + mask宽度/2 > leftbox高度
时,top = leftbox高度 - mask宽度/2
-
-
-
右侧图片联动
-
计算缩放比例:
rightbox高度 / mask高度
-
rightbox
图片移动量:-
left = -mask.left * 缩放比例
-
top = -mask.top * 缩放比例
-
-
2.实现
2.1HTML
-
container:作为外层容器,可能通过 CSS 控制整体布局。
-
left-box:左侧区域,包含遮罩层和商品图片,可能用于展示商品缩略图或触发交互效果。mask:遮罩层,通常通过 CSS 设置半透明背景或 hover 效果。
-
goods:左侧商品图片,可能与右侧大图是同一张图片的不同尺寸。
-
right-box:右侧区域,展示大尺寸商品图片,可能用于细节预览。
<body>
<div class="container">
<div class="left-box box">
<div class="mask"></div>
<img class="goods" src="goods.jpg">
</div>
<div class="right-box box">
<img class='big' src="goods.jpg">
</div>
</div>
</body>
2.2CSS
通过为 div.box
设置 overflow: hidden
属性,可以隐藏元素超出边界的内容。同时,对 div.mask
应用 transform: translate(-50%, -50%)
样式,能够使遮罩层向上和向左各偏移自身宽度的一半,从而实现遮罩中心始终跟随鼠标位置的效果。
*{
margin: 0;
padding: 0;
}
div.container{
width: 100%;
height: 100vh;
display: flex;
flex-direction: row;
gap: 20px;
justify-content: center;
align-items: center;
}
div.box{
position: relative;
width: 600px;
height: 600px;
border: 1px solid black;
overflow: hidden;
}
img.goods{
height: 600px;
}
img.big{
position: relative;
height: 1200px;
}
div.mask{
display: none;
position: absolute;
width: 300px;
height: 300px;
background-color: rgba(213, 224, 112, 0.5);
z-index: 1;
transform: translate(-50%,-50%);
cursor: move;
}
2.3JavaScript
倍数由mask和box的大小计算。
//获取dom元素
const doms={
mask:document.querySelector('.mask'),
leftbox:document.querySelector('.left-box'),
rightbox:document.querySelector('.right-box'),
bigimg:document.querySelector('.big')
}
//左侧box位置计算
let offsetTop=doms.leftbox.offsetTop;
let offsetLeft=doms.leftbox.offsetLeft;
//事件监听
doms.leftbox.addEventListener('mouseover',over)
doms.leftbox.addEventListener('mouseout',function(){
doms.leftboxremoveEventListener('mousemove',move);
doms.mask.removeEventListener('mousemove',over);
doms.mask.style.display='none';
})
//鼠标进入,mask显示,为mask添加鼠标移动事件
function over(){
doms.mask.style.display='block';
doms.mask.addEventListener('mousemove',move);
}
//鼠标移动,mask移动,图片移动
function move(e){
const {pageX,pageY}=e;
//计算mask的top和left值
let x=pageX-offsetLeft;
let y=pageY-offsetTop;
//移动范围限制
let range={
left:doms.mask.clientWidth/2,
right:doms.leftbox.clientWidth-doms.mask.clientWidth/2,
top:doms.mask.clientHeight/2,
bottom:doms.leftbox.clientHeight-doms.mask.clientHeight/2
}
if(x<range.left){x=range.left}
if(x>range.right){x=range.right}
if(y<range.top){y=range.top}
if(y>range.bottom){y=range.bottom}
//修改样式
doms.mask.style.left=x+'px';
doms.mask.style.top=y+'px';
doms.bigimg.style.left=-2*(x-doms.mask.clientWidth/2)+'px';
doms.bigimg.style.top=-2*(y-doms.mask.clientHeight/2)+'px';
}
2.4最终效果
3.完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
div.container{
width: 100%;
height: 100vh;
display: flex;
flex-direction: row;
gap: 20px;
justify-content: center;
align-items: center;
}
div.box{
position: relative;
width: 600px;
height: 600px;
border: 1px solid black;
overflow: hidden;
}
img.goods{
height: 600px;
}
img.big{
position: relative;
height: 1200px;
}
div.mask{
display: none;
position: absolute;
width: 300px;
height: 300px;
background-color: rgba(213, 224, 112, 0.5);
z-index: 1;
transform: translate(-50%,-50%);
cursor: move;
}
</style>
</head>
<body>
<div class="container">
<div class="left-box box">
<div class="mask"></div>
<img class="goods" src="good.jpg" alt="">
</div>
<div class="right-box box">
<img class='big' src="good.jpg" alt="">
</div>
</div>
</div>
<script>
//获取dom元素
const doms={
mask:document.querySelector('.mask'),
leftbox:document.querySelector('.left-box'),
rightbox:document.querySelector('.right-box'),
bigimg:document.querySelector('.big')
}
//左侧box位置计算
let offsetTop=doms.leftbox.offsetTop;
let offsetLeft=doms.leftbox.offsetLeft;
//事件监听
doms.leftbox.addEventListener('mouseover',over)
doms.leftbox.addEventListener('mouseout',function(){
doms.leftboxremoveEventListener('mousemove',move);
doms.mask.removeEventListener('mousemove',over);
doms.mask.style.display='none';
})
//鼠标进入,mask显示,为mask添加鼠标移动事件
function over(){
doms.mask.style.display='block';
doms.mask.addEventListener('mousemove',move);
}
//鼠标移动,mask移动,图片移动
function move(e){
const {pageX,pageY}=e;
//计算mask的top和left值
let x=pageX-offsetLeft;
let y=pageY-offsetTop;
//移动范围限制
let range={
left:doms.mask.clientWidth/2,
right:doms.leftbox.clientWidth-doms.mask.clientWidth/2,
top:doms.mask.clientHeight/2,
bottom:doms.leftbox.clientHeight-doms.mask.clientHeight/2
}
if(x<range.left){x=range.left}
if(x>range.right){x=range.right}
if(y<range.top){y=range.top}
if(y>range.bottom){y=range.bottom}
//修改样式
doms.mask.style.left=x+'px';
doms.mask.style.top=y+'px';
doms.bigimg.style.left=-2*(x-doms.mask.clientWidth/2)+'px';
doms.bigimg.style.top=-2*(y-doms.mask.clientHeight/2)+'px';
}
</script>
</body>
</html>