Skip to content

CSS 常见效果实现集锦 ​

本文收集了一些常见且实用的 CSS 效果实现方案。从基础的悬停动画到现代的 Houdini API,这些效果都经过精心设计和优化,可以直接应用到实际项目中。

目录 ​

  1. 导航栏下划线跟随效果
  2. 玻璃镜片流光效果
  3. 轮盘按钮效果
  4. 立体书签角标
  5. 文字渐入动画效果
  6. 渐变色边框容器
  7. CSS圆形贴合裁剪效果

导航栏下划线跟随效果 ​

这是一个常见的导航栏交互效果,当鼠标悬停在导航项上时,下划线会平滑地跟随移动。

实现要点 ​

  • 使用 transition 实现平滑动画
  • 记录最后停留位置,实现鼠标离开时的回归动画
  • 通过 JavaScript 动态计算下划线宽度和位置

效果预览 ​

鼠标跟随下划线

代码实现 ​

html
<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <title>导航栏下划线跟随效果</title>
  <style>
    .nav {
      display: flex;
      position: relative;
      width: 800px;
      margin: 100px auto;
    }

    .nav-item {
      padding: 20px;
      font-size: 18px;
      cursor: pointer;
      text-align: center;
      flex: 1;
    }

    .nav-item:hover {
      color: #1890ff;
    }

    .indicator {
      position: absolute;
      bottom: 0;
      height: 2px;
      background-color: #1890ff;
      transition: all 0.3s ease 0.1s;
    }
  </style>
</head>

<body>
  <div class="nav">
    <div class="nav-item">首页</div>
    <div class="nav-item">产品</div>
    <div class="nav-item">服务</div>
    <div class="nav-item">关于我们</div>
    <div class="indicator"></div>
  </div>

  <script>
    const items = document.querySelectorAll('.nav-item');
    const indicator = document.querySelector('.indicator');
    let lastHoveredItem = items[0]; // 记录最后停留的位置

    // 初始化indicator位置
    function initIndicator() {
      indicator.style.width = `${items[0].offsetWidth}px`;
      indicator.style.left = `${items[0].offsetLeft}px`;
    }

    items.forEach(item => {
      item.addEventListener('mouseenter', () => {
        indicator.style.width = `${item.offsetWidth}px`;
        indicator.style.left = `${item.offsetLeft}px`;
        lastHoveredItem = item;
      });
    });

    // 鼠标离开导航区域时,回到最后停留的位置
    document.querySelector('.nav').addEventListener('mouseleave', () => {
      indicator.style.width = `${lastHoveredItem.offsetWidth}px`;
      indicator.style.left = `${lastHoveredItem.offsetLeft}px`;
    });

    // 初始化
    initIndicator();
  </script>
</body>

</html>

玻璃镜片流光效果 ​

这是一个现代化的卡片设计,结合了玻璃拟态(Glassmorphism)和流光溢彩的动画效果。

实现要点 ​

  • 使用 linear-gradient 创建渐变背景
  • 通过伪元素实现流光动画
  • 利用 opacity 和 transition 控制动画效果

效果预览 ​

玻璃镜片流光效果

关键CSS属性解析 ​

css
/* 玻璃镜片效果 */
.box::before {
  background: linear-gradient(
    110deg,
    rgba(255, 255, 255, 0.9),
    rgba(255, 255, 255, 0) 20%,
    rgba(255, 255, 255, 0) 70%,
    rgba(255, 255, 255, 0.9)
  );
}

/* 流光动画效果 */
.box::after {
  transform: skew(-20deg);  /* 创建倾斜效果 */
  box-shadow: 0 0 10vmin 2.5vmin rgba(255, 255, 255, 1); /* 发光效果 */
}

