In this tutorial, we’ll work with two JavaScript mouse events and GSAP to build a creative effect that you’ve probably seen somewhere on a website: a custom cursor that follows the native one and adapts its appearance depending on the hovered element.
Our Cursor Effect
Here’s what we're going to create:
Especially pay attention to the following things:
- As the mouse moves over the page, a custom cursor will follow the native one:
- As the mouse moves over the images, another custom cursor will replace the initial one:
- As the mouse moves over the copyright links, the first custom cursor will appear larger:
1. Include the Required Assets
As already discussed, to make the cursor effect, we’re going to use GSAP.
Keep in mind that GSAP isn’t the only option for this effect. You can certainly achieve it with pure JavaScript or by utilizing another JavaScript animation library like Anime.js.
I chose this library over pure JavaScript for two of its powerful tools: the timing functions and Timeline. As a website evolves, maintaining all animations through Timelines helps you have greater control of your code.
Optionally, just to make the page more appealing and speed up the development process, we’ll also add a Google Font and Bootstrap 5.
With that in mind, if you look under the Settings tab of our demo pen, you’ll see that there are two external CSS files and one external JavaScript file.
2. Define the HTML Markup
The markup for our page will consist of three sections and two div
s.
More specifically, we’ll have the following sections:
- The intro section
- The section with an image grid
- The section with the copyright licenses
Each div
will contain an icon that will be responsible for showing a custom cursor depending on the element that is being hovered. For greater flexibility, you can insert these icons in your projects by using an svg
tag instead of an img
one.
Here’s the page structure:
<section class="intro">...</section> <section class="image-grid"> <div class="container-fluid"> <div class="row"> <div class="col-12 col-sm-6 col-md-4"> <a class="d-block" href="" target="_blank"> <img width="640" height="426" src="bee1.jpg" class="shadow img-fluid" alt=""> </a> </div> <div class="col-12 col-sm-6 col-md-4"> <a class="d-block" href="" target="_blank"> <img width="640" height="426" src="/bee2.jpg" class="shadow img-fluid" alt=""> </a> </div> <div class="col-12 col-sm-6 col-md-4"> <a class="d-block" href="" target="_blank"> <img width="640" height="426" src="bee3.jpg" class="shadow img-fluid" alt=""> </a> </div> </div> </div> </section> <section class="copyright"> <div class="container"> <div class="row justify-content-center"> <div class="col-auto"> <p class="mb-0">Images from <a class="line-animation" href="https://pixabay.com/" target="_blank">Pixabay.com</a></p> </div> <div class="col-auto"> <p class="mb-0">SVG icon from <a class="line-animation" href="https://svgsilh.com/" target="_blank">SVG Silh</a></p> </div> <div class="col-auto"> <p class="mb-0">Text from <a class="line-animation" href="https://en.wikipedia.org/wiki/Cinque_Terre" target="_blank">Wikipedia</a></p> </div> </div> </div> </section> <div class="cursor cursor-bee"> <img width="30" height="26" src="cursor-bee.svg" alt=""> </div> <div class="cursor cursor-eye"> <img width="60" height="60" src="cursor-eye.svg" alt=""> </div>
3. Specify the Main Styles
Let’s now concentrate on the cursor styles, as these are the important ones.
Here are the remarkable things:
- The cursors will be fixed positioned elements.
- We’ll set accordingly their
top
andleft
property values, so the native cursor will appear in the center of the custom ones. - We’ll give them
pointer-events: none
to disable mouse interactions. - The bee cursor will always be underneath the page elements, while the eye cursor will sit on top.
- The eye cursor will initially be hidden.
Here are the associated styles:
/*CUSTOM VARIABLES HERE*/ .cursor { position: fixed; pointer-events: none; } .cursor-bee { top: -15px; left: -13px; z-index: -1; } .cursor-eye { top: -50px; left: -50px; padding: 20px; opacity: 0; z-index: 1; border-radius: 50%; background-color: var(--darkblue); }
4. Add the JavaScript
Let’s now add GSAP to the game. As we move the cursor within the page, the mousemoveHandler()
callback will fire:
document.addEventListener("mousemove", mousemoveHandler);
Inside this function, we’ll initialize a Timeline and then perform the following actions:
- Detect the hovered element.
- Define some default properties that all tweens (custom cursors) will inherit. More specifically, we’ll grab the X and Y coordinates of the mouse pointer relative to the viewport and pass those values to the target elements accordingly. Plus, we’ll use the same timing function for all animations.
- If the hovered element is an image within the image grid, we’ll simultaneously hide the bee cursor and show the eye one.
- In any other case, we’ll hide the eye cursor and at the same time show the bee one. At this point, we’ll also check if the hovered element is any of the links inside the copyright section. If that happens, we’ll quadruple the cursor’s size.
Here’s the corresponding JavaScript code:
const cursorBee = document.querySelector(".cursor-bee"); const cursorEye = document.querySelector(".cursor-eye"); let scale = 1; function mousemoveHandler(e) { // 1 const target = e.target; // 2 const tl = gsap.timeline({ defaults: { x: e.clientX, y: e.clientY, ease: "power2.out" } }); // 3 if ( target.tagName.toLowerCase() === "img" && target.closest(".image-grid") ) { tl.to(cursorBee, { opacity: 0 }).to( cursorEye, { opacity: 1 }, "-=0.5" ); } else { // 4 if (target.classList.contains("line-animation")) { scale = 4; } else { scale = 1; } tl.to(cursorBee, { opacity: 1, scale: scale }).to( cursorEye, { opacity: 0 }, "-=0.5" ); } }
Note: depending on the position type of our cursors (e.g. absolute) we can grab the mouse pointer coordinates by utilizing the pageX
and pageY
properties instead of the clientX
and clientY
ones.
In the same way, as the cursor stops moving around the page, the mouseLeaveHandler()
callback will fire:
document.addEventListener("mouseleave", mouseleaveHandler);
Inside this function, we’ll create a tween responsible for hiding the bee cursor:
... function mouseleaveHandler() { gsap.to(cursorBee, { opacity: 0 }); }
Conclusion
In today’s exercise, we managed to build a common cursor hover effect with JavaScript mouse events and GSAP.
Let’s look again at what we built:
Hopefully, you’ll “bee” able to apply what you learned here in a project. Based on what we created, go ahead and try to build something even more creative by adding interesting CSS effects like the mix-blend-mode property. Or, enhance this code for limiting the effect only on non-touch devices or/and screens wider than a certain width.
As always, thanks a lot for reading!
No comments:
Post a Comment