You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CSS链接动画导致未点击链接提前显示visited颜色及动画状态异常问题求助

CSS链接动画导致未点击链接提前显示visited颜色及动画状态异常问题求助

我刚接触CSS,最近一直在尝试关键帧动画,目前同时用CSS和JS实现以下效果:

  • 鼠标悬停链接时应用第一个关键帧动画
  • 鼠标离开链接但未点击时应用第二个动画
  • 点击链接时应用第三个动画(同时用JS延迟导航,让动画能播放完,但只在第一次点击时生效,之后恢复正常链接行为)

现在遇到的核心问题是:所有链接在未点击前就显示了:visited的颜色。我确定这和关键帧动画的设置有关,但找不到原因——鼠标悬停进入的动画以未访问链接颜色开始,悬停离开的动画以currentColor结束。如果把currentColor改成未访问链接的颜色,链接又会完全忽略:visited的颜色。

我觉得点击动画应该不是问题所在,因为它只在:active触发后才生效(我也试过:focus但没区别),不过它确实会在结束时停在已访问链接颜色。

(还有其他小问题,比如页面加载时悬停离开动画会播放(尽管设置了暂停),浏览器在页面刷新后不记住已访问状态,但如果链接颜色能正常工作,这些我可以接受。)

或者会不会是JS的问题?我对JS完全不熟悉,这段JS是别人帮我写的。

补充:我给关键帧动画加了animation-fill-mode: none;,但没效果。
补充2:修复了CSS里的链接颜色,但悬停离开动画的结束状态还是默认变成黑色
补充3:修复了默认颜色,但似乎没有纯CSS方案能让悬停离开动画从黑色淡入到当前链接颜色——它总是默认变成黑色或偏红的颜色,而不是根据链接当前的:link(偏红)或:visited(黑色)状态来变化。

用到的JS代码

document.querySelectorAll('a:not(.sitenav a):not(.footer a)').forEach(function (link) {
  let isAnimating = false;  // Flag to track if animation is already happening
  const linkId = link.href; // Use the link's href as a unique identifier
  let hasAnimatedOnce = localStorage.getItem(linkId) === 'true'; // Retrieve the value from localStorage

  link.addEventListener('click', function (e) {
    // If the link has been clicked before (stored in localStorage), allow normal behavior
    if (hasAnimatedOnce) {
      return; // Normal navigation will happen
    }

    // If animation is already happening, ignore the click
    if (isAnimating) {
      return;  // Do nothing if animation is in progress
    }

    // Prevent default navigation behavior to wait for the animation
    e.preventDefault();

    // Mark that the animation is starting
    isAnimating = true;

    // Reset the animation by removing it first (so it can be reapplied)
    this.style.animation = '';  // Remove the animation to allow it to play again

    // Trigger the animation by adding the animation property again
    this.style.animation = 'active-animation 3s forwards';  // Adjust timing as necessary

    // Store the linkElement to use later in the animationend handler
    this._linkElement = this;
  });

  // Separate animationend listener outside of click event listener
  link.addEventListener('animationend', function () {
    // If the link element was stored and animation is complete
    if (this._linkElement) {
      // Now navigate to the link's href after the animation finishes
      window.location.href = this._linkElement.href;

      // Reset the animation flag so the link can be clicked again
      isAnimating = false;

      // Mark that the link has been clicked and animated once
      hasAnimatedOnce = true;
      
      // Save the state to localStorage so the flag persists across sessions
      localStorage.setItem(linkId, 'true');
      
      // Clear the stored link element reference
      delete this._linkElement;
    }
  });
});

用到的CSS代码

/* Base state for the link - initial color is reddish */
a:link {
    position: relative;  /* Ensure the link is positioned */
    z-index: 1; /* Ensure the link is above other elements */
    color: #660e0e;  /* Start as reddish */
    pointer-events: auto;
    text-decoration: none;
    transition: color 0.4s ease;
}

