Не работают стили анимаций в компоненте ReactJS
У меня есть компонент Header, в котором находятся ссылки для навигации. Я пытался сделать так, чтобы при нажатии на "open navigation" этот блок плавно уходил вверх и исчезал, а вместо него появлялся плавно сверху вниз блок со всеми ссылками. Но ссылки не появляются так, как надо, и я не могу понять что тут не так. Помогите, пожалуйста
Header.jsx и Header.css
import { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import './Header.css';
const Header = () => {
const [isNavOpen, setIsNavOpen] = useState(false);
const navRef = useRef(null);
const toggleRef = useRef(null);
useEffect(() => {
const handleOutsideClick = (event) => {
if (navRef.current && !navRef.current.contains(event.target) && !toggleRef.current.contains(event.target)) {
setIsNavOpen(false);
}
};
document.addEventListener('click', handleOutsideClick);
return () => {
document.removeEventListener('click', handleOutsideClick);
};
}, []);
const handleNavToggle = () => {
setIsNavOpen((prev) => !prev);
};
return (
<header className="header">
<nav ref={navRef} className={`nav ${isNavOpen ? 'open' : ''}`}>
<ul className="nav-list">
<li className={`nav-item ${isNavOpen ? '' : 'hidden'}`}>
<Link to="/leaderboard">
svg
</Link>
</li>
<li className={`nav-item ${isNavOpen ? '' : 'hidden'}`}>
<Link to="/scores-feed">
svg
</Link>
</li>
<li className={`nav-item ${isNavOpen ? '' : 'hidden'}`}>
<Link to="/about">
svg
</Link>
</li>
</ul>
</nav>
<div ref={toggleRef} className={`nav-toggle ${isNavOpen ? 'hidden' : ''}`} onClick={handleNavToggle}>
open navigation
</div>
</header>
);
};
export default Header;
.header {
width: 100%;
top: 0;
left: 0;
color: white;
display: flex;
justify-content: center;
align-items: center;
transition: background 0.3s ease;
z-index: 1;
padding: 10px;
}
.nav {
display: none;
opacity: 0;
transform: translateY(-20px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.nav.open {
display: block;
opacity: 1;
transform: translateY(0);
}
.nav-list {
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.nav-item {
margin: 0 15px;
position: relative;
margin-bottom: 10px;
opacity: 0;
transform: translateY(20px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.nav.open .nav-item {
opacity: 1;
transform: translateY(0);
transition-delay: 0.3s;
}
.svg-icon {
width: 160px;
height: 50px;
position: relative;
}
.svg-border {
stroke-dasharray: 600;
stroke-dashoffset: 600;
transition: stroke-dashoffset 0.5s ease;
}
.nav-item:hover .svg-border {
stroke-dashoffset: 0;
}
.svg-icon rect,
.svg-icon line {
visibility: hidden;
}
.nav-item:hover .svg-icon rect,
.nav-item:hover .svg-icon line {
visibility: visible;
}
.nav-toggle {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background-color: transparent;
padding: 3px;
position: absolute;
top: -30px;
left: 50%;
transform: translateX(-50%);
}
.navigationSvg {
width: 230px;
height: auto;
}
svg.navigationSvg:hover path {
fill: rgba(218, 218, 218, 0.116);
}
.nav-toggle-label {
margin-right: 5px;
font-size: 20px;
}
.hidden {
opacity: 0;
transform: translateY(-100px);
transition: opacity .55s ease, transform 4.5s ease;
pointer-events: none;
}
Ответы (1 шт):
Автор решения: Arbery
→ Ссылка
В рабочем виде - приблизительно так, если убрать display
, и трансформации для дочерних элементов - хотя последнее не обязательно, возможно такова задумка анимации, чтобы весь блок приезжал сверху и его дочерние еще откуда-то.
const Link = ({children}) => <a>{children}</a>
const Header = () => {
const [isNavOpen, setIsNavOpen] = React.useState(false);
const navRef = React.useRef(null);
const toggleRef = React.useRef(null);
React.useEffect(() => {
const handleOutsideClick = (event) => {
if (
navRef.current &&
!navRef.current.contains(event.target) &&
!toggleRef.current.contains(event.target)
) {
setIsNavOpen(false);
}
};
document.addEventListener("click", handleOutsideClick);
return () => {
document.removeEventListener("click", handleOutsideClick);
};
}, []);
const handleNavToggle = () => {
setIsNavOpen((prev) => !prev);
};
return (
<header className="header">
<nav ref={navRef} className={`nav ${isNavOpen ? "open" : ""}`}>
<ul className="nav-list">
<li className={`nav-item ${isNavOpen ? "" : "hidden"}`}>
<Link to="/leaderboard">
<svg
width="140"
height="50"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 50"
preserveAspectRatio="xMidYMid meet"
className="svg-icon"
>
<rect
x="5"
y="40"
width="5"
height="5"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<rect
x="180"
y="5"
width="5"
height="5"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<line
x1="1"
y1="12"
x2="12"
y2="1"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<line
x1="179"
y1="49"
x2="190"
y2="37"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<polygon
points="20,0 190,0 190,30 172,50 0,50 0,40 0,20"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="3"
className="svg-border"
/>
<text
className="text"
x="50%"
y="50%"
textAnchor="middle"
fill="white"
dy=".3em"
fontSize="30"
>
Leaderboard
</text>
</svg>
</Link>
</li>
<li className={`nav-item ${isNavOpen ? "" : "hidden"}`}>
<Link to="/scores-feed">
<svg
width="140"
height="50"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 50"
preserveAspectRatio="xMidYMid meet"
className="svg-icon"
>
<rect
x="5"
y="40"
width="5"
height="5"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<rect
x="180"
y="5"
width="5"
height="5"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<line
x1="1"
y1="12"
x2="12"
y2="1"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<line
x1="179"
y1="49"
x2="190"
y2="37"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<polygon
points="20,0 190,0 190,30 172,50 0,50 0,40 0,20"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="3"
className="svg-border"
/>
<text
className="text"
x="50%"
y="50%"
textAnchor="middle"
fill="white"
dy=".3em"
fontSize="30"
>
Scores feed
</text>
</svg>
</Link>
</li>
<li className={`nav-item ${isNavOpen ? "" : "hidden"}`}>
<Link to="/about">
<svg
width="140"
height="50"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 50"
preserveAspectRatio="xMidYMid meet"
className="svg-icon"
>
<rect
x="5"
y="40"
width="5"
height="5"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<rect
x="180"
y="5"
width="5"
height="5"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<line
x1="1"
y1="12"
x2="12"
y2="1"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<line
x1="179"
y1="49"
x2="190"
y2="37"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<polygon
points="20,0 190,0 190,30 172,50 0,50 0,40 0,20"
fill="none"
stroke="rgb(19, 65, 150)"
strokeWidth="3"
className="svg-border"
/>
<text
className="text"
x="50%"
y="50%"
textAnchor="middle"
fill="white"
dy=".3em"
fontSize="30"
>
About
</text>
</svg>
</Link>
</li>
</ul>
</nav>
<div
ref={toggleRef}
className={`nav-toggle ${isNavOpen ? "hidden" : ""}`}
onClick={handleNavToggle}
>
<svg
width="140"
height="50"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 50"
preserveAspectRatio="xMidYMid meet"
className={`navigationSvg ${isNavOpen ? "hidden" : ""}`}
>
<path
d="M 10 10 L 190 10 L 180 40 L 20 40 L 10 10"
fill="transparent"
stroke="rgb(19, 65, 150)"
strokeWidth="2"
/>
<text
className={`nav-toggle-label ${isNavOpen ? "hidden" : ""}`}
x="50%"
y="50%"
textAnchor="middle"
fill="white"
dy=".3em"
>
Open navigation
</text>
</svg>
</div>
</header>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Header />
);
body {
background: #000;
}
.header {
width: 100%;
top: 0;
left: 0;
color: white;
display: flex;
justify-content: center;
align-items: center;
transition: background 0.3s ease;
z-index: 1;
padding: 10px;
overflow: hidden;
}
.nav {
/* display: none; */
opacity: 0;
transform: translateY(-50px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.nav.open {
/* display: block; */
opacity: 1;
transform: translateY(0);
}
.nav-list {
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.nav-item {
margin: 0 15px;
position: relative;
margin-bottom: 10px;
/* opacity: 0;
transform: translateY(20px);
transition: opacity 0.5s ease, transform 0.5s ease; */
}
/*
.nav.open .nav-item {
opacity: 1;
transform: translateY(0);
transition-delay: 0.3s;
}
*/
.svg-icon {
width: 160px;
height: 50px;
position: relative;
}
.svg-border {
stroke-dasharray: 600;
stroke-dashoffset: 600;
transition: stroke-dashoffset 0.5s ease;
}
.nav-item:hover .svg-border {
stroke-dashoffset: 0;
}
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>