CSS实现跑马灯效果-案例

示例图

控制速度

设计思路

使用CSS动画和transform属性创建平滑的滚动效果,通过@keyframes控制动画过程,并利用:hover伪类实现悬停暂停功能。

代码

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS 跑马灯效果 - 完整实现与优化</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        :root {
            --primary-color: #4361ee;
            --secondary-color: #3a0ca3;
            --accent-color: #4cc9f0;
            --dark-color: #1a1a2e;
            --light-color: #f8f9fa;
            --success-color: #4caf50;
            --warning-color: #ff9800;
            --danger-color: #f44336;
            --animation-speed: 20s;
            --border-radius: 12px;
            --box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
            --transition: all 0.3s ease;
        }
        
        body {
            background: linear-gradient(135deg, var(--dark-color), var(--secondary-color));
            color: var(--light-color);
            min-height: 100vh;
            padding: 40px 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
            line-height: 1.6;
        }
        
        .container {
            max-width: 1200px;
            width: 100%;
            margin: 0 auto;
        }
        
        header {
            text-align: center;
            margin-bottom: 50px;
            padding: 30px;
            background: rgba(255, 255, 255, 0.05);
            border-radius: var(--border-radius);
            backdrop-filter: blur(10px);
            box-shadow: var(--box-shadow);
        }
        
        h1 {
            font-size: 3rem;
            margin-bottom: 15px;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
            background: linear-gradient(90deg, var(--accent-color), var(--primary-color));
            -webkit-background-clip: text;
            background-clip: text;
            color: transparent;
        }
        
        .subtitle {
            font-size: 1.2rem;
            color: rgba(255, 255, 255, 0.8);
            max-width: 800px;
            margin: 0 auto;
        }
        
        h2 {
            font-size: 1.8rem;
            margin: 40px 0 20px;
            color: var(--accent-color);
            text-align: center;
            position: relative;
            padding-bottom: 10px;
        }
        
        h2::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 100px;
            height: 3px;
            background: linear-gradient(90deg, transparent, var(--accent-color), transparent);
        }
        
        h3 {
            font-size: 1.5rem;
            margin: 25px 0 15px;
            color: var(--accent-color);
        }
        
        .section {
            margin-bottom: 60px;
        }
        
        .marquee-container {
            overflow: hidden;
            position: relative;
            padding: 25px 0;
            margin: 30px 0;
            background: rgba(255, 255, 255, 0.05);
            border-radius: var(--border-radius);
            box-shadow: var(--box-shadow);
            border: 1px solid rgba(255, 255, 255, 0.1);
        }
        
        .marquee-container::before, .marquee-container::after {
            content: '';
            position: absolute;
            top: 0;
            width: 100px;
            height: 100%;
            z-index: 2;
        }
        
        .marquee-container::before {
            left: 0;
            background: linear-gradient(90deg, rgba(26, 26, 46, 0.9), transparent);
        }
        
        .marquee-container::after {
            right: 0;
            background: linear-gradient(90deg, transparent, rgba(26, 26, 46, 0.9));
        }
        
        .marquee {
            display: flex;
            width: max-content;
            animation: marquee var(--animation-speed) linear infinite;
        }
        
        .marquee:hover {
            animation-play-state: paused;
        }
        
        .text-marquee {
            font-size: 2.5rem;
            font-weight: bold;
            white-space: nowrap;
        }
        
        .text-marquee span {
            padding: 0 30px;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
        }
        
        .text-marquee i {
            margin-right: 10px;
            color: var(--accent-color);
        }
        
        .image-marquee {
            display: flex;
        }
        
        .image-item {
            width: 200px;
            height: 150px;
            margin: 0 15px;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
            transition: var(--transition);
            position: relative;
        }
        
        .image-item:hover {
            transform: scale(1.05);
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.6);
        }
        
        .image-item img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }
        
        .mixed-marquee {
            display: flex;
        }
        
        .mixed-item {
            display: flex;
            align-items: center;
            margin: 0 20px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 10px;
            padding: 15px;
            min-width: 350px;
            transition: var(--transition);
        }
        
        .mixed-item:hover {
            background: rgba(255, 255, 255, 0.15);
            transform: translateY(-5px);
        }
        
        .mixed-icon {
            font-size: 2.5rem;
            margin-right: 15px;
            color: var(--accent-color);
        }
        
        .mixed-content {
            flex: 1;
        }
        
        .mixed-title {
            font-weight: bold;
            font-size: 1.2rem;
            margin-bottom: 5px;
        }
        
        .mixed-desc {
            font-size: 0.9rem;
            color: rgba(255, 255, 255, 0.7);
        }
        
        .marquee-reverse {
            animation-direction: reverse;
        }
        
        .marquee-fast {
            animation-duration: 15s;
        }
        
        .marquee-slow {
            animation-duration: 30s;
        }
        
        .controls {
            display: flex;
            justify-content: center;
            gap: 15px;
            margin: 20px 0;
            flex-wrap: wrap;
        }
        
        button {
            padding: 12px 25px;
            background: var(--primary-color);
            color: white;
            border: none;
            border-radius: 50px;
            font-weight: bold;
            cursor: pointer;
            transition: var(--transition);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        button:hover {
            background: var(--secondary-color);
            transform: translateY(-2px);
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
        }
        
        button.active {
            background: var(--accent-color);
            color: var(--dark-color);
        }
        
        .explanation {
            background: rgba(255, 255, 255, 0.05);
            padding: 30px;
            border-radius: var(--border-radius);
            margin: 30px 0;
            backdrop-filter: blur(5px);
            box-shadow: var(--box-shadow);
        }
        
        .code-example {
            background: rgba(0, 0, 0, 0.7);
            color: #fff;
            padding: 20px;
            border-radius: 10px;
            margin: 20px 0;
            font-family: 'Courier New', monospace;
            overflow-x: auto;
            position: relative;
            border-left: 4px solid var(--accent-color);
        }
        
        .code-example pre {
            margin: 0;
        }
        
        .code-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
        }
        
        .code-title {
            font-weight: bold;
            color: var(--accent-color);
        }
        
        .copy-btn {
            background: rgba(255, 255, 255, 0.1);
            color: white;
            border: none;
            padding: 5px 10px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 0.8rem;
            transition: var(--transition);
        }
        
        .copy-btn:hover {
            background: rgba(255, 255, 255, 0.2);
        }
        
        .note {
            background: rgba(76, 201, 240, 0.1);
            padding: 15px;
            border-radius: 8px;
            margin: 15px 0;
            border-left: 4px solid var(--accent-color);
        }
        
        .features {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin: 30px 0;
        }
        
        .feature-card {
            background: rgba(255, 255, 255, 0.05);
            padding: 25px;
            border-radius: var(--border-radius);
            text-align: center;
            transition: var(--transition);
            box-shadow: var(--box-shadow);
        }
        
        .feature-card:hover {
            transform: translateY(-5px);
            background: rgba(255, 255, 255, 0.08);
        }
        
        .feature-icon {
            font-size: 2.5rem;
            color: var(--accent-color);
            margin-bottom: 15px;
        }
        
        .feature-title {
            font-size: 1.3rem;
            margin-bottom: 10px;
            color: var(--accent-color);
        }
        
        .implementation-steps {
            margin: 30px 0;
        }
        
        .step {
            margin-bottom: 25px;
            padding: 20px;
            background: rgba(255, 255, 255, 0.05);
            border-radius: var(--border-radius);
        }
        
        .step-number {
            display: inline-block;
            width: 30px;
            height: 30px;
            background: var(--accent-color);
            color: var(--dark-color);
            border-radius: 50%;
            text-align: center;
            line-height: 30px;
            font-weight: bold;
            margin-right: 10px;
        }
        
        footer {
            margin-top: 60px;
            text-align: center;
            color: rgba(255, 255, 255, 0.7);
            font-size: 0.9rem;
            padding: 20px;
            border-top: 1px solid rgba(255, 255, 255, 0.1);
            width: 100%;
        }
        
        /* 动画定义 */
        @keyframes marquee {
            0% {
                transform: translateX(0);
            }
            100% {
                transform: translateX(-50%);
            }
        }
        
        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(20px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        
        .fade-in {
            animation: fadeIn 0.8s ease forwards;
        }
        
        /* 响应式设计 */
        @media (max-width: 768px) {
            h1 {
                font-size: 2.2rem;
            }
            
            .text-marquee {
                font-size: 1.8rem;
            }
            
            .image-item {
                width: 160px;
                height: 120px;
            }
            
            .mixed-item {
                min-width: 280px;
            }
            
            .features {
                grid-template-columns: 1fr;
            }
        }
        
        @media (max-width: 480px) {
            h1 {
                font-size: 1.8rem;
            }
            
            .text-marquee {
                font-size: 1.4rem;
            }
            
            .image-item {
                width: 120px;
                height: 90px;
            }
            
            .mixed-item {
                min-width: 220px;
                padding: 10px;
            }
            
            button {
                padding: 10px 20px;
                font-size: 0.9rem;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header class="fade-in">
            <h1>CSS 跑马灯效果</h1>
            <p class="subtitle">纯CSS实现的文字、图片和混合内容跑马灯,支持暂停、速度控制和多种动画效果</p>
        </header>
        
        <section class="section fade-in">
            <h2>文字跑马灯</h2>
            <div class="marquee-container">
                <div class="marquee text-marquee">
                    <span><i class="fas fa-star"></i> 欢迎来到CSS跑马灯世界!</span>
                    <span><i class="fas fa-code"></i> 纯CSS实现</span>
                    <span><i class="fas fa-bolt"></i> 无需JavaScript!</span>
                    <span><i class="fas fa-pause"></i> 可悬停暂停</span>
                    <span><i class="fas fa-star"></i> 欢迎来到CSS跑马灯世界!</span>
                    <span><i class="fas fa-code"></i> 纯CSS实现</span>
                    <span><i class="fas fa-bolt"></i> 无需JavaScript!</span>
                    <span><i class="fas fa-pause"></i> 可悬停暂停</span>
                </div>
            </div>
        </section>
        
        <section class="section fade-in">
            <h2>图片跑马灯</h2>
            <div class="marquee-container">
                <div class="marquee image-marquee">
                    <div class="image-item"><img src="https://picsum.photos/200/150?random=1" alt="示例图片"></div>
                    <div class="image-item"><img src="https://picsum.photos/200/150?random=2" alt="示例图片"></div>
                    <div class="image-item"><img src="https://picsum.photos/200/150?random=3" alt="示例图片"></div>
                    <div class="image-item"><img src="https://picsum.photos/200/150?random=4" alt="示例图片"></div>
                    <div class="image-item"><img src="https://picsum.photos/200/150?random=5" alt="示例图片"></div>
                    <div class="image-item"><img src="https://picsum.photos/200/150?random=6" alt="示例图片"></div>
                    <div class="image-item"><img src="https://picsum.photos/200/150?random=7" alt="示例图片"></div>
                    <div class="image-item"><img src="https://picsum.photos/200/150?random=8" alt="示例图片"></div>
                </div>
            </div>
        </section>
        
        <section class="section fade-in">
            <h2>混合内容跑马灯</h2>
            <div class="marquee-container">
                <div class="marquee mixed-marquee">
                    <div class="mixed-item">
                        <div class="mixed-icon"><i class="fas fa-palette"></i></div>
                        <div class="mixed-content">
                            <div class="mixed-title">CSS动画</div>
                            <div class="mixed-desc">使用@keyframes创建平滑动画效果</div>
                        </div>
                    </div>
                    <div class="mixed-item">
                        <div class="mixed-icon"><i class="fas fa-magic"></i></div>
                        <div class="mixed-content">
                            <div class="mixed-title">悬停暂停</div>
                            <div class="mixed-desc">鼠标悬停时动画暂停,提升交互体验</div>
                        </div>
                    </div>
                    <div class="mixed-item">
                        <div class="mixed-icon"><i class="fas fa-tachometer-alt"></i></div>
                        <div class="mixed-content">
                            <div class="mixed-title">速度控制</div>
                            <div class="mixed-desc">可调节动画速度,适应不同场景</div>
                        </div>
                    </div>
                    <div class="mixed-item">
                        <div class="mixed-icon"><i class="fas fa-sync-alt"></i></div>
                        <div class="mixed-content">
                            <div class="mixed-title">无缝循环</div>
                            <div class="mixed-desc">通过内容复制实现无缝滚动效果</div>
                        </div>
                    </div>
                    <div class="mixed-item">
                        <div class="mixed-icon"><i class="fas fa-palette"></i></div>
                        <div class="mixed-content">
                            <div class="mixed-title">CSS动画</div>
                            <div class="mixed-desc">使用@keyframes创建平滑动画效果</div>
                        </div>
                    </div>
                    <div class="mixed-item">
                        <div class="mixed-icon"><i class="fas fa-magic"></i></div>
                        <div class="mixed-content">
                            <div class="mixed-title">悬停暂停</div>
                            <div class="mixed-desc">鼠标悬停时动画暂停,提升交互体验</div>
                        </div>
                    </div>
                    <div class="mixed-item">
                        <div class="mixed-icon"><i class="fas fa-tachometer-alt"></i></div>
                        <div class="mixed-content">
                            <div class="mixed-title">速度控制</div>
                            <div class="mixed-desc">可调节动画速度,适应不同场景</div>
                        </div>
                    </div>
                    <div class="mixed-item">
                        <div class="mixed-icon"><i class="fas fa-sync-alt"></i></div>
                        <div class="mixed-content">
                            <div class="mixed-title">无缝循环</div>
                            <div class="mixed-desc">通过内容复制实现无缝滚动效果</div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
        
        <section class="section fade-in">
            <h2>反向跑马灯</h2>
            <div class="marquee-container">
                <div class="marquee text-marquee marquee-reverse">
                    <span><i class="fas fa-arrow-left"></i> 这个跑马灯是反向滚动的!</span>
                    <span><i class="fas fa-rocket"></i> CSS动画强大!</span>
                    <span><i class="fas fa-mouse-pointer"></i> 尝试悬停暂停效果</span>
                    <span><i class="fas fa-arrow-left"></i> 这个跑马灯是反向滚动的!</span>
                    <span><i class="fas fa-rocket"></i> CSS动画强大!</span>
                    <span><i class="fas fa-mouse-pointer"></i> 尝试悬停暂停效果</span>
                </div>
            </div>
        </section>
        
        <section class="section fade-in">
            <h2>速度控制</h2>
            <div class="controls">
                <button id="speed-fast" onclick="changeSpeed('fast')">
                    <i class="fas fa-tachometer-alt-fast"></i> 加速
                </button>
                <button id="speed-normal" onclick="changeSpeed('normal')" class="active">
                    <i class="fas fa-tachometer-alt"></i> 正常速度
                </button>
                <button id="speed-slow" onclick="changeSpeed('slow')">
                    <i class="fas fa-tachometer-alt-slow"></i> 减速
                </button>
                <button onclick="toggleAnimation()" id="toggle-btn">
                    <i class="fas fa-pause"></i> 暂停所有动画
                </button>
            </div>
        </section>
        
        <section class="section fade-in">
            <h2>核心特性</h2>
            <div class="features">
                <div class="feature-card">
                    <div class="feature-icon">
                        <i class="fas fa-code"></i>
                    </div>
                    <div class="feature-title">纯CSS实现</div>
                    <p>无需JavaScript,仅使用CSS动画和转换属性</p>
                </div>
                <div class="feature-card">
                    <div class="feature-icon">
                        <i class="fas fa-pause-circle"></i>
                    </div>
                    <div class="feature-title">悬停暂停</div>
                    <p>鼠标悬停时暂停动画,提供更好的交互体验</p>
                </div>
                <div class="feature-card">
                    <div class="feature-icon">
                        <i class="fas fa-tachometer-alt"></i>
                    </div>
                    <div class="feature-title">速度控制</div>
                    <p>可动态调整动画速度,适应不同需求</p>
                </div>
                <div class="feature-card">
                    <div class="feature-icon">
                        <i class="fas fa-mobile-alt"></i>
                    </div>
                    <div class="feature-title">响应式设计</div>
                    <p>适配各种屏幕尺寸,移动设备友好</p>
                </div>
            </div>
        </section>
        
        <section class="section fade-in">
            <h2>实现原理</h2>
            <div class="explanation">
                <p>CSS跑马灯使用<code>@keyframes</code>动画和<code>transform: translateX()</code>实现水平移动效果。</p>
                
                <div class="implementation-steps">
                    <h3>实现步骤</h3>
                    
                    <div class="step">
                        <div class="step-number">1</div>
                        <h3>创建动画关键帧</h3>
                        <p>使用@keyframes定义从0%到100%的动画过程,通过transform: translateX(-50%)实现元素向左移动50%的宽度。</p>
                        <div class="code-example">
                            <div class="code-header">
                                <div class="code-title">CSS 动画关键帧</div>
                                <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <pre><code>@keyframes marquee {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-50%);
  }
}</code></pre>
                        </div>
                    </div>
                    
                    <div class="step">
                        <div class="step-number">2</div>
                        <h3>应用动画到元素</h3>
                        <p>将动画应用到跑马灯元素,设置无限循环和线性时间函数。</p>
                        <div class="code-example">
                            <div class="code-header">
                                <div class="code-title">CSS 动画应用</div>
                                <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <pre><code>.marquee {
  display: flex;
  width: max-content;
  animation: marquee 20s linear infinite;
}</code></pre>
                        </div>
                    </div>
                    
                    <div class="step">
                        <div class="step-number">3</div>
                        <h3>实现悬停暂停</h3>
                        <p>通过:hover伪类和animation-play-state属性实现悬停时暂停动画。</p>
                        <div class="code-example">
                            <div class="code-header">
                                <div class="code-title">悬停暂停效果</div>
                                <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <pre><code>.marquee:hover {
  animation-play-state: paused;
}</code></pre>
                        </div>
                    </div>
                    
                    <div class="step">
                        <div class="step-number">4</div>
                        <h3>实现无缝滚动</h3>
                        <p>通过复制内容实现无缝滚动效果。当内容滚动到一半时,原始内容开始处刚好接上。</p>
                        <div class="code-example">
                            <div class="code-header">
                                <div class="code-title">HTML 结构示例</div>
                                <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                            </div>
                            <pre><code>&lt;div class="marquee"&gt;
  &lt;span&gt;内容1&lt;/span&gt;
  &lt;span&gt;内容2&lt;/span&gt;
  &lt;span&gt;内容3&lt;/span&gt;
  &lt;!-- 重复内容实现无缝滚动 --&gt;
  &lt;span&gt;内容1&lt;/span&gt;
  &lt;span&gt;内容2&lt;/span&gt;
  &lt;span&gt;内容3&lt;/span&gt;
&lt;/div&gt;</code></pre>
                        </div>
                    </div>
                </div>
                
                <div class="note">
                    <p><strong>技术要点:</strong> 为了实现无缝滚动,需要复制一份内容(或使内容足够长),这样当内容滚动到一半时,原始内容开始处刚好接上,形成无缝循环效果。</p>
                </div>
                
                <h3>JavaScript 控制功能</h3>
                <p>通过JavaScript动态修改CSS类来实现速度控制功能。</p>
                
                <div class="code-example">
                    <div class="code-header">
                        <div class="code-title">JavaScript 速度控制</div>
                        <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <pre><code>function changeSpeed(speed) {
  const marquees = document.querySelectorAll('.marquee');
  
  marquees.forEach(marquee => {
    marquee.classList.remove('marquee-fast', 'marquee-slow');
    
    if (speed === 'fast') {
      marquee.classList.add('marquee-fast');
    } else if (speed === 'slow') {
      marquees.classList.add('marquee-slow');
    }
  });
}</code></pre>
                </div>
                
                <div class="code-example">
                    <div class="code-header">
                        <div class="code-title">CSS 速度类定义</div>
                        <button class="copy-btn" onclick="copyCode(this)">复制代码</button>
                    </div>
                    <pre><code>.marquee-fast {
  animation-duration: 15s;
}

.marquee-slow {
  animation-duration: 30s;
}

.marquee-reverse {
  animation-direction: reverse;
}</code></pre>
                </div>
            </div>
        </section>
        
        <section class="section fade-in">
            <h2>应用场景</h2>
            <div class="explanation">
                <p>CSS跑马灯效果可以在多种场景下使用:</p>
                
                <div class="features">
                    <div class="feature-card">
                        <div class="feature-icon">
                            <i class="fas fa-newspaper"></i>
                        </div>
                        <div class="feature-title">新闻头条</div>
                        <p>用于展示重要新闻或公告,吸引用户注意力</p>
                    </div>
                    <div class="feature-card">
                        <div class="feature-icon">
                            <i class="fas fa-shopping-cart"></i>
                        </div>
                        <div class="feature-title">产品展示</div>
                        <p>在电商网站中展示热门产品或促销信息</p>
                    </div>
                    <div class="feature-card">
                        <div class="feature-icon">
                            <i class="fas fa-award"></i>
                        </div>
                        <div class="feature-title">荣誉展示</div>
                        <p>展示企业荣誉、合作伙伴或客户评价</p>
                    </div>
                    <div class="feature-card">
                        <div class="feature-icon">
                            <i class="fas fa-images"></i>
                        </div>
                        <div class="feature-title">图片画廊</div>
                        <p>创建动态图片展示效果,增强视觉吸引力</p>
                    </div>
                </div>
                
                <div class="note">
                    <p><strong>最佳实践:</strong> 在使用跑马灯效果时,确保内容简洁明了,滚动速度适中,避免给用户带来不适的体验。同时提供暂停功能,方便用户仔细阅读内容。</p>
                </div>
            </div>
        </section>
    </div>
    
    <footer>
        <p>CSS 跑马灯效果示例 &copy; 2023 | 使用纯CSS实现,无需JavaScript</p>
    </footer>

    <script>
        function changeSpeed(speed) {
            const marquees = document.querySelectorAll('.marquee');
            
            // 更新按钮状态
            document.getElementById('speed-fast').classList.remove('active');
            document.getElementById('speed-normal').classList.remove('active');
            document.getElementById('speed-slow').classList.remove('active');
            document.getElementById(`speed-${speed}`).classList.add('active');
            
            marquees.forEach(marquee => {
                marquee.classList.remove('marquee-fast', 'marquee-slow');
                
                if (speed === 'fast') {
                    marquee.classList.add('marquee-fast');
                } else if (speed === 'slow') {
                    marquee.classList.add('marquee-slow');
                }
            });
        }
        
        function toggleAnimation() {
            const marquees = document.querySelectorAll('.marquee');
            const button = document.getElementById('toggle-btn');
            const icon = button.querySelector('i');
            
            let isPaused = false;
            
            marquees.forEach(marquee => {
                if (marquee.style.animationPlayState === 'paused') {
                    marquee.style.animationPlayState = 'running';
                    icon.className = 'fas fa-pause';
                    button.innerHTML = '<i class="fas fa-pause"></i> 暂停所有动画';
                } else {
                    marquee.style.animationPlayState = 'paused';
                    icon.className = 'fas fa-play';
                    button.innerHTML = '<i class="fas fa-play"></i> 播放所有动画';
                    isPaused = true;
                }
            });
            
            if (isPaused) {
                button.innerHTML = '<i class="fas fa-play"></i> 播放所有动画';
            }
        }
        
        function copyCode(button) {
            const codeElement = button.closest('.code-example').querySelector('code');
            const textArea = document.createElement('textarea');
            textArea.value = codeElement.textContent;
            document.body.appendChild(textArea);
            textArea.select();
            document.execCommand('copy');
            document.body.removeChild(textArea);
            
            // 显示复制成功提示
            const originalText = button.textContent;
            button.textContent = '已复制!';
            setTimeout(() => {
                button.textContent = originalText;
            }, 2000);
        }
        
        // 添加滚动动画
        const observerOptions = {
            threshold: 0.1,
            rootMargin: '0px 0px -50px 0px'
        };
        
        const observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    entry.target.classList.add('fade-in');
                }
            });
        }, observerOptions);
        
        document.querySelectorAll('.section').forEach(section => {
            observer.observe(section);
        });
    </script>