a:not(.sitenav a):not(.footer a) {
  animation-play-state: paused; /* Prevent any animation from starting initially */
  pointer-events: auto;
  position: relative; /* Ensure the link is positioned */
  text-decoration: none;
}

/* Ensuring the link remains clickable during the animation */
a:hover {
  pointer-events: auto; /* Ensures pointer events remain enabled */
}

/* Hover-in animation for normal hover effect (only when not clicked) */
a:not(.sitenav a):not(.footer a):not(:active):hover {
  animation: hover-in 3s forwards; /* Add hover animation */
}

/* Hover-out animation when the mouse leaves, but only if the link hasn't been clicked */
a:not(.sitenav a):not(.footer a):not(:active):not(:hover) {
  animation: hover-out 4s none cubic-bezier(.45,.05,.55,.95);
}

/* visited link */
a:visited {
  color: black;
}

/* selected link */
a:not(.sitenav a):not(.footer a):active {
  animation-name: active-animation;
  animation-duration: 3s;
  animation-fill-mode: none;
} 

/* Active link animation (bright red -> black) */
@keyframes active-animation {
  0% {
    color: #b80909; /* Start as bright red */
    text-shadow: 0 0 20px darkred, text-shadow: 0 0 5px brown;
  }
  10% {
    font-size: 1.02em; /* embiggen */
    color: #b80909;
    text-shadow: 0 0 20px darkred, text-shadow: 0 0 10px brown;
  }
  20% {
      color: black; /* Fade back to black */
  }
  30% {
    font-size: 1.04em;
  }
  60% {
    text-shadow: 0 0 10px darkred, 0 0 5px brown;
    font-size: ''; /* shrink again */
  }
  100% {
    text-shadow: 0 0 0px darkred, text-shadow: 0 0 0px brown;
    color: '';
  }
}

/* Hover-in animation (reddish to black with shadow) */
@keyframes hover-in {
  0% {
    color: ''; /* Start as link or visited */
    text-shadow: none;
  }
  100% {
    color: black;
    text-shadow: 0 0 30px #850000, 0 0 10px #110402, 0 0 5px #110402;
  }
}

/* Hover-out animation (black to prev color with shadow fading) */
@keyframes hover-out {
  0% {
    color: black;
    text-shadow: 0 0 30px #850000, 0 0 10px #110402, 0 0 5px #110402;
  }
  50% {
    color: black;
    text-shadow: 0 0 20px #850000, 0 0 5px #110402, 0 0 3px #110402;
  }
  100% {
    color: ''; /* return to prev state? */
  }
}

用到的HTML代码

<!doctype html>
<html>
<head>
  <script type="text/javascript" src="CC-xxxCSS/CC-scripts.js" defer></script>
  <script type="text/javascript" src="CC-xxxCSS/fragment-loader.js" defer></script>
  <script type="text/javascript" src="CC-xxxCSS/base-navigation.js" defer></script>
  <link rel="stylesheet" type="text/css" href="CC-xxxCSS/CC-styles.css">
  <script src="https://code.jquery.com/jquery-3.7.1.slim.js" integrity="sha256-UgvvN8vBkgO0luPSUl2s8TIlOSYRoGFAX4jlCIm9Adc=" crossorigin="anonymous"></script>
</head>
<body>
  <div>
    <p>Fonts used on this website:</p>
    <ul>
      <li><a href="https://www.1001freefonts.com/black-castle-mf.font">Black Castle MF</a></li>
      <li><a href="http://www.dafont.com/blackletter-hplhs.font">Blackletter HPLHS</a></li>
      <li><a href="https://www.dafont.com/chomsky.font">Chomsky</a></li>
      <li><a href="https://freefontsfamily.org/trajan-pro-font-free/">Trajan Pro</a></li>
      <li><a href="http://www.dafont.com/ww2blackletter.font">WW2 Blackletter HPLHS</a></li>
    </ul>
  </div>
</body>
</html>

备注:内容来源于stack exchange,提问作者K-RAM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 08:33:04