Improve the UX of Your Website
· 826
Wajdi Alkayal Wajdi Alkayal




☰ open


Use a Custom Cursor to Improve the UX of Your Website

ARTIFICIAL INTELLIGENCE   LASTETS NEWS  Top List

BY: 

  • The mouse cursor plays a vital role in the user experience of every website. It is the reason why you know you can click a link, drag and drop an element, zoom in or zoom out on something, and so on and so forth.

    What inspired me to write this article was some fantastic websites that have made the cursor an integral part of their designs, bringing it to the next level.

    These are some of the best that caught my attention:

🆗 Basic Cursor

  • The User-Agent Stylesheet defines the basic styling of the cursor to give the user visual feedback of what they are doing on the screen, for example:

    • 👆🏼 cursor: pointer indicates a link,
    • 🚫 cursor: not-allowed suggests you can’t do a specific action,
    • 🔎 cursor: zoom-in lets you know you can zoom in on something,
    • if you want to see all of the available values, check out the cursor documentation at MDN.

    We can all agree that the basic cursor styling is ok but neither modern nor original.

    Don’t worry.

    You can customize it to make the User Experience more engaging.

🆒 Custom cursor

  • We will create a random article page to learn how to handle different styles for a custom cursor for some mouse-related events.

    This image shows a preview of the final design:

  • You can download the starter files to code along with me.

    Once you’ve downloaded the project folder, the README.md file will guide you through setting it all up to be ready to develop.

    What you’re going to see in the browser once you have installed the packages and started the development server is the layout where we will add the necessary lines of code for the custom cursor


    All the files we are going to use are inside the src folder.

  • In index.html, immediately after the <body> tag, add a new tag for the cursor.

    I prefer to use the <span> tag instead of the <div> because it has no semantic meaning, and it’s better for SEO, but feel free to use whatever you like.

    That’s enough for HTML. Next step: CSS.

  • In the scss/components folder, inside _cursor.scss, we will add the styling for the cursor.

    First of all, we need to hide the original cursor, and to do so, we need to add cursor: none !important; in scss/base/_reset.scss to the * selector.

    Now we will need a style for the default cursor and the pointer cursor. Plus, we will create a class for when the user clicks a button on the mouse.

    3.1 — Default Cursor

    Our default cursor will be a circle 40px wide with transparent background and a 2px solid border of color $secondary.

    .cursor {
    position: fixed;
    top: -20px;
    left: -20px;
    width: 40px;
    height: 40px;
    border-radius: 100%;
    border: 2px solid $secondary;
    z-index: 1;
    transition: top .2s linear, left .2s linear, width .2s linear, height .2s linear, background-color .2s linear, border-color .2s linear;
    }

    As you can see from the snippet, you need to set the position to fix and the top and left properties to -20px (half of the circle’s width, 40px / 2).

    Why I’m not just using the transform property to translate the object?

    The reason is that we are going to need the transform property later in JavaScript.

    If you refresh the browser page, you’ll now see a slice of our cursor at the top-left corner of the screen.

    Before moving on, let’s add a controller to prevent our newly created cursor from showing up on devices where the user does not have any pointing device.

    Achieving this is so easy, thanks to any-pointera CSS media feature.

    In scss/abstract/_mixins.scss, I’ve created a mixin for any-pointer that we will use in the .cursor class in a few seconds.

    @mixin anyPointer {
    @media (any-pointer: fine) {
    @content;
    }
    }

    Now, back to _cursor.scsswe need to make some adjustments:

    These lines of code will make the cursor half the size of the default cursor and add a background color to it.

    With this in place, styling is over.

    It’s JavaScript turn.

  • In the js folder, there are three files:

    • utils.js: a support file with some small reusable pieces of code
    • cursor.js: this file will contain the class Cursor with all the needed logic to make it work as expected
    • index.js: the main javascript file included in index.html

    4.1 — Utils

    This project will have only one util: getMousePosition.

    getMousePosition purpose is that, given a mousemove event, it returns an object with the coordinates of the cursor’s position on the screen. Remember to export it

    4.2 — Cursor

    Let’s get to the fun part. 🎉

    First, we should track the mouse’s position, and we can do this with the help of the mousemove event and getMousePosition.

    Remember that getMousePosition should be imported

    We’ll now define the Cursor class using the ES6 syntax with the class keyword:

    export default class Cursor {
    // ...
    }

    With the keyword constructor, we will define the constructor function for the class to store:

    • an element, whose opacity should be set to 0 to prevent flickering and to give the browser the time to see exactly where to show it according to the pointer position;
    • the element’s boundaries, with the help of getBoundingClientRect();
    • an object to hold the previous and current position on both the x-axis and y-axis of where the user’s pointer is;
    • some events to be called as callbacks to a few addEventListener().export default class Cursor {
          constructor(el) {
              this.DOM = { el: el };
              this.DOM.el.style.opacity = 0;
              this.bounds = this.DOM.el.getBoundingClientRect();
              this.renderedStyles = {
                  tx: { previous: 0, current: 0 },
                  ty: { previous: 0, current: 0 }
              };
         
              this.onFirstMouseMove = () => { /* ... */ }
              this.onMouseDown = () => { /* ... */ }
              this.onMouseUp = () => { /* ... */ }
              
              window.addEventListener('mousemove', this.onFirstMouseMove);
              window.addEventListener('mousedown', this.onMouseDown);
              window.addEventListener('mouseup', this.onMouseUp);
          }
      }

      The basic code of the constructor function is in place. Now we need to write the code for the single events. 🙌🏼

      For this.onFirstMouseMove, we need the help of GSAP, so make sure you import it at the top of the document. We want this event to run only when the user moves the pointer for the first time. To do so, we call removeEventListener() at the end of the function.


    this.onFirstMouseMove = () => {
        // center our custom cursor to the position of the pointer
        this.renderedStyles.tx.previous = this.renderedStyles.tx.current = mouse.x - this.bounds.width / 2;
        this.renderedStyles.ty.previous = this.renderedStyles.ty.previous = mouse.y - this.bounds.height / 2;
        
        // set opacity of the element to 1 
        gsap.to(this.DOM.el, {
            duration: 2,
            ease: 'Power3.easeOut',
            opacity: 1
        });
        
        // render the cursor
        this.render(); // we still have to create this method!
        
        // remove the event listener
        window.removeEventListener('mousemove', this.onFirstMouseMove);
    }

    this.onMouseDown and this.onMouseUp handle the addition or removal of the .cursor--mousedown to obtain visual feedback when a mouse’s button is pushed.

    In this.onMouseDown, we also need to check which of the mouse buttons is clicked. We can achieve this thanks to a numeric code stored inside the which property.

    Since we don’t want the effect of mouse-down to show up when the user makes a right-click, we are interested only in left-clicks that can be recognized by code 1.

    While in this.onMouseUp, nothing fancy happens: we only remove the class .cursor--mousedown.


