Detailed explanation CSS3 + JS perfectly realizes the magnifying glass mode

Time:2021-12-26

I wrote an article about more than a year ago:Analysis of several ways and principles of imitating magnifying glass effectAt that time, I felt that my technology was OK and floating, so I made such a bull roaring title. In fact, it only introduced the two animation methods of transform and animation in CSS – of course, the effect is also very simple… Ashamed.

Although later, with the growth of technology, we gradually realized the magnifying glass in canvas mode and another “Taobao” model in pure JS, it is still unsatisfactory: because the implementation is too complex and depends on most JS logic, the effects of movement and display depend on JS, and the offset is calculated through JS before rendering the style.

But the emergence of CSS3 custom variables let me see the “light of hope”!

First look at the effect:

css3+js实现放大镜

Its implementation core:

  • CSS functions, such as:calc()——Dynamic calculation;var()——Use custom variables
  • CSS pseudo element:::before/after——It is easy to control, independent of document flow, and easy to render
  • JS API:offsetX/offsetY: positioning relative to the upper left corner of the parent node area

In fact, what we want to achieve is: when the mouse moves in, a small circle will be displayed (follow the mouse). Where the small circle goes, the picture area 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 up offset of the mouse in real time, and these two offsets are relative to the parent node. By combining the left offset and the up offsetcalc()You can calculate the display position of the magnifying glass display content relative to the parent node.
It is not difficult to find. In the mouse event object, JS provides us with the following API:

  • screenX/screenY: locate relative to the upper left corner of the screen area. If scrolling occurs, locate relative to this area
  • pageX/pageY: positioning relative to the upper left corner of the web page area
  • clientX/clientY: positioning relative to the upper left corner of the browser viewing area
  • offsetX/offsetY: relative to the upper left corner of the parent node area. If there is no parent node, it is relative<html>or<body>location

But in comparison, the only thing 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=>{
	//Controls the movement of the mirror small circle
});

In fact, the content displayed by the magnifying glass is to enlarge the original image n times, and intercept the display content of a certain area in proportion through the above offset.

First define the relevant CSS variables. If we set the magnification to 2.5 times, the width and height of the enlarged image is also 2.5 times of the original width and height. Declare two variables, divided into--xand--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 in the form of background picture, which is convenient to control the size.

Obviously, in this scenario, there is no need to insert child nodes as the container of the magnifying glass::beforeJust!

The width and height of the magnifying glass is 100px when in use and 0 when not in use. By absolutely positioning the position where the layout magnifying glass moves with the mouse, i.e. declare left and top, and thentransform:translate(-50%,-50%)Place the magnifying glass so that the center of the magnifying glass is consistent with the position of the mouse cursor. Since you declare the position of the left and top positioning magnifier, you can also declarewill-changeImprove the performance problems caused by changes in left and top!
And another advantage of using CSS to solve these problems is that with the help of pseudo elements / pseudo classes, we can solve some more detailed things with CSS instead of relying on “heavy” JavaScript. For example, move the mouse into 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 realize (display) the contents of the magnifying glass. According to the magnification of 2.5 times, you can declare size:--outbox-w --outbox-h, you can move the background through position-x and position-y, and finally write itBackground: #333 URL (background picture) no repeat var (- - scale-x) var (- - scale-y) / var (- - outbox-w) var (- - outbox-h)
Where — scale-x and — scale-y correspond to position-x and position-y (i.ebackground-position)To change the position of the background 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 can be changed in the MouseMove function above:


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::beforeIf you want to use a picture that is twice the size itself in background--outbox-wand--outbox-hReplace with the original--box-wand--box-hThen make appropriate fine adjustment.

Pay attention to the content in your magnifying glass. It shows that it is not just a simple enlargement of the picture, so it isvar(--size) / var(--ratio)This code;
About modifying CSS3 custom variables in CSS: I still think it can only be modified and displayed successfully within the range of “same sibling”.

This is the end of this article about explaining the perfect implementation of the magnifying glass mode of CSS3 + JS. For more information about CSS3 + JS magnifying glass, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!

Recommended Today

Why is reids fast

1. What is redis? Redis is completely open source and complies with the BSD protocol. It is a high-performance key value database. Redis is also one of the most popular NoSQL databases at present. It contains a variety of data structures, supports network, is memory based, and has an optional key value pair storage database […]