</body>
</html>

实现原理

创建动画关键帧

使用@keyframes定义从0%到100%的动画过程,通过transform: translateX(-50%)实现元素向左移动50%的宽度。

css 复制代码
CSS 动画关键帧
@keyframes marquee {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-50%);
  }
}

应用动画到元素

将动画应用到跑马灯元素,设置无限循环和线性时间函数。

css 复制代码
.marquee {
  display: flex;
  width: max-content;
  animation: marquee 20s linear infinite;
}

实现悬停暂停

通过:hover伪类和animation-play-state属性实现悬停时暂停动画。

css 复制代码
.marquee:hover {
  animation-play-state: paused;
}

实现无缝滚动

通过复制内容实现无缝滚动效果。当内容滚动到一半时,原始内容开始处刚好接上。

css 复制代码
<div class="marquee">
  <span>内容1</span>
  <span>内容2</span>
  <span>内容3</span>
  <!-- 重复内容实现无缝滚动 -->
  <span>内容1</span>
  <span>内容2</span>
  <span>内容3</span>
</div>

技术要点: 为了实现无缝滚动,需要复制一份内容(或使内容足够长),这样当内容滚动到一半时,原始内容开始处刚好接上,形成无缝循环效果。

JavaScript 控制功能

通过JavaScript动态修改CSS类来实现速度控制功能。

