Detailed explanation of CSS3+JS perfect implementation of magnifying glass mode

Detailed explanation of CSS3+JS perfect implementation of magnifying glass mode

About a year ago, I wrote an article: Analysis of the principles of several ways to imitate the magnifying glass effect. At that time, I felt that my skills were good enough and I was proud of it, so I gave it such a boastful title. In fact, it only introduced two animation methods in CSS: transform and animation. Of course, the effect achieved was also very simple... I am ashamed.

Although with the advancement of technology, we gradually realized a canvas magnifying glass and another "Taobao-style" model using pure JS, it was still unsatisfactory: because the implementation was too complicated and relied on most of the JS logic. The movement and display effects all relied on JS, and the offset was calculated through JS and then the style was rendered.

But the emergence of CSS3 custom variables has given me hope!

First look at the effect:

CSS3+JS implementation of magnifying glass

Its core implementation:

  • CSS functions, such as: calc() - dynamic calculation; var() - use custom variables
  • CSS pseudo-elements: ::before/after — easy to control, independent of the document flow, and easy to render
  • JS API: offsetX/offsetY : Position relative to the upper left corner of the parent node area

In fact, what we want to achieve specifically is: when the mouse moves in, a small circle is displayed (following the mouse), and wherever this small circle goes, the image area there will be enlarged by the corresponding multiple and displayed in the circle.

Why use the offset API?
In fact, according to the above description, we need to obtain the left offset and top offset of the mouse in real time, and these two offsets are relative to the parent node. The display position of the magnifying glass content relative to the parent node can be calculated by combining the left offset and the top offset with calc() .
It is not difficult to find that in the mouse event object, js provides us with the following API:

  • screenX/screenY : Position relative to the upper left corner of the screen area. If scrolling occurs, position relative to this area.
  • pageX/pageY : Position relative to the upper left corner of the web page area
  • clientX/clientY : Position relative to the upper left corner of the browser's visible area
  • offsetX/offsetY : Position relative to the upper left corner of the parent node area. If there is no parent node, position relative to <html> or <body>

But by comparison, the only one that meets the requirements is offset "relative to the parent element".

<div class="bruce">
    <div class="magnifier"></div>
</div>
let magnifier = document.querySelector(".magnifier");
magnifier.addEventListener("mousemove",e=>{
	//Control the movement of the small circle of the "mirror"});

The magnifying glass displays the content by magnifying the original image N times, and proportionally intercepting a certain area to display the content through the above offset.

First define the relevant css variables. We set the magnification to 2.5 times, so the width and height of the enlarged image will also be 2.5 times the original width and height. Declare two variables, divided into --x and --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;
}

The picture is displayed as a background image, which makes it easy to control the size.

Obviously, in this scenario, there is no need to insert a child node as a container for the magnifying glass. Just use ::before !

The magnifying glass is 100px wide and high when in use, and 0px wide and high when not in use. The position of the magnifying glass as the mouse moves is arranged through absolute positioning, that is, declaring left and top, and then filling the position of the magnifying glass by declaring transform:translate(-50%,-50%) so that the center of the magnifying glass is consistent with the position of the mouse cursor. Since left and top are declared to locate the position of the magnifying glass, will-change can also be declared to improve performance issues caused by changes in left and top!
Another benefit of using CSS to solve these problems is that with the help of pseudo-elements/pseudo-classes, we can use CSS to solve some of the more detailed things instead of relying on "heavy" JavaScript. For example: mouse enters the style 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;
}

Next, use background to implement (display) the magnifying glass content. According to the magnification of 2.5 times, you can declare size: --outbox-w --outbox-h , and move the background through position-x and position-y. Finally, you can write it as background:#333 url(背景圖片) no-repeat var(--scale-x) var(--scale-y)/var(--outbox-w) var(--outbox-h) .
Among them, --scale-x and --scale-y correspond to position-x and position-y (ie background-position ), which are used to change the background position as the mouse moves.

--scale-x: calc(var(--size) / var(--ratio) - var(--ratio) * var(--x));
--scale-y: calc(var(--size) / var(--ratio) - var(--ratio) * var(--y));

Then the "position coordinates" of the mirror in the mousemove function above can be written like this:

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

so eazy~

The final CSS content is as follows:

: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;
}

If you want to use an image that is twice the size in ::before , replace --outbox-w and --outbox-h with the original --box-w and --box-h in background and make appropriate adjustments.

Pay attention to the content in your magnifying glass, it shows that it is not just a simple enlargement of the image, so there is the var(--size) / var(--ratio) code;
Regarding modifying CSS3 custom variables in CSS: I still believe that it can only be modified and displayed successfully within the "same level and same belonging" scope.

This is the end of this article about how to perfectly implement the magnifying glass mode with CSS3+JS. For more relevant CSS3+JS magnifying glass content, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope you will support 123WORDPRESS.COM in the future!

<<:  Count the list tags in HTML

>>:  How to disable web page styles using Firefox's web developer

Recommend

...

html option disable select select disable option example

Copy code The code is as follows: <select> ...

How to build a Vue3 desktop application

In this article, we will look at how to develop a...

MySQL series 9 MySQL query cache and index

Table of contents Tutorial Series 1. MySQL Archit...

Detailed explanation of the use of Vue.js draggable text box component

Table of contents Registering Components Adding C...

Tips on disabling IE8 and IE9's compatibility view mode using HTML

Starting from IE 8, IE added a compatibility mode,...

MySQL learning database search statement DQL Xiaobai chapter

Table of contents 1. Simple retrieval of data 2. ...

In-depth explanation of JavaScript this keyword

Table of contents 1. Introduction 2. Understand t...

How to uninstall MySQL 5.7 on CentOS7

Check what is installed in mysql rpm -qa | grep -...

Java imports data from excel into mysql

Sometimes in our actual work, we need to import d...

Steps for IDEA to integrate Docker to achieve remote deployment

1. Enable remote access to the docker server Log ...