Exploring the Magnifying Glass Newspaper Effect with HTML, SCSS, and JavaScript
Have you ever wanted to create a unique and captivating way to explore content on the web? The Magnifying Glass Newspaper effect provides an interesting and interactive experience, reminiscent of examining a newspaper through a magnifying glass. In this article, we'll break down the code that powers this effect, exploring the HTML, SCSS (Sass), and JavaScript components that come together to create this visually engaging feature.
HTML Structure
The HTML structure is relatively straightforward, comprising a container with three nested div elements: viewer, paper, and glass. These elements serve as the foundation for the entire effect.
<div id="viewer" class="viewer">
<div id="paper" class="paper"></div>
<div id="glass" class="glass"></div>
</div>
Styling with SCSS
The SCSS (Sass) code enhances the visual appeal of the Magnifying Glass Newspaper effect. It defines the dimensions, positioning, and styles of the viewer, paper, and glass elements. Notable features include the use of a linear gradient for the background, a newspaper texture for the paper, and a dynamic glass element with a subtle shadow.
html, body {
height: 100%;
}
body {
background-image: linear-gradient(45deg, grey 0% lightgray 100%);
background-color: black;
display: flex;
justify-content: center;
align-items: center;
}
.viewer {
width: 800px;
height: 520px;
border: 1px solid rgba(black, 0.1);
position: relative;
overflow: hidden;
box-shadow: 0 0 24px rgba(black, 0.13);
.paper {
width: 100%;
height: 205%;
background: url(https://assets.codepen.io/439000/newspaper_texture2832.webp);
background-size: 800px auto;
// opacity: 0.2;
}
$glass_radius: 32px;
.glass {
position: absolute;
top: 0;
left: 0;
width: 360px;
height: 190px;
border-radius: $glass_radius;
background: url(https://assets.codepen.io/439000/newspaper_texture2832.webp);
background-size: 1600px 2132px;
pointer-events: none;
box-shadow: inset -20px 20px 40px rgba(white, 0.4),
inset 20px -20px 40px rgba(black, 0.2);
opacity: 0.95;
&::before,
&::after {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
content: "";
border-radius: $glass_radius;
}
&::before {
box-shadow: -6px 4px 4px rgba(black, 0.23);
}
&::after {
// background-image: linear-gradient(21deg, transparent 50%, rgba(white, 0.3) 60%)
background-image: url(https://assets.codepen.io/439000/dirty-window-texture-11.webp);
background-size: cover;
mix-blend-mode: soft-light;
opacity: 0.9;
}
}
}
Js (Babel)
const normalize = (va, mi, ma) => (va - mi) / (ma - mi),
interpolate = (no, mi, ma) => mi + (ma - mi) * no,
map = (va, mi1, ma1, mi2, ma2) => interpolate(normalize(va, mi1, ma1), mi2, ma2),
viewer = document.getElementById("viewer"),
paper = document.getElementById("paper"),
glass = document.getElementById("glass"),
offset = 50, // dragging calculated with an edge to make it feel more comfortable
smoothFactor = .28, // x and y are not directly set, but with a tendency towards that target (tx, ty)
STATUS_IDLE = 1, // idle
STATUS_DRAG = 2, // dragging
STATUS_FADE = 3; // post dragging
let glassPos = { x: 0, y: 0, tx: 0, ty: 0 },
glassBackPos = { x: 0, y: 0, tx: 0, ty: 0 },
paperPos = { x: 0, y: 0, tx: 0, ty: 0 },
status = STATUS_IDLE;
const touchstart = (e) => {
if (status === STATUS_DRAG) return;
status = STATUS_DRAG;
if (!glass.classList.contains("active")) glass.classList.add("active");
};
const touchmove = (e) => {
if (status !== STATUS_DRAG) return;
e.preventDefault();
const cx = e.type == 'touchmove' ? e.touches[0].clientX : e.clientX,
cy = e.type == 'touchmove' ? e.touches[0].clientY : e.clientY,
rect = viewer.getBoundingClientRect(),
x = Math.min(viewer.clientWidth - offset, Math.max(offset, Math.min(viewer.clientWidth, cx - rect.left))),
y = Math.min(viewer.clientHeight - offset, Math.max(offset, Math.min(viewer.clientHeight, cy - rect.top))),
normX = normalize(x, offset, viewer.clientWidth - offset),
normY = normalize(y, offset, viewer.clientHeight - offset),
diffX = paper.clientWidth - viewer.clientWidth,
diffY = paper.clientHeight - viewer.clientHeight;
glassPos.tx = interpolate(normX, 0, viewer.clientWidth - glass.clientWidth);
glassPos.ty =interpolate(normY, 0, viewer.clientHeight - glass.clientHeight);
paperPos.tx = interpolate(normX, 0, diffX);
paperPos.ty =interpolate(normY, 0, diffY);
glassBackPos.tx = interpolate(normX, 0, 100);
glassBackPos.ty = interpolate(normY, 0, 100);
};
const touchend = () => {
if (status !== STATUS_DRAG) return;
status = STATUS_FADE;
if (glass.classList.contains("active")) glass.classList.remove("active");
// console.log("touchend");
};
const magnify = (() => {})();
viewer.addEventListener("touchstart", touchstart);
viewer.addEventListener("touchmove", touchmove);
viewer.addEventListener("touchend", touchend);
viewer.addEventListener("touchcancel", touchend);
viewer.addEventListener("mousedown", touchstart);
viewer.addEventListener("mousemove", touchmove);
viewer.addEventListener("mouseup", touchend);
(function tick() {
// repeat
requestAnimationFrame(tick);
// nothing on idle
if (status === STATUS_IDLE) return;
// return to idle when smoothing out is at its end
if (status === STATUS_FADE && Math.abs(glassPos.tx - glassPos.x) < 0.2) status = STATUS_IDLE;
// smooth motion towards targets
paperPos.x += smoothFactor * (paperPos.tx - paperPos.x);
paperPos.y += smoothFactor * (paperPos.ty - paperPos.y);
glassPos.x += smoothFactor * (glassPos.tx - glassPos.x);
glassPos.y += smoothFactor * (glassPos.ty - glassPos.y);
glassBackPos.x += smoothFactor * (glassBackPos.tx - glassBackPos.x);
glassBackPos.y += smoothFactor * (glassBackPos.ty - glassBackPos.y);
// transformations
paper.style.transform = `translate(${-paperPos.x}px, ${-paperPos.y}px)`;
glass.style.transform = `translate(${glassPos.x}px, ${glassPos.y}px)`;
glass.style.backgroundPosition = `${glassBackPos.x}% ${glassBackPos.y}%`;
})();
Live Preview
See the Pen Magnifying Glass Newspaper by Codewithshobhit (@Codewithshobhit) on CodePen.
Conclusion
Combining HTML, SCSS, and JavaScript, the Magnifying Glass Newspaper effect offers a delightful and interactive way to engage users with content. The code provided serves as a foundation for customization, allowing developers to adapt and expand upon this unique feature. Feel free to experiment with different textures, sizes, or additional visual elements to make this effect your own!

No comments:
Post a Comment