javascript 复制代码
function changeSpeed(speed) {
  const marquees = document.querySelectorAll('.marquee');
  
  marquees.forEach(marquee => {
    marquee.classList.remove('marquee-fast', 'marquee-slow');
    
    if (speed === 'fast') {
      marquee.classList.add('marquee-fast');
    } else if (speed === 'slow') {
      marquees.classList.add('marquee-slow');
    }
  });
}

CSS 速度类定义

css 复制代码
.marquee-fast {
  animation-duration: 15s;
}

.marquee-slow {
  animation-duration: 30s;
}

.marquee-reverse {
  animation-direction: reverse;
}

使用到的技术点

1. CSS 动画技术

  • @keyframes 关键帧动画

    • 定义动画从0%到100%的过程

    • 使用transform: translateX(-50%)实现水平移动

  • animation 属性

    • animation: marquee 20s linear infinite - 设置动画名称、时长、时间函数和循环次数

    • animation-play-state: paused - 控制动画播放状态

    • animation-direction: reverse - 反向播放动画

2. CSS 布局技术

  • Flexbox 布局

    • display: flex - 创建弹性容器

    • width: max-content - 使容器宽度适应内容

  • CSS Grid 布局

    • 用于特性展示区域的响应式网格布局
  • 定位技术

    • position: relative/absolute - 相对和绝对定位

    • 伪元素(::before, ::after)创建渐变遮罩

3. 现代 CSS 特性

  • CSS 自定义属性 (CSS Variables)

    • 定义主题颜色、动画速度等可复用值
  • CSS 渐变

    • linear-gradient() - 创建背景渐变和文本渐变效果
  • backdrop-filter

    • 创建毛玻璃效果
  • object-fit

    • 控制图片在容器中的填充方式

4. 响应式设计

  • 媒体查询 (@media)

    • 针对不同屏幕尺寸调整样式
  • 相对单位

    • 使用rem、百分比等相对单位
  • flex-wrap

    • 控制元素在空间不足时的换行行为

5. JavaScript 交互

  • DOM 操作

    • querySelectorAll() - 选择多个元素

    • classList.add/remove() - 动态添加/移除CSS类

  • 事件处理

    • onclick - 按钮点击事件

    • onhover - 鼠标悬停事件(通过CSS实现)

  • Intersection Observer API

    • 实现滚动时的淡入动画效果

6. 视觉效果技术

  • transform 变换

    • scale() - 缩放效果

    • translateX/Y() - 平移效果

  • transition 过渡

    • 创建平滑的状态变化
  • box-shadow

    • 添加阴影效果增强立体感
  • text-shadow

    • 文字阴影效果

注意事项

1. 性能优化

  • 使用 transform 和 opacity

    • 这些属性不会触发重排,动画性能更好

    • 避免使用会触发重排的属性(如width、height、left、top)

  • 硬件加速

    • transform和opacity属性可以利用GPU加速
  • 动画复杂度

    • 保持动画简单,避免过多复杂的动画同时运行

2. 可访问性

  • 动画暂停功能

    • 必须提供暂停动画的方法(如悬停暂停)

    • 考虑前庭障碍用户,避免引起不适

  • 键盘导航

    • 确保所有功能可以通过键盘操作
  • 屏幕阅读器

    • 使用适当的ARIA标签和语义化HTML

3. 浏览器兼容性

  • 前缀使用

    • 某些CSS属性可能需要浏览器前缀(-webkit-, -moz-, -ms-)
  • 渐进增强

    • 在不支持某些特性的浏览器中提供降级方案
  • 功能检测

    • 使用@supports规则检测CSS特性支持

4. 用户体验

  • 动画速度

    • 速度不宜过快,确保内容可读

    • 提供速度调节选项

  • 暂停时机

    • 用户与内容交互时应暂停动画

    • 页面不可见时(如标签页切换)应暂停动画

  • 内容重要性

    • 跑马灯内容不应是关键信息,用户可能错过

5. 内容设计

  • 无缝循环

    • 确保内容复制足够形成无缝循环

    • 计算合适的动画时长和内容长度比例

  • 响应式内容

    • 在不同屏幕尺寸下调整内容大小和布局

    • 移动设备上可能需要简化内容

6. 代码维护

  • CSS 组织

    • 使用CSS变量统一管理颜色、尺寸等

    • 合理分组相关样式

  • 命名规范

    • 使用有意义的类名和ID

    • 遵循BEM或其他命名约定

  • 注释和文档

    • 为复杂代码添加详细注释

    • 提供使用说明和示例