代码实现 ​

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>玻璃镜片流光效果</title>
  <style>
    /* 容器样式 */
    .container {
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      background: #1a1a1a;
      /* 深色背景突出效果 */
    }

    /* 卡片基础样式 */
    .box {
      position: relative;
      /* 相对定位,作为伪元素的定位父级 */
      width: 400px;
      height: 200px;
      background: linear-gradient(45deg, #2196f3, #ff4685);
      border-radius: 15px;
      overflow: hidden;
      /* 隐藏溢出部分,使流光效果不超出卡片 */
      cursor: pointer;
    }

    /* 玻璃镜片效果 - 使用::before */
    .box::before {
      content: "";
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      /* 创建渐变效果,形成玻璃质感 */
      background: linear-gradient(110deg,
          rgba(255, 255, 255, 0.9),
          rgba(255, 255, 255, 0) 20%,
          rgba(255, 255, 255, 0) 70%,
          rgba(255, 255, 255, 0.9));
      opacity: 1;
      transition: opacity 0.65s ease;
      /* 过渡动画 */
    }

    /* 流光效果 - 使用::after */
    .box::after {
      content: "";
      position: absolute;
      background-color: rgba(255, 255, 255, 0.6);
      width: 5vmin;
      top: 0;
      bottom: 0;
      left: -100%;
      /* 初始位置在卡片外 */
      transform: skew(-20deg);
      /* 倾斜效果 */
      /* 发光效果 */
      box-shadow: 0 0 10vmin 2.5vmin rgba(255, 255, 255, 1);
      transition: all 0.25s ease;
    }

    /* 悬停时玻璃效果消失 */
    .box:hover::before {
      opacity: 0;
    }

    /* 悬停时触发流光动画 */
    .box:hover::after {
      left: 400px;
      /* 移动到卡片右侧 */
      transition: left 0.5s ease;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="box"></div>
  </div>
</body>

</html>

轮盘按钮效果 ​

这是一个创意十足的交互设计,适用于需要展示多个快捷操作的场景。按钮初始呈现为圆形,悬停时展开成扇形菜单。

效果预览 ​

轮盘按钮效果

关键技术 ​

  1. 扇形计算
css
/* 扇形区域计算公式:
 * 旋转角度 = -160° + (n-1) * 50°
 * 其中 n 为扇形序号(1,2,3)
 */
.sectorBox:nth-child(1) {
  transform: rotate(-160deg) skewY(40deg);
}
.sectorBox:nth-child(2) {
  transform: rotate(-110deg) skewY(40deg);
}
.sectorBox:nth-child(3) {
  transform: rotate(-60deg) skewY(40deg);
}
  1. 文字方向修正
css
/* 文字需要反向旋转以保持正确方向 */
.sectorBox:nth-child(1) span {
  transform: skewY(-40deg) rotate(160deg);
}

使用注意事项 ​

  • 建议控制菜单项数量在3-5个之间
  • 注意移动端触发区域的大小
  • 可以通过调整 transform-origin 改变展开中心点

代码实现 ​

html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>轮盘按钮效果</title>
  <style>
    html,
    body {
      background-color: #000;
    }

    /* 外层容器:固定定位,初始状态为圆形 */
    .RouletteOut {
      background: rgba(255, 255, 255, 0.2);
      border-radius: 500px;
      width: 120px;
      height: 120px;
      position: fixed;
      bottom: 1.5vw;
      left: 3vw;
      transform-origin: center center;
      /* 变形的原点设置为中心 */
      transition: all 0.3s ease;
      /* 添加过渡效果 */
      overflow: hidden;
      cursor: pointer;
    }

    /* 内层圆形:始终保持在外层容器的中心 */
    .RouletteIn {
      background: rgba(255, 255, 255, 0.6);
      border-radius: 100px;
      width: 88px;
      height: 88px;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      /* 使用transform居中 */
      transform-origin: center center;
      transition: all 0.3s ease;
      z-index: 1;
      /* 确保在扇形区域上方 */
      overflow: hidden;
    }

    /* 鼠标悬停时外层容器的样式 */
    .menuShow.RouletteOut {
      width: 337px;
      height: 337px;
      /* 扩大尺寸时,调整位置保持中心点不变 */
      bottom: calc(1.5vw - 108px);
      left: calc(3vw - 108px);
    }

    /* 鼠标悬停时内层圆形的样式 */
    .menuShow .RouletteIn {
      width: 112px;
      height: 112px;
    }

    /* 扇形区域的容器 */
    .circleContainer {
      position: relative;
      width: 337px;
      height: 337px;
      border-radius: 50%;
      overflow: hidden;
      z-index: -1;
      display: none;
      /* 初始状态隐藏 */
    }

    /* 显示扇形区域 */
    .menuShow .circleContainer {
      display: block;
    }

    /* 单个扇形的基础样式 */
    .sectorBox {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 50%;
      height: 50%;
      transform-origin: 0 0;
      /* 变形原点设置在左上角 */
      font-size: 14px;
      font-family: Arial-Regular, Arial;
      font-weight: 400;
      color: #FFFFFF;
    }

    /* 扇形内的文字 */
    .sectorBox span {
      position: absolute;
      white-space: nowrap;
    }

    /* 三个扇形区域的旋转和倾斜角度 */
    .sectorBox:nth-child(1) {
      transform: rotate(-160deg) skewY(40deg);
    }

    .sectorBox:nth-child(1) span {
      transform: skewY(-40deg) rotate(160deg);
    }

    .sectorBox:nth-child(2) {
      transform: rotate(-110deg) skewY(40deg);
    }

    .sectorBox:nth-child(2) span {
      transform: skewY(-40deg) rotate(110deg);
    }

    .sectorBox:nth-child(3) {
      transform: rotate(-60deg) skewY(40deg);
    }

    .sectorBox:nth-child(3) span {
      transform: skewY(-40deg) rotate(60deg);
    }

    /* 扇形hover效果 */
    .sectorBox:hover {
      background: linear-gradient(63deg,
          rgba(215, 255, 55, 0.9) 0%,
          rgba(215, 255, 55, 0.8) 32%,
          rgba(215, 255, 55, 0.18) 71%,
          rgba(74, 0, 224, 0) 100%,
          rgba(215, 255, 55, 0) 100%);
      box-shadow: 0px 0px 16px 0px rgba(200, 173, 255, 0.8);
      color: #373737;
    }
  </style>
</head>

<body>
  <!-- 主要结构 -->
  <div class="RouletteOut" id="rouletteOut">
    <!-- 中心圆形 -->
    <div class="RouletteIn"></div>
    <!-- 扇形区域容器 -->
    <div class="circleContainer">
      <!-- 三个扇形区域 -->
      <div class="sectorBox" onclick="handleClick(0)">
        <span style="left: 20%; top: 30%;">Mine</span>
      </div>
      <div class="sectorBox" onclick="handleClick(1)">
        <span style="bottom: 60%; left: 10%;">Featured</span>
      </div>
      <div class="sectorBox" onclick="handleClick(2)">
        <span style="left: 20%; top: 30%;">Recent</span>
      </div>
    </div>
  </div>

  <script>
    // 获取外层容器元素
    const rouletteOut = document.getElementById('rouletteOut');

    // 添加鼠标进入事件
    rouletteOut.addEventListener('mouseenter', () => {
      rouletteOut.classList.add('menuShow');
    });

    // 添加鼠标离开事件
    rouletteOut.addEventListener('mouseleave', () => {
      rouletteOut.classList.remove('menuShow');
    });

    // 扇形点击处理函数
    function handleClick(index) {
      console.log('点击了第', index + 1, '个扇形');
      // 这里可以添加点击后的具体操作
    }
  </script>
</body>

</html>

立体书签角标 ​

一个精致的立体书签角标效果,适用于标记重要信息或状态。通过叠加阴影和伪元素创造出逼真的折纸效果。

效果预览 ​

立体书签角标

代码实现 ​

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>立体书签角标示例</title>
    <style>
        /* 重置图片默认间距 */
        img {
            vertical-align: bottom;
        }

        /* 主容器 - 用于放置内容和角标 */
        .cornerMarkBox {
            width: 400px;
            height: 500px;
            position: relative;      /* 为角标定位提供参考 */
            background: #1890ff;
            overflow: visible;       /* 允许角标超出容器 */
            margin: 20px;
            display: inline-block;
        }

        /* 角标容器 - 控制角标的位置和溢出隐藏 */
        .MarkBox {
            width: 106px;
            height: 108px;
            overflow: hidden;        /* 隐藏旋转后多余的部分 */
            position: absolute;      /* 相对主容器定位 */
            top: -6px;
            left: 297px;
        }

        /* 角标内部样式 - 实现旋转和立体效果 */
        .insideBox {
            line-height: 18px;
            text-align: center;
            transform: rotate(45deg);    /* 45度旋转实现角标效果 */
            position: relative;
            padding: 8px 0;
            left: -8px;
            top: 25px;
            width: 150px;               /* 宽度要足够以便旋转后覆盖角落 */
            background: red;
            color: white;
            box-shadow: 0 5px 5px rgba(0, 0, 0, 0.1);  /* 添加阴影提升立体感 */
            letter-spacing: 1px;
        }

        /* 使用伪元素创建立体效果的两个小三角 */
        .insideBox:before,
        .insideBox:after {
            content: "";
            border-top: 4px solid #4e7c7d;     /* 暗色边框营造立体感 */
            border-left: 4px solid transparent;
            border-right: 4px solid transparent;
            position: absolute;
            bottom: -4px;
        }

        /* 左侧小三角 */
        .insideBox:before {
            left: 0;
        }

        /* 右侧小三角 */
        .insideBox:after {
            right: 0;
        }
    </style>
</head>
<body>
    <!-- 主要结构 -->
    <div class="cornerMarkBox">
        <!-- 内容区域 -->
        <img style="width:auto;height:auto;max-width:100%;max-height: 100%" 
             src="https://preview.qiantucdn.com/58pic/44/05/54/47858PIC4pj2zTn5Dhzr6_PIC2018.png!w1024_new_0">
        
        <!-- 角标区域 -->
        <div class="MarkBox">
            <div class="insideBox">水香木鱼</div>
        </div>
    </div>
</body>
</html>

文字渐入动画效果 ​

一个优雅的文字动画效果,通过逐字延迟显示创造出流畅的渐入体验。适用于标题、提示文字等需要吸引注意力的场景。

实现原理 ​

  1. 使用 JavaScript 将文本拆分为单个字符
  2. 为每个字符添加延迟动画
  3. 利用 CSS custom properties 控制动画延迟

关键代码解析 ​

javascript
// 文本拆分处理
text.innerHTML = text.textContent
  .split('')
  .map(char => `<span class="letter">
    ${char === ' ' ? '&nbsp;' : char}
  </span>`)
  .join('');

// 设置动画延迟
letters.forEach((letter, index) => {
  letter.style.setProperty('--delay', `${index * 0.05}s`);
});

动画优化建议 ​

  • 使用 cubic-bezier 创建更自然的动画曲线
  • 控制合适的延迟时间间隔(建议 0.05s-0.08s)
  • 考虑添加 will-change 优化性能

性能注意事项 ​

  • 避免在过长文本中使用
  • 考虑使用 requestAnimationFrame 优化动画
  • 添加 transform 硬件加速

效果预览 ​

文字渐入动画效果

代码实现 ​

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文字渐入动画效果</title>
    <style>
        /* 容器样式 */
        .text-container {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            font-size: 24px;
        }

        /* 文字容器基础样式 */
        .generating-tip {
            position: relative;
            display: inline-block;
        }

        /* 每个字母的基础样式 */
        .letter {
            display: inline-block;
            opacity: 0; /* 初始设置为透明 */
        }

        /* 添加动画效果 */
        .letter.animate {
            /* 使用cubic-bezier创建弹跳效果 */
            animation: moveIn 1s cubic-bezier(0.89, 0.32, 0.84, 1.3) forwards;
            /* animation-delay 将由 JS 通过 --delay 变量设置 */
            animation-delay: var(--delay);
        }

        /* 定义动画关键帧 */
        @keyframes moveIn {
            from {
                opacity: 0;
                transform: translateY(-100%);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
    </style>
</head>
<body>
    <div class="text-container">
        <div class="generating-tip">Multiple views, please be patient.</div>
    </div>

    <script>
        // 等待DOM加载完成
        document.addEventListener('DOMContentLoaded', () => {
            const text = document.querySelector('.generating-tip');
            
            // 1. 将文本分割成单个字符并包装在span中
            text.innerHTML = text.textContent
                .split('')
                .map(char => `<span class="letter">${char === ' ' ? '&nbsp;' : char}</span>`)
                .join('');
            
            // 2. 为每个字母设置延迟时间
            const letters = document.querySelectorAll('.letter');
            letters.forEach((letter, index) => {
                // 设置每个字母的延迟时间,每个间隔50ms
                letter.style.setProperty('--delay', `${index * 0.05}s`);
                // 添加动画类
                letter.classList.add('animate');
            });
        });
    </script>
</body>
</html>

中间透明圆角渐变色边框的容器 ​

一个现代化的 UI 容器效果,结合了渐变边框、毛玻璃效果和圆角设计。适用于卡片、弹窗等需要突出视觉层次的界面元素。

实现要点 ​

  • 使用 backdrop-filter 实现毛玻璃效果
  • 通过 mask 属性创建中空边框
  • 利用 CSS 渐变实现边框颜色过渡

效果预览 ​

圆角渐变色边框

代码实现 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>透明渐变边框容器</title>
    <style>
        /* 创建一个深色背景以便更好地展示效果 */
        body {
            background: #1a1a1a;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
        }

        /* 主容器样式 */
        .box {
            width: 500px;
            height: 500px;
            border-radius: 16px;
            /* 添加毛玻璃效果 */
            backdrop-filter: blur(4px);
            padding: 0 min(1.32vw, 30px);
            /* 设置容器背景为半透明渐变 */
            background: linear-gradient(180deg, 
                rgba(0, 0, 0, 0.30) 0%, 
                rgba(0, 0, 0, 0.20) 100%
            );
            position: relative;

            /* 添加一些内容样式 */
            color: white;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 24px;
        }

        /* 渐变边框效果 */
        .box::before {
            /* 定义边框相关变量 */
            --border-width: 2px;
            --border-color: linear-gradient(
                10deg, 
                rgb(166, 36, 227) 0%,
                rgb(190, 160, 235) 45%, 
                rgb(190, 160, 235) 55%, 
                rgb(67, 0, 255) 100%
            );
            
            /* 绝对定位并居中 */
            position: absolute;
            content: '';
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            
            /* 设置尺寸和基础样式 */
            width: 100%;
            height: 100%;
            box-sizing: border-box;
            display: block;
            border-radius: inherit;
            padding: var(--border-width);
            
            /* 设置渐变背景 */
            background: var(--border-color);
            background-clip: padding-box;
            
            /* 关键:使用mask实现中间透明效果 */
            -webkit-mask-image: linear-gradient(red, red), linear-gradient(red, red);
            -webkit-mask-clip: padding-box, content-box;
            mask-composite: exclude;
            
            /* 将伪元素置于内容下方 */
            z-index: -10;
        }
    </style>
</head>
<body>
    <div class="box">
        渐变边框容器
    </div>
</body>
</html>

CSS圆形贴合裁剪效果 ​

效果介绍 ✨ ​

在现代网页设计中,我们经常需要实现一些独特的视觉效果。今天要介绍的是如何使用CSS实现两个元素之间的圆形贴合裁剪效果,这种效果常用于创建连接的标签、气泡对话框等设计元素。 圆形贴合裁剪效果

实现原理 💡 ​

这个效果主要通过以下几个关键技术点实现:

  1. 使用border-radius创建圆形元素
  2. 利用radial-gradient实现圆形裁剪效果
  3. 通过定位和z-index控制元素层级关系

代码实现 🔨 ​

html
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>圆形贴合裁剪效果</title>
  <style>
    body {
      padding: 10px;
    }

    .inversePair {
      border: 1px solid black;
      display: inline-block;
      position: relative;
      height: 100px;
      text-align: center;
      line-height: 100px;
      vertical-align: middle;
    }

    #a {
      width: 100px;
      border-radius: 50px;
      background: grey;
      z-index: 1;
    }

    #b {
      width: 200px;
      padding-left: 30px;
      margin-left: -30px;
      border-left: none;
      background-image: radial-gradient(
        circle closest-corner at -23px 50%, 
        transparent 0, 
        transparent 55px, 
        black 56px, 
        grey 57px
      );
    }
  </style>
</head>
<body>
  <div id="a" class="inversePair">A</div>
  <div id="b" class="inversePair">B</div>
</body>
</html>

关键点解析 🔍 ​

  1. 圆形元素A:

    • 使用border-radius: 50px创建圆形
    • 设置z-index: 1确保显示在上层
  2. 元素B的裁剪效果:

    • 使用radial-gradient创建径向渐变
    • -23px 50%定位渐变的中心点
    • circle closest-corner确定渐变的形状
    • 使用透明色和实色的过渡创建裁剪效果

浏览器兼容性 🌐 ​

为确保更好的兼容性,建议添加各种浏览器前缀:

  • -webkit-radial-gradient
  • -moz-radial-gradient
  • -ms-radial-gradient
  • -o-radial-gradient

使用场景 💼 ​

  1. 标签连接效果
  2. 气泡对话框
  3. 导航菜单设计
  4. 时间轴节点

注意事项 ⚠️ ​

  1. 确保两个元素的高度保持一致
  2. 注意调整间距和裁剪半径以获得最佳效果
  3. 在移动端需要注意响应式适配

跑马灯效果实现 ​

跑马灯(Marquee)是一种常见的UI效果,能够实现内容的水平滚动展示,适用于新闻通知、合作伙伴展示等场景。下面介绍三种实现方案,各有优缺点。

跑马灯效果

实现方案对比 ​

方案优点缺点适用场景
废弃的marquee标签实现简单已被W3C废弃,兼容性差仅作为了解,不推荐使用
绝对定位+动画延时精确控制每个元素实现复杂,需计算延时固定数量的元素循环滚动
双份元素循环动画实现简单,性能好需额外DOM元素大多数跑马灯场景的最佳选择

1. 废弃的 marquee 标签 ​

这是最早的跑马灯实现方式,虽然使用简单,但已被W3C标准废弃,现代浏览器可能不再支持。

html
<marquee behavior="scroll" direction="left">
  <div class="marquee-item"></div>
  <div class="marquee-item"></div>
  <div class="marquee-item"></div>
</marquee>

2. 通过绝对定位+动画延时 ​

这种方案通过精确计算每个元素的动画延时,实现无缝循环效果。

html
<div class="wrapper">
  <div class="item" style="--count: 1"></div>
  <div class="item" style="--count: 2"></div>
  <div class="item" style="--count: 3"></div>
  <!-- 更多元素... -->
</div>
css
.wrapper {
  --logo-width: 200px;
  --logo-height: 100px;
  --logo-count: 8;
  --duration: 30s;
  width: 90%;
  max-width: 1200px;
  margin-inline: auto;
  position: relative;
  height: var(--logo-height);
  overflow: hidden;
  /* 两侧渐隐效果 */
  mask-image: linear-gradient(
    to right,
    rgba(0, 0, 0, 0),
    rgba(0, 0, 0, 1) 20%,
    rgba(0, 0, 0, 1) 80%,
    rgba(0, 0, 0, 0)
  );
}

@keyframes scrollLeft {
  to {
    left: calc(var(--logo-width) * -1);
  }
}

.item {
  width: var(--logo-width);
  height: var(--logo-height);
  background-color: #3498db;
  border-radius: 6px;
  position: absolute;
  left: calc(var(--logo-width) * var(--logo-count));
  animation-name: scrollLeft;
  animation-duration: var(--duration);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  /* 关键点:动态计算每个元素的延时 */
  animation-delay: calc(var(--duration) / var(--logo-count) * (var(--logo-count) - var(--count)) * -1);
}

实现原理说明:

  1. 所有元素都是绝对定位,初始位置在容器右侧
  2. 通过 CSS 变量计算每个元素的动画延时
  3. 元素从右向左移动,当移出视口后,因为动画是无限循环的,会重新从右侧进入
  4. 通过 mask-image 创建两侧渐隐效果,提升视觉体验

3. 双份元素进行动画循环(✨推荐) ​

这是现代网页中最常用的跑马灯实现方式,原理简单且效果良好。

html
<div class="marquee-container">
  <!-- 第一组元素 -->
  <div class="marquee">
    <span>#CSS</span>
    <span>#HTML</span>
    <span>#JavaScript</span>
    <span>#SVG</span>
    <span>#React</span>
    <span>#Vue</span>
  </div>
  
  <!-- 第二组完全相同的元素 -->
  <div class="marquee">
    <span>#CSS</span>
    <span>#HTML</span>
    <span>#JavaScript</span>
    <span>#SVG</span>
    <span>#React</span>
    <span>#Vue</span>
  </div>
</div>
css
@keyframes marquee {
  to {
    transform: translateX(calc(-100% - var(--gap)));
  }
}

.marquee-container {
  --gap: 1rem;
  position: relative;
  display: flex;
  overflow: hidden;
  gap: var(--gap);
  /* 两侧渐隐效果 */
  mask: linear-gradient(90deg, transparent, #000 5% 95%, transparent);
  
  /* 可选:增加内边距,提升视觉效果 */
  padding-block: 1rem;
  background: #f8f9fa;
  border-radius: 8px;
}

.marquee {
  flex-shrink: 0;
  display: flex;
  justify-content: space-around;
  gap: var(--gap);
  min-width: 100%;
  
  /* 关键动画设置 */
  animation: marquee 20s linear infinite;
}

/* 鼠标悬停时暂停动画 */
.marquee-container:hover .marquee {
  animation-play-state: paused;
}

/* 元素样式 */
.marquee span {
  padding: 0.5rem 1rem;
  background: #e9ecef;
  border-radius: 4px;
  font-weight: bold;
  color: #495057;
}

实现原理说明:

  1. 创建两组完全相同的元素
  2. 将它们放在同一个容器中,水平排列
  3. 让整个容器向左移动一个组的宽度
  4. 由于有两组相同的元素,当第一组完全移出视口时,第二组刚好完全进入视口
  5. 动画无限循环,创造无缝滚动的效果

性能优化tips ​

  1. 使用 transform 而非 left/top 属性:transform 属性触发的是 GPU 加速,性能更好
  2. 使用 will-change: transform:提前告知浏览器元素将发生变化,优化渲染性能
  3. 设置合适的动画时长:太短的动画会显得急促,太长则缺乏视觉吸引力
  4. 考虑使用 requestAnimationFrame:对于复杂场景,可用JS控制动画,性能更优

响应式适配 ​

对于移动端,可以调整速度和元素大小:

css
@media (max-width: 768px) {
  .marquee-container {
    --gap: 0.5rem;
  }
  
  .marquee {
    animation-duration: 15s; /* 移动端屏幕小,适当加快速度 */
  }
  
  .marquee span {
    padding: 0.25rem 0.5rem;
    font-size: 0.875rem;
  }
}

完整实现代码 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>现代跑马灯效果</title>
  <style>
    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      padding: 2rem;
      max-width: 1200px;
      margin: 0 auto;
      background-color: #f5f5f5;
    }
    
    h2 {
      color: #333;
      margin-bottom: 1.5rem;
    }
    
    /* 跑马灯容器 */
    .marquee-container {
      --gap: 1rem;
      position: relative;
      display: flex;
      overflow: hidden;
      gap: var(--gap);
      border-radius: 8px;
      background: white;
      box-shadow: 0 4px 6px rgba(0,0,0,0.05);
      margin-bottom: 2rem;
      
      /* 两侧渐隐效果 */
      mask: linear-gradient(90deg, transparent, #000 5% 95%, transparent);
    }
    
    /* 跑马灯内容 */
    .marquee {
      flex-shrink: 0;
      display: flex;
      align-items: center;
      gap: var(--gap);
      min-width: 100%;
      padding: 1rem 0;
      
      /* 动画设置 */
      animation: marquee 25s linear infinite;
      will-change: transform;
    }
    
    /* 暂停效果 */
    .marquee-container:hover .marquee {
      animation-play-state: paused;
    }
    
    /* 动画关键帧 */
    @keyframes marquee {
      to {
        transform: translateX(calc(-100% - var(--gap)));
      }
    }
    
    /* 内容项样式 */
    .marquee__item {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 80px;
      padding: 0 1.5rem;
      background-color: #f8f9fa;
      border-radius: 8px;
      font-weight: 600;
      color: #444;
      box-shadow: 0 2px 4px rgba(0,0,0,0.04);
      transition: transform 0.3s, box-shadow 0.3s;
    }
    
    .marquee__item:hover {
      transform: translateY(-5px);
      box-shadow: 0 6px 12px rgba(0,0,0,0.08);
    }
    
    /* 响应式调整 */
    @media (max-width: 768px) {
      .marquee-container {
        --gap: 0.5rem;
      }
      
      .marquee {
        animation-duration: 20s;
      }
      
      .marquee__item {
        height: 60px;
        padding: 0 1rem;
        font-size: 0.875rem;
      }
    }
  </style>
</head>
<body>
  <h2>现代跑马灯效果</h2>
  
  <div class="marquee-container">
    <!-- 第一组元素 -->
    <div class="marquee">
      <div class="marquee__item">🎨 CSS</div>
      <div class="marquee__item">🌐 HTML</div>
      <div class="marquee__item">💻 JavaScript</div>
      <div class="marquee__item">⚛️ React</div>
      <div class="marquee__item">🖼️ SVG</div>
      <div class="marquee__item">📱 响应式设计</div>
      <div class="marquee__item">🔄 动画</div>
    </div>
    
    <!-- 第二组完全相同的元素 -->
    <div class="marquee">
      <div class="marquee__item">🎨 CSS</div>
      <div class="marquee__item">🌐 HTML</div>
      <div class="marquee__item">💻 JavaScript</div>
      <div class="marquee__item">⚛️ React</div>
      <div class="marquee__item">🖼️ SVG</div>
      <div class="marquee__item">📱 响应式设计</div>
      <div class="marquee__item">🔄 动画</div>
    </div>
  </div>
</body>
</html>