this.onMouseDown = (e) => {
    if (e.which === 1) {
        this.DOM.el.classList.add("cursor--mousedown");
    }
}

this.onMouseUp = () => {
    this.DOM.el.classList.remove("cursor--mousedown");
}

The constructor function is ready. Now, we only need some methods: render()onMouseOver() and onMouseLeave().

The render() method, that we already encounter in the this.onFirstMouseMove event, is responsible for rendering our cursor and behaving correctly.


render() {
    // check mouse position and update the current value of x and y in this.renderedStyles
    this.renderedStyles['tx'].current = mouse.x - this.bounds.width / 2;
    this.renderedStyles['ty'].current = mouse.y - this.bounds.height / 2;

    // store the current position in the previous property
    for (const key in this.renderedStyles ) {
        this.renderedStyles[key].previous = this.renderedStyles[key].current;
    }
    
    // change the styling to update the translateX and translateY in transform property so that the cursor follows the pointer
    this.DOM.el.style.transform = `translateX(${(this.renderedStyles['tx'].previous)}px) translateY(${this.renderedStyles['ty'].previous}px)`;

    // perform the animation before the next repaint
    requestAnimationFrame(() => this.render());
}

I suggest you check out requestAnimationFrame, the method that tells the browser that you wish to perform an animation before the next repaint.

onMouseOver() and onMouseLeave() methods will give visual feedback when hovering over links.

You may ask why I’m treating these last two as methods instead of events inside the object: the reason is that these two are not events directly related to the cursor, and they will be used as callback functions for mouseover and mouseleave on links.

onMouseOver = () => this.DOM.el.classList.add("cursor--mousehover");
onMouseLeave = () => this.DOM.el.classList.remove("cursor--mousehover");

Lastly, we must initialize the Cursor class in index.js and listen for mouseover and mouseleave events on every link.


import Cursor from './cursor';

const cursor = new Cursor(document.querySelector(.cursor));

const links = document.querySelectorAll('.link');
links.forEach(link => {
    link.addEventListener('mouseover', () => cursor.onMouseOver());
    link.addEventListener('mouseleave', () => cursor.onMouseLeave());
}

The end. 🥳

🎓 Conclusion

My example is only a simple one to show you that creating a custom cursor is not a bloodbath and can have unexpected results on the overall UX of your website.

Plus, I really love the way custom cursors make websites look and feel. Out there, you can find so many great examples to get inspired, learn from and, experiment with.

The sky is the limit! ⭐️

 PROGRAMMING



Social Channels:

TWIITER

FACEBOOK

YOUTUBE

INSTAGRAM



Join Our Telegram Channel for More Insights


WMK-IT W3.CSS


News

Machinlearning
python
Programming
Javascript
Css
Mobile Application
Web development
Coding
Digital Marketing
Web Development
WMK-IT&TECH
Job

Blog post

web developer
SENIOR OR MIDDLE ANDROID DEVELOPER
IT RECRUITER


Related Posts
Graphic design
09 June
The Power of Email Marketing
03 June
Photography
01 June

WMK Tech Copyright © 2024. All rights reserved