7. 移动端优化

  • 触摸交互

    • 考虑触摸设备上的交互方式

    • 确保按钮和交互元素有足够的触摸目标大小

  • 性能考虑

    • 移动设备性能有限,优化动画复杂度

    • 考虑在低端设备上减少动画效果

8. 无障碍设计

  • 减少运动

    • 提供减少动画的选项(如通过 prefers-reduced-motion 媒体查询)
  • 焦点管理

    • 确保焦点在交互过程中正确移动
  • 语义化结构

    • 使用恰当的HTML标签传达内容结构

最佳实践总结

  1. 性能优先:优先使用transform和opacity实现动画

  2. 用户控制:始终提供暂停和速度控制选项

  3. 渐进增强:在不支持某些特性的浏览器中提供可用的降级方案

  4. 响应式设计:确保在所有设备上都有良好的体验

  5. 无障碍访问:考虑所有用户的需求,包括有特殊需求的用户

  6. 内容适宜:跑马灯适合展示非关键信息,重要内容应有静态展示方式


html 复制代码
伪代码
页面结构
<div class="image-marquee__group image-marquee__hover">
  {{#for _ in 1 | range(4)}}
  <div 
    style="--animation-time: {{block.settings.select_speed}}s;"
    class="image-marquee__item {{#if block.settings.select_direction == '1'}}image-marquee-reverse{{/if}}">
    <div 
      style="
        {{#if block.settings.switch_bgColor}}
        border-radius:{{block.settings.range_radius}}px;
        background-color:rgba({{block.settings.color_bgColor.red}},{{block.settings.color_bgColor.green}},{{block.settings.color_bgColor.blue}},{{block.settings.range_mask}}%);
        {{/if}}
      "
      class="image-marquee__text" >
      {{{block.settings.text}}}
    </div>

    <div 
      style="width: {{block.settings.range_height}}px;"
      class="image-marquee__image">
      {{#if block.settings.image}}
        {{#component "image" data=block.settings.image /}}
      {{#else/}}
        {{#placeholder_svg "image" class="empty-image-class" /}}
      {{/if}}
    </div>

    <div 
      style="
        {{#if block.settings.switch_bgColor}}
        border-radius:{{block.settings.range_radius}}px;
        background-color:rgba({{block.settings.color_bgColor.red}},{{block.settings.color_bgColor.green}},{{block.settings.color_bgColor.blue}},{{block.settings.range_mask}}%);
        {{/if}}
      "
      class="image-marquee__text">
      {{{block.settings.text}}}
    </div>

    <div 
      style="width: {{block.settings.range_height}}px;"
      class="image-marquee__image" 
      {{{block.shopline_attributes}}}>
      {{#if block.settings.image}}
        {{#component "image" data=block.settings.image /}}
      {{#else/}}
        {{#placeholder_svg "image" class="empty-image-class" /}}
      {{/if}}
    </div>
  </div>
  {{/for}}
</div>


样式动画
.image-marquee-wrap {
  display: flex;
  align-items: center;
  overflow: hidden;
  width: 100%;
}

.image-marquee__group{
  font-size: 36px;
  font-weight: bold;
  color: #232833;
  width: max-content;
  display: flex;
  align-items: center;

}

.image-marquee__item{
  display: flex;
  align-items: center;
  white-space: nowrap;
  width: fit-content;
  // 动画
  animation: move var(--animation-time) linear infinite;
}

.image-marquee__text{
  color: rgb(var(--color-text));
}
// 反向
.image-marquee-reverse {
  animation-direction: reverse;
}
// 暂停
.image-marquee__hover:hover .image-marquee__item{
  animation-play-state: paused;
}

@keyframes move {
  /* 0% {
      transform: translateZ(0)
  }
  to {
      transform: translate3d(-100%,0,0)
  } */
  0% {
      transform: translateX(0);
  }
  100% {
      transform: translateX(-50%);
  }
}
相关推荐
羽沢312 小时前
Vue3组件间通信——pinia
前端·javascript·vue.js
BBB努力学习程序设计2 小时前
简易横向导航制作指南
前端·html
BBB努力学习程序设计2 小时前
深入理解CSS定位叠放次序:z-index完全指南
前端·html
头疼8462 小时前
vue 组件实现 、background-hover随鼠标丝滑移动~
前端
焦糖小布丁3 小时前
加http和https访问的网站不同?
前端
人工智能的苟富贵3 小时前
用 Rust 写一个前端项目辅助工具:JSON 格式化器
前端·rust·json
季春二九3 小时前
Edge 卸载工具 | 版本号1.0 | 专为彻底卸载Microsoft Edge设计
前端·microsoft·edge·edge 卸载工具
雨过天晴而后无语3 小时前
HTML中JS监听输入框值的即时变化
前端·javascript·html
座山雕~3 小时前
html 和css基础常用的标签和样式(2)-css
前端·css·html