Skip to content
Advertisement

Zoom on Scroll Down & Scroll up the zoomed element when scale is more than full screen

I tried to make zoom in Zoom out on scroll. The element is zooming on scrolling but I want to make it(the zoomed element) go up once it reached the full width of the screen.

Here’s my code:

    <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style>
        .zoom{  
    height:100vh;  
    width:100%;  
    display:grid;  
    place-items:center;  
    position:fixed;  
    top:0;  
    left:0;
    background: url('img/bg.png');
}
.afterzoom{
height: 200vh;
background: red;
}
    </style>

</head>
<body>

<div class="zoom">  
    <!-- <h1>Zoom meeeee</h1> -->
    <img src="img/square.png" alt="">
</div>
<div class="afterzoom"></div>
<script>
    const zoomElement = document.querySelector(".zoom");
let zoom = 1;
const ZOOM_SPEED = 0.1;

document.addEventListener("wheel", function(e) {  
    
    if(e.deltaY > 0){    
        if (zoomElement.style.transform >= `scale(5)`) {
            console.log("now scroll down");
            return false;
        }
        zoomElement.style.transform = `scale(${zoom += ZOOM_SPEED})`;  

    }else{    
        if (zoomElement.style.transform == `scale(1)`) {
            // console.log("minus");
            return false;
        }
        zoomElement.style.transform = `scale(${zoom -= ZOOM_SPEED})`;  }

});

</script>
</body>
</html>

Fiddle: https://jsfiddle.net/mayureshpitale/6etpn0vs/3/

I am trying to make something like this: http://truegossiper.com/vilson17/

Advertisement

Answer

A bit of a different approach using the scroll event and window.scrollY for positioning together with requestAnimationFrame (RAF).

This also works, if the image (or other content) is not squared.

The problem with the wheel event is, that it does not trigger when the user uses the scrollbar or arrow keys to scroll the page.

The problem with the scroll event is, that it executes a lot… that’s why RAF is used, to only execute necessary zoom changes.


Keep in mind, this exact code works with the document width when the page is loaded. If the user resizes the window or changes the browsers zoom, the element will resize to the same scale as before. You could fix this with some extra code by using a ResizeObserver. (Remove the existing event listener, resize the Image and execute parts of the code again, every time the document is resized…)

You will notice this, when you try to view the below snippet as full page.

const zoomElement = document.querySelector('.zoom')
const fadeElement = document.querySelector('.fade')
const afterZoomElement = document.querySelector('.afterzoom')
const imgElement = document.querySelector('img')
const WIDTH = document.body.clientWidth
const HEIGHT = zoomElement.clientHeight
const IMAGE_WIDTH = imgElement.clientWidth
const IMAGE_HEIGHT = imgElement.clientHeight
const ZOOM_SPEED = 100 // Lower is faster
const ZOOM_BREAKPOINT = WIDTH / IMAGE_WIDTH // When it should stop zooming in
const IMAGE_HEIGHT_MAX = IMAGE_HEIGHT * ZOOM_BREAKPOINT
const ABSOLUTE = ZOOM_BREAKPOINT * ZOOM_SPEED // Absolute position, when the Element reached maximum size

// Fade --------------------------------------------------------------------------------------
const FADE_SPEED = 500 // Lower is faster
let fade = 1
let prev = 0
// -------------------------------------------------------------------------------------- Fade

function anim() {
    let scroll = window.scrollY
    let temp = scroll / ZOOM_SPEED
    let zoom = temp > 1 ? temp : 1

    // Only update the Elements scale, when we are below the breakpoint
    if (zoom < ZOOM_BREAKPOINT) {
        // Only scale the Image, so the Zoom element does not mess with the document width
        imgElement.style.transform = `scale(${zoom})`
        // Sets the Elements position to fixed, so it can resize without scrolling away
        zoomElement.style.top = '0px'
        zoomElement.style.position = 'fixed'
    } else {
        // Makes sure the Element always reaches Max Size
        imgElement.style.transform = `scale(${ZOOM_BREAKPOINT})`
        // Sets the elements position to absolute, so it will scroll with the rest of the document
        zoomElement.style.position = 'absolute'
        zoomElement.style.top = ABSOLUTE + 'px'
    }

    // Fade --------------------------------------------------------------------------------------
    let dif = prev - scroll

    if (zoom < ZOOM_BREAKPOINT - FADE_SPEED / ZOOM_SPEED) {
        fade = 1
    } else if (zoom > ZOOM_BREAKPOINT) {
        fade = 0
    } else {
        fade += dif / FADE_SPEED
    }

    fadeElement.style.opacity = fade
    prev = scroll
    // -------------------------------------------------------------------------------------- Fade
}

// Resets scroll position on every reload
if ('scrollRestoration' in history) {
    history.scrollRestoration = 'manual'
}

document.addEventListener('scroll', () => window.requestAnimationFrame(anim))

// Fade --------------------------------------------------------------------------------------
zoomElement.style.opacity = 1
// -------------------------------------------------------------------------------------- Fade

// Positions the afterZoom element right below the zoomed image
afterZoomElement.style.top = ABSOLUTE + IMAGE_HEIGHT_MAX / 2 + HEIGHT / 2 + 'px'
body {
    margin: 0;
}

img {
    width: 150px;
    height: 150px;
    background-color: black;
}

.fade {
    height: 100vh;
    width: 100%;
    position: fixed;
    top: 0;
    left: 0;
    background: blue;
}

.zoom {
    height: 100vh;
    width: 100%;
    display: grid;
    place-items: center;
    position: fixed;
    top: 0;
    left: 0;
}

.afterzoom {
    position: absolute;
    height: 200vh;
    width: 100%;
    background: red;
    overflow-x: auto;
}
<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="UTF-8">
</head>

<body>
    <div class="fade"></div>
    <div class="zoom">
        <img src="https://via.placeholder.com/150" alt="">
    </div>
    <div class="afterzoom">
        <p>This should appear after the above element is fully zoomed.</p>
    </div>
</body>

I got a bit carried away during coding and added some fading-in and -out to the blue background. Not necessary, but looks nice. You can remove the Fade ----- Fade parts of the code, without affecting functionality.

To alter zoom and fade speed, simply change the ZOOM_SPEED and FADE_SPEED variables.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement