/    Sign up×
Community /Pin to ProfileBookmark

Parallax Animation

I am trying to build and parallax animation on mousemove. The problem is that is not working and I can’t figure it would. Here’s the code

“`
data-speed=”2″
src=”svg/app design/guy.svg”
class=”guy illustration”
/>

const servicesAnimation = () => {
const cards = document.querySelectorAll(“.card”);
const illustrations = document.querySelectorAll(“.illustration”);

const parallaxEffect = (e) => {
illustrations.forEach((illustration) => {
const speed = illustration.dataset.speed;

cards.forEach((card) => {
const x = (card.getBoundingClientRect().width – e.pageX * speed) / 100;
const y = (card.getBoundingClientRect().height – e.pageY * speed) / 100;
});

illustration.style.transform = `translateX(${x}px) translateY(${y})`;
});
};

card.addEventListener(“mousemove”, parallaxEffect);
};
servicesAnimation();
“`

the console does not display anything. It just doesn’t work.

to post a comment
JavaScript

20 Comments(s)

Copy linkTweet thisAlerts:
@SempervivumAug 18.2021 — Regarding this code:
``<i>
</i> cards.forEach((card) =&gt; {
const x = (card.getBoundingClientRect().width - e.pageX * speed) / 100;
const y = (card.getBoundingClientRect().height - e.pageY * speed) / 100;
});

