Animations

Adaptive cursor

05 Jul 2023

Cursor with adaptive scaling
HTML
SCSS
PostCSS
JS
                            <a class="link" data-adaptive-cursor href="#">About Us</a> <!--For default cursor  --> 
<a class="link" data-adaptive-cursor="invert" href="#">About Us</a> <!-- For cursor with color invertion -->
                        
                            .link{
  position: relative;
}

[data-adaptive-cursor] {
  &:hover {
    .adaptive-cursor {
      opacity: 1;
      transform: translate(-50%, -50%) scale(1.2);
    }
  }

  &:active {
    .adaptive-cursor {
      transform: translate(-50%, -50%) scale(0.5) !important;
    }
  }
}

.adaptive-cursor {
  position: absolute;
  transform: translate(-50%, -50%);
  z-index: -1;

  display: block;

  width: 24px;
  height: 24px;

  border-radius: 999px;

  background: var(--primary-cl);
  opacity: 0;
  pointer-events: none;

  @include transition-all(200ms);

  &.adaptive-cursor--invert {
    z-index: 1;
    background: transparent;
    backdrop-filter: invert(1);
  }
}
                        
                            .link{
  position: relative;
}

[data-adaptive-cursor] {
	&:hover {
		.adaptive-cursor {
			opacity: 1;
			transform: translate(-50%, -50%) scale(1.2);
		}
	}

	&:active {
		.adaptive-cursor {
			transform: translate(-50%, -50%) scale(0.5) !important;
		}
	}
}

.adaptive-cursor {
	position: absolute;
	transform: translate(-50%, -50%);
	z-index: -1;

	display: block;

	width: 24px;
	height: 24px;

	border-radius: 999px;

	background: var(--primary-cl);
	opacity: 0;
	pointer-events: none;

	transition: setTransition(200ms, opacity, left, top, transform);

	&.adaptive-cursor--invert {
		z-index: 1;
		background: transparent;
		backdrop-filter: invert(1);
	}
}
                        
                            const adaptiveCursorItems = document.querySelectorAll("[data-adaptive-cursor]");
if (adaptiveCursorItems.length) {
	adaptiveCursorItems.forEach((item) => {
		const span = document.createElement("span");
		span.classList.add("adaptive-cursor");
		if (item.dataset.adaptiveCursor === "invert")
			span.classList.add("adaptive-cursor--invert");

		item.appendChild(span);

		item.addEventListener(
			"mousemove",
			throttle(({ layerX, layerY, target: { offsetWidth } }) => {
				span.style.left = layerX + "px";
				span.style.top = layerY + "px";

				let pxBetweenEdges = 0;

				if (layerX > offsetWidth / 2) {
					pxBetweenEdges = offsetWidth - layerX;
				} else {
					pxBetweenEdges = layerX;
				}

				pxBetweenEdges = pxBetweenEdges;

				const scaleSize =
					pxBetweenEdges > 20
						? (pxBetweenEdges * 100) / (offsetWidth / 2) / 40
						: 0.8; //For cursor min size

				span.style.transform = `translate(-50%, -50%) scale(${scaleSize})`;
			}, 100)
		);
	});
}
                        

Посилання на Codepen для тесту.

Також для роботи потрібна функція Throttle з бібліотеки Lodash, її можна завантажити окремо від всієї бібліотеки.

https://www.jsdelivr.com/package/npm/lodash.throttle

0