They were working before, but I was trying to add react based page linking and that seemed to have broken the hover effects and now I cannot get them to function properly again. They do the correct hover animation on click, and work perfectly after I resize the page. It also doesn't display the "clickable" mouse pointer hand on hovering over them and another button on the page until I resize. What is the problem here?
EDIT: It seems to work on a new page in chrome but not in a tab with many other tabs open - thats when the resize hover thing is happening.
my app page:
import React from "react";
import Home from "./pages/Home";
import "./Styles/index.css";
const App: React.FC = () => {
return (
<div className="app">
<Home />
</div>
);
};
export default App;
my Main page:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./Styles/index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
my home page:
import React from "react";
import TopBar from "../components/TopBar";
import IntroSection from "../components/IntroSection";
import "../Styles/DefaultPage.css";
const Home: React.FC = () => {
return (
<div className="home-screen">
<TopBar />
<IntroSection />
</div>
);
};
export default Home;
my top bar:
import React, { useEffect, useState } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import "../Styles/TopBar.css";
gsap.registerPlugin(ScrollTrigger);
const TopBar: React.FC = () => {
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
// Add button swing animation
const navButtons = document.querySelectorAll(".nav-button");
console.log("useEffect fired - styles should be applied now");
navButtons.forEach((button) => {
const btn = button as HTMLElement;
btn.addEventListener("mouseenter", () => {
btn.style.animation = "none"; // Remove existing animation
btn.offsetHeight; // Trigger reflow
btn.style.animation = "swing 2s ease-in-out forwards"; // Reapply animation
});
btn.style.display = "none";
btn.offsetHeight; // Trigger reflow
btn.style.display = ""; // Reset display
});
return () => {
navButtons.forEach((button) => {
const btn = button as HTMLElement;
btn.removeEventListener("mouseenter", () => {});
});
};
}, []);
const toggleDarkMode = () => {
setDarkMode((prevMode) => !prevMode);
document.body.classList.toggle("dark-mode");
};
return (
<div className="top-bar">
<div className="nav-buttons">
<button className="nav-button">HOME</button>
<button className="nav-button">DEV & DESIGN</button>
<button className="nav-button">ACTING</button>
<button className="nav-button">FILMMAKING</button>
</div>
<div className="dark-mode-toggle-container">
<button className="dark-mode-toggle" onClick={toggleDarkMode}>
{darkMode ? "Light Mode" : "Dark Mode"}
</button>
</div>
</div>
);
};
export default TopBar;
the top bar CSS:
.top-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 60px;
background-color: white;
z-index: 10;
display: flex;
justify-content: space-between;
align-items: center;
}
/* Navigation buttons container */
.nav-buttons {
display: flex;
padding-left: 20px;
gap: 20px; /* Space between buttons */
height: 100%;
padding-right: 20px;
}
/* Individual navigation button styling */
.nav-button {
background: none;
border: none;
font-family: inherit;
font-size: 1rem;
cursor: pointer;
color: #333;
padding: 10px;
transform-origin: top left;
transition: transform 0.1s ease, color 0.3s ease;
align-items: center;
}
/* Color change on hover */
.nav-button:hover {
animation: wiggle 0.5s ease-in-out; /* Use the same animation keyframes */
color: #555;
}
/* Swing animation class to add animation on hover */
.swing-animation {
animation: swing 2s ease-in-out forwards;
}
/* Dark mode toggle button styling */
.dark-mode-toggle {
background: none;
border: 2px solid #333;
font-family: inherit;
font-size: 1rem;
cursor: pointer;
padding: 8px 12px;
border-radius: 4px;
transition: background-color 0.3s ease, color 0.3s ease;
}
.dark-mode-toggle-container {
display: flex;
align-items: center;
gap: 10px;
padding-right: 20px;
}
.dark-mode-toggle:hover {
background-color: #333;
color: #fff;
}
/* Dark mode styles */
body.dark-mode {
background-color: #333;
color: #fff;
}
body.dark-mode .top-bar {
background-color: #000; /* Solid black for dark mode */
}
body.dark-mode .nav-button {
color: #ccc;
}
body.dark-mode .dark-mode-toggle {
color: #fff;
}
@keyframes wiggle {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(3deg);
}
50% {
transform: rotate(-3deg);
}
75% {
transform: rotate(2deg);
}
100% {
transform: rotate(0deg);
}
}
/* Swinging animation */
@keyframes swing {
0% {
transform: rotate(0deg);
}
10% {
transform: rotate(15deg);
}
20% {
transform: rotate(-10deg);
}
30% {
transform: rotate(7deg);
}
40% {
transform: rotate(-5deg);
}
50% {
transform: rotate(3deg);
}
60% {
transform: rotate(-2deg);
}
70% {
transform: rotate(1deg);
}
80% {
transform: rotate(-0.5deg);
}
90% {
transform: rotate(0.2deg);
}
100% {
transform: rotate(0deg);
}
}
my current test build of the website:https://mattekranz.com/
The issue seems to be a combination of React's rendering quirks and animation handling. Thus, I'd try a combination of solutions:
You're using inline styles for animations in JavaScript, which can interfere with CSS hover effects. Instead, use CSS classes:
btn.addEventListener("mouseenter", () => {
btn.classList.remove("swing-animation");
void btn.offsetWidth; // Reflow to restart animation
btn.classList.add("swing-animation");
});
btn.addEventListener("mouseleave", () => btn.classList.remove("swing-animation"));
The buttons work after resizing because the browser recalculates layout. Id reflow how React handles these operations. Force this in useEffect
:
useEffect(() => {
const navButtons = document.querySelectorAll(".nav-button");
navButtons.forEach((btn) => btn.offsetHeight); // reflow
}, []);
If it works better on fewer tabs, the browser may be throttling resources. Add hardware acceleration:
* {
will-change: transform, opacity;
}
Obv, if the pointer cursor is missing, explicitly add it in CSS:
.nav-button {
cursor: pointer !important;
}
More generally, I'd run animations without GSAP to isolate the issue