illustration.style.transform =
translateX(${x}px) translateY(${y});<i>
</i>
`</CODE>
<LIST type="decimal"><LI>1. I'm surprised that the console doesn't output any error as the variables x and y cannot be accessed outside the anonymous function for <C>
cards.forEach`.
  • 2. I do not understand what your intention is, even if I consider that the transform should be inside the anonymous function.


  • Please post some sample HTML so that your code is easier to understand.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 18.2021 — @Sempervivum#1635693
    ``<i>
    </i> &lt;div class="card"&gt;
    &lt;div class="card-info"&gt;
    &lt;h1&gt;Lorem&lt;br /&gt;ipsum&lt;/h1&gt;
    &lt;p&gt;
    Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eum eius soluta, ut perspiciatis, reiciendis autem quasi, aliquam aspernatur itaque eaque in accusantium cum distinctio. Sequi, veritatis vero. Earum necessitatibus corrupti magnam iusto tenetur possimus iste dicta quisquam blanditiis illo voluptate maiores, sit consequuntur libero labore.
    &lt;/p&gt;
    &lt;button&gt;Ask for an offer&lt;/button&gt;
    &lt;/div&gt;
    &lt;div class="card-illustration"&gt;
    &lt;img
    data-speed="5"
    src="svg/app design/phone.svg"
    class="phone illustration"
    /&gt;
    &lt;img
    data-speed="2"
    src="svg/app design/guy.svg"
    class="guy illustration"
    /&gt;
    &lt;img
    data-speed="6"
    src="svg/app design/girl.svg"
    class="girl illustration"
    /&gt;
    &lt;/div&gt;
    &lt;/div&gt;<i>

    </i>
    `</CODE>
    <CODE>
    `<i>
    </i>.card-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    }

    .card {
    background-color: var(--highlight);
    margin: 20px 0;
    width: 250px;
    padding: 20px;
    border-radius: 8px;
    }
    .card-info {
    width: 100%;
    height: auto;
    margin: 0;
    }
    .card-info h1 {
    font-size: 1.6rem;
    margin-bottom: 20px;
    }
    .card-info p {
    margin-bottom: 20px;
    }
    .card-info button {
    font-weight: 700;
    color: white;
    padding: 10px 35px;
    margin-bottom: 10px;
    background: var(--lightDark);
    border: none;
    border-radius: 50px;
    transition: all 300ms ease;
    }
    .card-info button:hover {
    color: var(--dark);
    background: white;
    }

    .card-illustration {
    position: relative;
    width: 100%;
    height: 250px;
    }
    .illustration {
    position: absolute;
    }
    .phone {
    width: 100px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    }
    .guy {
    width: 80px;
    top: calc(50% + 0px);
    left: calc(50% + 60px);
    transform: translate(-50%, -50%);
    }
    .girl {
    width: 65px;
    top: calc(50% + 40px);
    left: calc(50% - 80px);
    transform: translate(-50%, -50%);
    }<i>
    </i>
    ``

    https://we.tl/t-TDpkhvU5qx the svgs if it would help
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 18.2021 — @RaulRogojan#1635694 Forgot to say that there are multiple cards
    Copy linkTweet thisAlerts:
    @SempervivumAug 18.2021 — When I test this as is I get the following error:
    >Uncaught ReferenceError: card is not defined

    I wrapped the corresponding line by adding an evenlistener:
    ``<i>
    </i> cards.forEach(card =&gt; {
    card.addEventListener('mousemove', parallaxEffect);
    });<i>
    </i>
    ``

    Having done so, when moving the mouse I get the following error repeatedly:
    >Uncaught ReferenceError: x is not defined

    just as I expected previously.
    Copy linkTweet thisAlerts:
    @SempervivumAug 18.2021 — I changed your javascript to this:
    ``<i>
    </i> const servicesAnimation = () =&gt; {
    const cards = document.querySelectorAll(".card");
    cards.forEach(card =&gt; {
    const illustrations = card.querySelectorAll(".illustration");

    const parallaxEffect = (e) =&gt; {
    illustrations.forEach((illustration) =&gt; {
    const speed = illustration.dataset.speed;
    const x = (card.getBoundingClientRect().width - e.pageX * speed) / 100;
    const y = (card.getBoundingClientRect().height - e.pageY * speed) / 100;
    // error in the following line: "px" missing for Y
    // illustration.style.transform =
    translateX(${x}px) translateY(${y});
    illustration.style.transform =
    translateX(${x}px) translateY(${y}px);
    });
    };
    card.addEventListener('mousemove', parallaxEffect);
    });
    };
    servicesAnimation();<i>
    </i>
    ``

    and it's working.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635699 Thx! it works.

    I have a problem as the illustration gets pushed far away and out of the container instead of moving just a few pixels.

    I am imagining that this is because of e.pageX and e.pageY. I tried replacing it with card.getBoundingReactClient.x but it doesn't work. I also tried to replace it e.clientX and Y but it has the same effect.
    Copy linkTweet thisAlerts:
    @SempervivumAug 19.2021 — >I am imagining that this is because of e.pageX and e.pageY.

    I agree, MDN says:
    >The pageY read-only property of the MouseEvent interface returns the Y (vertical) coordinate in pixels of the event **relative to the whole document**.

    https://plainjs.com/javascript/styles/get-the-position-of-an-element-relative-to-the-document-24/

    Try if this helps you:

    https://plainjs.com/javascript/styles/get-the-position-of-an-element-relative-to-the-document-24/
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635714 It doesn't work. It changes position only once still in that radical manner.
    ``<i>
    </i> const parallaxEffect = (e) =&gt; {
    illustrations.forEach((illustration) =&gt; {
    const speed = illustration.dataset.speed;
    const scrollLeft = document.documentElement.scrollLeft;
    const scrollTop = document.documentElement.scrollTop;

    const x =
    (card.getBoundingClientRect().width - scrollLeft * speed) / 100;
    const y =
    (card.getBoundingClientRect().height - scrollTop * speed) / 100;

    illustration.style.transform =
    translateX(${x}px) translateY(${y}px);
    console.log(scrollLeft);
    });
    };<i>
    </i>
    ``
    Copy linkTweet thisAlerts:
    @SempervivumAug 19.2021 — Try this javascript:
    ``<i>
    </i> const parallaxEffect = (e) =&gt; {
    illustrations.forEach((illustration) =&gt; {
    const speed = illustration.dataset.speed,
    // x-positon of the card relative to the document:
    xCard = card.getBoundingClientRect().left + window.scrollX,
    // y-positon of the card relative to the document:
    yCard = card.getBoundingClientRect().top + window.scrollY,
    // e.pageX-xCard is the offset relative to the card's
    // top left corner:
    x = (e.pageX - xCard) * speed / 100,
    y = (e.pageY - yCard) * speed / 100;
    illustration.style.transform =
    translateX(${x}px) translateY(${y}px);
    });
    };<i>
    </i>
    ``
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635723 it doesn't work at all and it breaks everything.

    The problem is that I need to change that e.pageX / Y in the original code with the illustration X / Y relative to the card.

    At least I think. But I can't find how I could do that.

    I think the problem is from the css as the illustrations are placed with position absolute and using top and left.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635723 This gives me undefined
    ``javaScript <i>
    </i>console.log(illustration.getBoundingClientRect.top);<i>
    </i>
    ``
    Copy linkTweet thisAlerts:
    @SempervivumAug 19.2021 — You forgot about the brackets: `console.log(illustration.getBoundingClientRect().top);`

    I wonder why it works perfectly for me but breaks completely for you. Do you habe your version online?
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635723 Ok, I know the problem.......

    In CSS the illustrations are position using absolute than a translate (-50% -50%). and the TOP and LEFT are calculated in such a way to place the illustrations in the place that I wanted. This parallaxEffect function changes the translate(-50 -50%) while the CSS TOP and LEFT remain the same witch positions the base of the illustration on the calc() from CSS. If I ass an

    illustration.style.top = 0 the javascript portion works as intended. But of course, it is still not the effect I want as the TOP becomes 0 repositionings the illustrations to.. well TOP 0.

    For example the CSS code of one of the illustration is this
    ``<i>
    </i>.girl {
    width: 65px;
    top: calc(50% + 40px);
    left: calc(50% - 80px);
    transform: translate(-50%, -50%);
    }<i>
    </i>
    ``

    changing the top from calc(50% + 40px) to 0 is placing the illustration to the top of the div as it was when I added the illustration.

    I guess a solution would be to change the top and left of the illustration base on mouse move...

    But I am not sure how to do it or if it would work at all.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635728 I can put it into a code pen, just give me some mins
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635731 The illustration I used in the code pen does not have the same dimensions as mine I hope it would not be a problem. I also added a content-simulator to simulate the rest of the content on my project. I also added the original code but I comment it out.

    https://codepen.io/raul-rogojan/pen/yLbdWjg
    Copy linkTweet thisAlerts:
    @SempervivumAug 19.2021 — My bad, I forgot to mention that that previously I had deactivated this:

    ` /* transform: translate(-50%, -50%); */</C><br/>
    in the CSS of the illustrations. I activated it again and additionally changed the javascript to this:
    <CODE>
    `<i>
    </i> const parallaxEffect = (e) =&gt; {
    const boundingRectCard = card.getBoundingClientRect();
    illustrations.forEach((illustration) =&gt; {
    const speed = illustration.dataset.speed,
    boundingRectIllu = illustration.getBoundingClientRect(),
    // x-positon of the card relative to the document:
    xCard = boundingRectCard.left + window.scrollX,
    // y-positon of the card relative to the document:
    yCard = boundingRectCard.top + window.scrollY,
    // e.pageX-xCard is the offset relative to the card's
    // top left corner
    // -boundingRect.width/2 corresponds to -50% in CSS
    x = (e.pageX - xCard) * speed / 100 - boundingRectIllu.width / 2,
    y = (e.pageY - yCard) * speed / 100 - boundingRectIllu.height / 2;
    illustration.style.transform =
    translateX(${x}px) translateY(${y}px);
    });
    };<i>
    </i>
    ``

    https://codepen.io/Sempervivum/pen/zYwVVYa

    Now when the mouse enters from the top left of the card there is no scipping of the illustrations.
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635734 Awesome it works! thank you!

    1 more question. To reset the position of illustration on mouselave do I need to reset the translate to what?

    I tried this but it doesn't work as expected.
    ``<i>
    </i> const resetIllustrationPos = () =&gt; {
    console.log("I'm out");
    illustrations.forEach((illustration) =&gt; {
    illustration.style.transform = "translateX(-50px) translateY(-50px)";
    });
    };

    card.addEventListener("mousemove", parallaxEffect);
    card.addEventListener("mouseleave", resetIllustrationPos);<i>
    </i>
    ``
    Copy linkTweet thisAlerts:
    @SempervivumAug 19.2021 — Use the same as in the CSS:

    `illustration.style.transform = "translateX(-50%) translateY(-50%)";`
    Copy linkTweet thisAlerts:
    @codyhillauthorAug 19.2021 — @Sempervivum#1635743 I thought I was using that one. I did not see I was using px instead of %. I am a bit ashamed of that xd.
    ×

    Success!

    Help @codyhill spread the word by sharing this article on Twitter...

    Tweet This
    Sign in
    Forgot password?
    Sign in with TwitchSign in with GithubCreate Account
    about: ({
    version: 0.1.9 BETA 5.12,
    whats_new: community page,
    up_next: more Davinci•003 tasks,
    coming_soon: events calendar,
    social: @webDeveloperHQ
    });

    legal: ({
    terms: of use,
    privacy: policy
    });
    changelog: (
    version: 0.1.9,
    notes: added community page

    version: 0.1.8,
    notes: added Davinci•003

    version: 0.1.7,
    notes: upvote answers to bounties

    version: 0.1.6,
    notes: article editor refresh
    )...
    recent_tips: (
    tipper: @AriseFacilitySolutions09,
    tipped: article
    amount: 1000 SATS,

    tipper: @Yussuf4331,
    tipped: article
    amount: 1000 SATS,

    tipper: @darkwebsites540,
    tipped: article
    amount: 10 SATS,
    )...