Не работают стили анимаций в компоненте 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>

→ Ссылка