注意:
- 看懂本文需要:
- 懂中文 :)
- 学习过 JavaScript 和 css
- 代码较长,框框可左右滑动哦
- 您的观看和点赞是对本公众号最大力的支持 ~~
原文链接:
- https://blog.csdn.net/qq_43624878/article/details/110197749 CSS3+JS完美实现放大镜模式
效果

核心
- CSS函数,如:
calc()
—— 动态计算;var()
—— 使用自定义变量 - CSS伪元素:
::before/after
—— 方便控制,而且独立于文档流之外,易于渲染 - JS API:
offsetX/offsetY
:相对父节点区域左上角定位 - …
其实我们具体要实现的就是:在鼠标移入时显示出来一个小圆圈(跟着鼠标走),这个小圆圈到哪,哪里的图片区域就放大相应的倍数并且显示在圆圈内。
为什么要用offset API?其实根据上面的描述,我们需要实时获取鼠标的左偏移量和上偏移量,而这两个偏移量是相对父节点的。通过左偏移量和上偏移量结合
calc()
即可计算放大镜显示内容相对父节点的显示位置。不难找到在鼠标事件对象中,js为我们提供了如下API:
screenX/screenY
:相对屏幕区域左上角定位,若发生滚动行为,则相对该区域定位pageX/pageY
:相对网页区域左上角定位clientX/clientY
:相对浏览器可视区域左上角定位offsetX/offsetY
:相对父节点区域左上角定位,若无父节点则相对或
定位
但相较而言唯一符合要求的就只有offset“相对于父元素”了。
<div class="bruce">
<div class="magnifier">div>
div>
let magnifier=document.querySelector(".magnifier");
magnifier.addEventListener("mousemove",e=>{
//控制“镜子”小圆圈的移动
});
放大镜显示内容其实就是将原图像放大N倍,通过上述偏移量按照比例截取一定区域显示内容。
先定义相关的css变量。我们设定放大倍率为2.5倍,那么被放大图像的宽高也是原来宽高的2.5倍。声明两个变量,分为为 --x
和 --y
:
:root{
--ratio: 2.5;
--box-w: 600px;
--box-h: 400px;
--outbox-w: calc(var(--box-w) * var(--ratio));
--outbox-h: calc(var(--box-h) * var(--ratio));
}
.bruce{
margin-top: 50px;
}
.magnifier{
--x:0;
--y:0;
overflow: hidden;
position: relative;
width: var(--box-w);
height: var(--box-h);
background: url("img/nan.png") no-repeat center/100% 100%;
cursor: grabbing;
}
图片以背景图的形式展示,方便控制大小。
很显然在这个场景下无需插入子节点作为放大镜的容器了,使用::before
即可!
放大镜在使用时宽高为100px,不使用时宽高为0。通过绝对定位布局放大镜随鼠标移动的位置,即声明left和top,再通过声明 transform:translate(-50%,-50%)
将放大镜补位,使放大镜中心与鼠标光标位置一致。由于声明left和top定位放大镜的位置,还可以声明 will-change
改善left和top因改变而引发的性能问题!而且用CSS解决这些问题的另一个好处就是:借助于伪元素/伪类,我们可以将一些比较细节的东西用CSS解决,而不是寄托于“繁重”的JavaScript。比如:鼠标移入样式hover:
.magnifier::before{
--size: 0;
position: absolute;
left: var(--x);
top: var(--y);
border-radius: 100%;
width: var(--size);
height: var(--size);
box-shadow: 1px 1px 3px rgba(0,0,0,.5);
content: "";
will-change: left,top;
transform: translate(-50%,-50%);
}
.magnifier:hover::before{
--size: 100px;
}
接下来使用background实现(展示)放大镜内容。依据放大倍率为2.5倍,那么可声明size: --outbox-w --outbox-h
,通过 position-x 和 position-y 移动背景即可,最终可连写成 background:#333 url(背景图片) no-repeat var(--scale-x) var(--scale-y)/var(--outbox-w) var(--outbox-h)
。其中 --scale-x 和 --scale-y 对应 position-x 和 position-y (即background-position
),用于随着鼠标移动而改变背景位置。
--scale-x: calc(var(--size) / var(--ratio) - var(--ratio) * var(--x));
--scale-y: calc(var(--size) / var(--ratio) - var(--ratio) * var(--y));
12
那么上面mousemove函数中改变镜子的“位置坐标”就可以这么写了:
e.target.style.setProperty("--x",`${e.offsetX}px`);
e.target.style.setProperty("--y",`${e.offsetY}px`);
12
so eazy~
最终的CSS内容如下:
:root{
--ratio: 2.5;
--box-w: 600px;
--box-h: 400px;
--outbox-w: calc(var(--box-w) * var(--ratio));
--outbox-h: calc(var(--box-h) * var(--ratio));
}
.bruce{
margin-top: 50px;
}
.magnifier{
--x:0;
--y:0;
overflow: hidden;
position: relative;
width: var(--box-w);
height: var(--box-h);
background: url("img/nan.png") no-repeat center/100% 100%;
cursor: grabbing;
}
.magnifier::before{
--size: 0;
--scale-x: calc(var(--size) / var(--ratio) - var(--ratio) * var(--x));
--scale-y: calc(var(--size) / var(--ratio) - var(--ratio) * var(--y));
position: absolute;
left: var(--x);
top: var(--y);
border-radius: 100%;
width: var(--size);
height: var(--size);
background: #333 url("img/nan.png") no-repeat var(--scale-x) var(--scale-y)/var(--outbox-w) var(--outbox-h);
box-shadow: 1px 1px 3px rgba(0,0,0,.5);
content: "";
will-change: left,top;
transform: translate(-50%,-50%);
}
.magnifier:hover::before{
--size: 100px;
}
若是::before
中想要用一张本身就是2倍大小的图片,则background中将--outbox-w
和--outbox-h
替换为原本的--box-w
和--box-h
再做适当的微调即可。
!注意看你放大镜中的内容,它表明不只是简单的图片的放大,所以才有了
var(--size) / var(--ratio)
这一段代码;关于css中修改css3自定义变量:我仍然认为只能在“同级同属”范围内才能修改并显示成功。
完整代码
已加上注释,注意修改图片路径
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<style>:root {--ratio: 2.5; /* 放大倍率 */--box-w: 600px; /* 原始宽度 */--box-h: 400px; /* 原始高度 */--outbox-w: calc(var(--box-w) * var(--ratio)); /* 放大后宽度 */--outbox-h: calc(var(--box-h) * var(--ratio)); /* 放大后高度 */
}/* 调一下框框位置 */.bruce {margin-top: 50px;
}/* 界面 */.magnifier {--x: 0;--y: 0;overflow: hidden; /* 溢出隐藏边框的内容 */position: relative; /* 相对定位 */width: var(--box-w); /* 应用root定义的宽度 */height: var(--box-h); /* 应用root定义的高度 *//* 注意:如果同时设置了position和size两个属性,应该用左斜杠“/”,而不是用空格把两个参数值隔开:position/size */background: url("1.jpg") no-repeat center/100% 100%; /* 调整图片宽高,设置背景图片居中不重复显示 */cursor: grabbing; /* 定义鼠标形状为手势 */
}.magnifier::before {--size: 0;/* 原图和放大之后的图片比例做计算 */--scale-x: calc(var(--size) / var(--ratio) - var(--ratio) * var(--x)); /* 显示放大后图片的x轴 */--scale-y: calc(var(--size) / var(--ratio) - var(--ratio) * var(--y)); /* 显示放大后图片的y轴 *//* 绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于: */position: absolute;left: var(--x); /* 左距离 */top: var(--y); /* 顶距离 */border-radius: 100%; /* 设置为圆形 */width: var(--size); /* 设置放大镜宽度 */height: var(--size); /* 设置放大镜高度 */background: #333 url("1.jpg") no-repeat var(--scale-x) var(--scale-y)/var(--outbox-w) var(--outbox-h);/* 设置阴影 */box-shadow: 1px 1px 3px rgba(0, 0, 0, .5);content: ""; /* content属性一般用于:before, :after伪元素中,用于呈现伪元素的内容 */will-change: left, top; /* 性能优化 *//* 设置放大镜 xy向左偏移一半,因为放大镜本身是一个正方形 */transform: translate(-50%, -50%);
}.magnifier:hover::before {--size: 100px; /* 当选择鼠标指针浮动在其上的元素,调整样式 */
}style>
head>
<body>
<div class="bruce">
<div class="magnifier">div>
div>
<script>let magnifier = document.querySelector(".magnifier");// 添加鼠标移动事件的监听
magnifier.addEventListener("mousemove", e => {//控制“镜子”小圆圈的移动
e.target.style.setProperty("--x", `${e.offsetX}px`);
e.target.style.setProperty("--y", `${e.offsetY}px`);
});script>
body>
html>
end
您的观看和点赞是对本公众号最大力的支持 ~~