<h1>
	Hover over each of the buttons to see the effect in action.</h1>
<div class="display">
	<a class="HOVER">
		<span></span>
		<text>Hover Me!</text>
	</a>
	<a class="HOVER">
		<span></span>
		<text>Hover Me!</text>
	</a>
	<a class="HOVER">
		<span></span>
		<text>Hover Me!</text>
	</a>
	<a class="HOVER FLASH">
		<span></span>
		<text>Don't Hover Me!</text>
	</a>
</div>

<footer>
	<div class="link">Did you like this? Check out my other projects <a href="https://codepen.io/ViktorKorolyuk" target="_blank">here</a></div>
</footer>
@keyframes shake {
	25% {
		transform: rotate(calc(var(--angle) * -1));
	}

	50% {
		transform: rotate(var(--angle));
	}

	100% {
		transform: rotate(0deg);
	}
}

body {
	font: 100 1.3em sans-serif;
	display: flex;
	flex-direction: column;
	align-content: center;
	padding: 0 5rem;
}

h1 {
	font-weight: 100;
}

.display {
	display: grid;
	grid-template-columns: 50% 50%;
	gap: 0.1em;
}

.HOVER {
	--width: 100%;
	--time: 0.7s;

	position: relative;
	display: inline-block;
	height: 1em;
	padding: 1em;

	color: white;
	background: #222;
	overflow: hidden;
}

.HOVER text {
	position: relative;
	z-index: 5;
	
	transition: color var(--time);
}

.HOVER:hover text {
	color: #222;
}

.HOVER span {
	position: absolute;
	display: block;
	content: "";
	z-index: 0;
	width: 0;
	height: 0;
	
	border-radius: 100%;
	background: #fff;
	
	transform: translate(-50%, -50%);
	transition: width var(--time), padding-top var(--time);
}

.HOVER:hover span {
	width: calc(var(--width) * 2.25);
	padding-top: calc(var(--width) * 2.25);
}

.HOVER.FLASH:hover text {
	color: white;
}

.HOVER.FLASH span {
	background: #ff3b3b;
}

.animated {
	--angle: 5deg;
	animation: shake 0.3s;
}

.link{
	position: absolute;
	right: 10px;
	bottom: 10px;
	
	font-size: 1rem;
}
const ANIMATEDCLASSNAME = "animated";
const ELEMENTS = document.querySelectorAll(".HOVER");
const ELEMENTS_SPAN = [];

ELEMENTS.forEach((element, index) => {
	let addAnimation = false;
	// Elements that contain the "FLASH" class, add a listener to remove
	// animation-class when the animation ends
	if (element.classList[1] == "FLASH") {
		element.addEventListener("animationend", e => {
			element.classList.remove(ANIMATEDCLASSNAME);
		});
		addAnimation = true;
	}

	// If The span element for this element does not exist in the array, add it.
	if (!ELEMENTS_SPAN[index])
		ELEMENTS_SPAN[index] = element.querySelector("span");

	element.addEventListener("mouseover", e => {
		ELEMENTS_SPAN[index].style.left = e.pageX - element.offsetLeft + "px";
		ELEMENTS_SPAN[index].style.top = e.pageY - element.offsetTop + "px";

		// Add an animation-class to animate via CSS.
		if (addAnimation) element.classList.add(ANIMATEDCLASSNAME);
	});

	element.addEventListener("mouseout", e => {
		ELEMENTS_SPAN[index].style.left = e.pageX - element.offsetLeft + "px";
		ELEMENTS_SPAN[index].style.top = e.pageY - element.offsetTop + "px";
	});
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.