Skip to content

Instantly share code, notes, and snippets.

@ijurko
Created July 13, 2022 08:54
Show Gist options
  • Save ijurko/f3f3f7aef71c04585372811d45099685 to your computer and use it in GitHub Desktop.
Save ijurko/f3f3f7aef71c04585372811d45099685 to your computer and use it in GitHub Desktop.
@use "sass:math";
.c-custom-cursor-wrapper {
position: relative;
}
.c-custom-cursor {
@include fluidValue("width", null, 26px);
@include fluidValue("height", null, 26px);
@include fluidValue("top", null, -19px);
@include fluidValue("left", null, -19px);
position: fixed;
z-index: getZindex("cursor");
pointer-events: none;
border-radius: 50%;
background: $white;
mix-blend-mode: exclusion;
box-shadow: 0 0 0 0 $white;
transition: box-shadow 0.3s ease-in-out, background-color 0.3s ease-in-out;
display: inline-flex;
justify-content: center;
align-items: center;
&.is-pointer,
&.is-loader {
box-shadow: 0 0 0 5px $white;
@include mq(null, xl) {
box-shadow: 0 0 0 get-vw(5px) $white;
}
}
&.is-video {
background-color: $white;
box-shadow: 0 0 0 10px $white;
mix-blend-mode: unset;
@include mq(null, xl) {
box-shadow: 0 0 0 get-vw(10px) $white;
}
.is-background-black & {
background-color: $off-black;
box-shadow: 0 0 0 10px $off-black;
@include mq(null, xl) {
box-shadow: 0 0 0 get-vw(10px) $off-black;
}
}
}
@include mq(md) {
display: none;
}
@media (hover: none) {
display: none;
}
.is-cursor-visible & {
}
.is-cursor-hidden & {
transform: scale(0.5);
opacity: 0;
}
&__icon {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
}
&__label {
opacity: 0;
transform: scale(0.5);
transition: all 0.3s ease-in-out;
transition-delay: 0.1s;
.is-cursor-visible & {
}
.is-cursor-hidden & {
}
.is-video & {
opacity: 1;
transform: scale(1);
}
.is-video-playing & {
transform: scale(0.5);
opacity: 0;
}
}
}
<!-- CUSTOM CURSOR -->
<div class="c-custom-cursor js-custom-cursor">
<span class="c-custom-cursor__label u-b1 u-uppercase js-custom-cursor-label">
</span>
</div>
<!-- end CUSTOM CURSOR -->
import { gsap } from "gsap";
/**
* Custom cursor
*/
export default class CustomCursor {
constructor() {
/**
* Dom selectors
* @type {{customCursorWrapper: string, cursorType: {loader: string, link: string, video: string}, customCursor: string, cursorTrigger: string, customCursorLabel: string, states: {cursorVisible: string, cursorHidden: string}}}
*/
this.DOM = {
customCursorWrapper: ".js-custom-cursor-wrapper",
customCursor: ".js-custom-cursor",
customCursorLabel: ".js-custom-cursor-label",
cursorTrigger: "[data-cursor]",
states: {
cursorHidden: "is-cursor-hidden",
cursorVisible: "is-cursor-visible",
},
cursorType: {
video: "is-video",
link: "is-pointer",
loader: "is-loader",
},
};
this.customCursorWrapper = document.querySelector(this.DOM.customCursorWrapper);
this.customCursor = document.querySelector(this.DOM.customCursor);
this.cursorTrigger = document.querySelectorAll(this.DOM.cursorTrigger);
this.customCursorLabel = document.querySelector(this.DOM.customCursorLabel);
document.addEventListener("customCursorReInit", () => {
this.cursorTrigger = document.querySelectorAll(this.DOM.cursorTrigger);
this.init();
});
}
/**
* init
*/
init() {
if (this.customCursorWrapper !== null && this.customCursor && this.customCursorLabel) {
this.initEvents();
this.render();
}
}
/**
* setup events
*/
initEvents() {
this.customCursorWrapper.addEventListener("pointermove", (e) => {
this.clientX = e.clientX;
this.clientY = e.clientY;
});
this.customCursorWrapper.addEventListener("mouseenter", () => {
this.customCursorWrapper.classList.remove(this.DOM.states.cursorHidden);
});
this.customCursorWrapper.addEventListener("mouseleave", () => {
this.customCursorWrapper.classList.add(this.DOM.states.cursorHidden);
});
if (this.cursorTrigger.length > 0) {
this.cursorTrigger.forEach((trigger) => {
trigger.addEventListener("mouseenter", (ev) => {
this.cursorMouseEnter(ev);
});
trigger.addEventListener("mouseleave", (ev) => {
this.cursorMouseLeave(ev);
});
});
}
}
/**
*
* @param ev
*/
cursorMouseEnter(ev) {
this.clearClasses();
this.customCursor.classList.add(this.DOM.cursorType[ev.target.dataset.cursorType]);
if (ev.target.dataset.cursorLabel !== "") {
this.customCursorLabel.innerHTML = ev.target.dataset.cursorLabel;
}
}
/**
* used on mouse leave event
*/
cursorMouseLeave() {
this.clearClasses();
}
/**
* Clear cursor classes and remove label
*/
clearClasses() {
this.customCursor.classList.remove(this.DOM.cursorType.link);
this.customCursor.classList.remove(this.DOM.cursorType.video);
this.customCursor.classList.remove(this.DOM.cursorType.loader);
this.customCursorLabel.innerHTML = "";
}
/**
* Renders cursor position
*/
render() {
gsap.set(this.customCursor, {
x: this.clientX,
y: this.clientY,
});
requestAnimationFrame(() => this.render());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment