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

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

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


先看效果:

其实现核心:

  • 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完美实现放大镜模式相关推荐

  1. HTML5,CSS3,js

    HTML5,CSS3,js html5 html基本结构 块级标签和行级标签 html5表格 html5表单 css3 css使用方法 css常用属性 css3的过渡和变换 css3的动画属性和多列属 ...

  2. 2023年最全前端面试题考点HTML5+CSS3+JS

    合集:2023年最全前端面试题考点HTML5+CSS3+JS+Vue3+React18+八股文+手写+项目+笔试_参宿7的博客-CSDN博客 本章内容为一面基础面 为了简洁,相关文章参考链接在标题里 ...

  3. 临摹中国慕课静态网页第二周周记(CSS3+JS)

    临摹中国慕课静态网页第二周周记(CSS3+JS) 第二周 这周主要是对细节,轮播图,下拉菜单等地完善和JS的学习 学习内容 (1)CSS word-break 属性 属性规定自动换行的处理方法. 语法 ...

  4. 登录页面html5 css3 js代码,H5+css3+js搭建带验证码的登录页面

    本文实例为大家分享了H5+css3+js搭建带验证码的登录页面,供大家参考,具体内容如下 login.html EasyBuy后台管理系统 .main_bar{ width:1350px; heigh ...

  5. Vue.js的IoC容器模式探索

    IoC概念阐述 IoC(Inversion of Control),意为控制反转,不是什么技术,而是一种设计思想.==Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制==. ...

  6. js完美转换阿拉伯数字为数字大写

    js将阿拉伯数组转换为中文数字 文章摘自:  js完美转换阿拉伯数字为数字大写(原创) 直接上代码: //阿拉伯数字转换为简写汉字 function Arabia_To_SimplifiedChine ...

  7. ❤女朋友生日❤ HTML+css3+js 实现抖音炫酷樱花3D相册 (含背景音乐)程序员表白必备

    一年一度的/520/七夕情人节/女朋友生日/程序员表白,是不是要给女朋友或者正在追求的妹子一点小惊喜呢,今天这篇博客就分享下前端代码如何实现3D立体动态相册.赶紧学会了,来制作属于我们程序员的浪漫吧! ...

  8. 利用HTML5+CSS3+JS实现简单的钟表

    HTML5+CSS3+JS实现动态时钟 利用HTML5+CSS3+JS实现简单的钟表,仅供参考学习 效果图: 在线效果预览 思路: 1. 先定义一个类名为timepiece的圆表表盘 HTML: &l ...

  9. HTML生日快乐代码 (粉色主题)(HTML5+CSS3+JS)520表白代码/七夕情人节网页/告白/求婚/生日快乐

    html+css+js 生日快乐网站模板(多页面功能版本+音乐)❤520/表白/七夕情人节/求婚❤专用炫酷动画网页的源代码(HTML5+CSS3+JS) 程序员爱情❤520/表白/七夕情人节/求婚❤专 ...

最新文章

  1. 皮一皮:碰到这样的领导怎么办...
  2. React Native系列(6) - 编译安卓私有React-Native代码
  3. hdu 6168 Numbers
  4. BZOJ #3064. Tyvj 1518 CPU监控(线段树,历史最值)
  5. Tomcat 使用apr优化
  6. 618哪家空调最受欢迎?格力奥克斯互撕 友商却笑到最后
  7. 【Elasticsearch】all shards failed no shard available for get .xxx[doc] routing null
  8. [恢]hdu 2040
  9. Type Dynamic Web Module 4.0 requires Java 1.8 or newer----彻底杀死Bug
  10. [转载] python迭代器
  11. CCNP精粹系列之三----OSPF(open short path first)
  12. MIT操作系统实验-XV6项目环境搭建
  13. 基于单片机的人体心率脉搏检测系统
  14. mysql新闻管理系统表_《新闻管理系统》数据库设计_参考答案.doc
  15. 网站服务器会把手机拉黑吗,怎么知道对方手机把我拉黑了
  16. 会计信息质量可靠性的案例_浅谈会计信息可靠性(一)
  17. [附源码]java毕业设计学校缴费系统
  18. 084 php获取美元人民币汇率方法
  19. ddr3和ddr4区别
  20. 华为ap3010转胖ap

热门文章

  1. HLOJ 1562* 手指游戏
  2. 王兴在这个被互联网遗忘的网站上,留下了一万多条碎碎念。
  3. 计算机接口电路的种类,接口电路的分类_接口电路的功能_接口电路的作用是什么...
  4. spring常见漏洞总结
  5. 并发编程之深入理解十三:CompletionService CompletableFuture
  6. FODM8061半距微型扁平逻辑兼容的高速光电耦合器
  7. 华为云主机怎么样?华为云弹性云服务器有什么优势?
  8. 网络对抗 Exp2.1 后门原理与实践 20154311 王卓然
  9. PG-REINFORCE tensorflow 2.0
  10. 干货 :深度学习的主流模型及应用