详解CSS3+JS完美实现放大镜模式


Posted in HTML / CSS onDecember 03, 2020

大概一年多之前写过一篇文章:仿放大镜效果的几种方式原理解析,当时觉得自己技术可以了、飘了,于是就起了这样牛气哄哄的标题,其实也只算是介绍了css里的transform和animation两种动画方式 —— 当然,实现的效果也是巨简单的那种…惭愧。

虽然后来随着技术的增长又逐渐实现了canvas方式的放大镜以及用纯JS实现了另一种“淘宝式”的模型,但是仍然不尽人意:因为实现起来太复杂了,而且需依赖大部分JS逻辑,移动和显示的效果均依赖JS,通过JS计算偏移量再渲染样式。

但是CSS3自定义变量的出现让我看到了“希望之光”!

先看效果:

详解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:相对父节点区域左上角定位,若无父节点则相对<html><body>定位

但相较而言唯一符合要求的就只有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));

那么上面mousemove函数中改变镜子的“位置坐标”就可以这么写了:

e.target.style.setProperty("--x",`${e.offsetX}px`);
e.target.style.setProperty("--y",`${e.offsetY}px`);

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自定义变量:我仍然认为只能在“同级同属”范围内才能修改并显示成功。

到此这篇关于详解CSS3+JS完美实现放大镜模式的文章就介绍到这了,更多相关CSS3+JS放大镜内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章,希望大家以后多多支持三水点靠木!

HTML / CSS 相关文章推荐
使用简单的CSS3属性实现炫酷读者墙效果
Jan 08 HTML / CSS
CSS+jQuery+PHP+MySQL实现的在线答题功能
Apr 25 HTML / CSS
CSS3的first-child选择器实战攻略
Apr 28 HTML / CSS
HTML5上传文件显示进度的实现代码
Aug 30 HTML / CSS
HTML5 通信API 跨域门槛将不再高、数据推送也不再是梦
Apr 25 HTML / CSS
HTML5 history新特性pushState、replaceState及两者的区别
Dec 26 HTML / CSS
详解如何通过H5(浏览器/WebView/其他)唤起本地app
Dec 11 HTML / CSS
Html5页面中的返回实现的方法
Feb 26 HTML / CSS
html2canvas生成清晰的图片实现打印的示例代码
Sep 30 HTML / CSS
CSS 实现Chrome标签栏的技巧
Aug 04 HTML / CSS
CSS实现五种常用的2D转换
Dec 06 HTML / CSS
css3 文字断裂效果
Apr 22 HTML / CSS
css3中仿放大镜效果的几种方式原理解析
Dec 03 #HTML / CSS
CSS3 实现飘动的云朵动画
Dec 01 #HTML / CSS
CSS3 filter(滤镜)实现网页灰色或者黑色模式的代码
Nov 30 #HTML / CSS
CSS3 实现时间轴动画
Nov 25 #HTML / CSS
纯CSS3实现的井字棋游戏
Nov 25 #HTML / CSS
HTML+CSS3+JS 实现的下拉菜单
Nov 25 #HTML / CSS
CSS3 实现倒计时效果
Nov 25 #HTML / CSS
You might like
PHP生成迅雷、快车、旋风等软件的下载链接代码实例
2014/05/12 PHP
浅析PHP程序设计中的MVC编程思想
2014/07/28 PHP
php判断两个浮点数是否相等的方法
2015/03/14 PHP
Yii净化器CHtmlPurifier用法示例(过滤不良代码)
2016/07/15 PHP
parseInt parseFloat js字符串转换数字
2010/08/01 Javascript
javascript的propertyIsEnumerable()方法使用介绍
2014/04/09 Javascript
AngularJS语法详解(续)
2015/01/23 Javascript
基于jQuery实现放大镜特效
2020/10/19 Javascript
仿iframe效果Aajx文件上传实例
2016/11/18 Javascript
微信小程序中子页面向父页面传值实例详解
2017/03/20 Javascript
bootstrap treeview 扩展addNode方法动态添加子节点的方法
2017/11/21 Javascript
LayUi中接口传数据成功,表格不显示数据的解决方法
2018/08/19 Javascript
JavaScript数组常用的增删改查与其他属性详解
2020/10/13 Javascript
Vue实现todo应用的示例
2021/02/20 Vue.js
[51:53]完美世界DOTA2联赛循环赛 LBZS vs DM BO2第二场 11.01
2020/11/02 DOTA
Python网络爬虫项目:内容提取器的定义
2016/10/25 Python
python 函数传参之传值还是传引用的分析
2017/09/07 Python
pandas数据清洗,排序,索引设置,数据选取方法
2018/05/18 Python
Python多线程应用于自动化测试操作示例
2018/12/06 Python
解决tensorflow训练时内存持续增加并占满的问题
2020/01/19 Python
python3.6连接mysql数据库及增删改查操作详解
2020/02/10 Python
python db类用法说明
2020/07/07 Python
matplotlib subplot绘制多个子图的方法示例
2020/07/28 Python
Django haystack实现全文搜索代码示例
2020/11/28 Python
python3.9.1环境安装的方法(图文)
2021/02/02 Python
印尼穆斯林时尚购物网站:Hijabenka
2016/12/10 全球购物
BNKR中国官网:带你感受澳洲领先潮流时尚
2018/08/21 全球购物
IGK Hair官网:喷雾、洗发水、护发素等
2020/11/03 全球购物
应届生会计电算化求职信
2013/10/03 职场文书
承诺书格式范文
2014/06/03 职场文书
2014年学校禁毒工作总结
2014/12/23 职场文书
2016秋季田径运动会广播稿
2015/12/21 职场文书
分析MySQL抛出异常的几种常见解决方式
2021/05/18 MySQL
MySQL 亿级数据导入导出及迁移笔记
2021/06/18 MySQL
教你部署vue项目到docker
2022/04/05 Vue.js
JS前端canvas交互实现拖拽旋转及缩放示例
2022/08/05 Javascript