Skip to content

28. CSS+JS结合实战(衔接JS教程,实现交互效果)

28.1 点击切换主题色(CSS变量+JS事件)

功能说明

创建一个可以通过按钮点击切换主题色的页面,使用CSS变量存储主题颜色,通过JavaScript修改变量值实现主题切换。

实现代码

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>
        /* 定义CSS变量 */
        :root {
            --primary-color: #3498db;
            --secondary-color: #2ecc71;
            --background-color: #f5f5f5;
            --text-color: #333;
            --card-background: white;
        }

        /* 深色主题 */
        .dark-theme {
            --primary-color: #9b59b6;
            --secondary-color: #e74c3c;
            --background-color: #2c3e50;
            --text-color: #ecf0f1;
            --card-background: #34495e;
        }

        /* 全局样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            line-height: 1.6;
            background-color: var(--background-color);
            color: var(--text-color);
            transition: all 0.3s ease;
        }

        /* 容器 */
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 2rem;
        }

        /* 头部 */
        .header {
            text-align: center;
            margin-bottom: 3rem;
        }

        .header h1 {
            color: var(--primary-color);
            margin-bottom: 1rem;
        }

        /* 主题切换按钮 */
        .theme-toggle {
            display: flex;
            justify-content: center;
            margin-bottom: 3rem;
        }

        .theme-btn {
            padding: 0.8rem 1.5rem;
            margin: 0 0.5rem;
            border: none;
            border-radius: 4px;
            background-color: var(--primary-color);
            color: white;
            font-weight: bold;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .theme-btn:hover {
            background-color: var(--secondary-color);
        }

        /* 卡片 */
        .cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 2rem;
        }

        .card {
            background-color: var(--card-background);
            padding: 2rem;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
        }

        .card h2 {
            color: var(--primary-color);
            margin-bottom: 1rem;
        }

        .card p {
            margin-bottom: 1rem;
        }

        /* 按钮 */
        .btn {
            display: inline-block;
            padding: 0.5rem 1rem;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 4px;
            text-decoration: none;
            transition: background-color 0.3s ease;
        }

        .btn:hover {
            background-color: var(--secondary-color);
        }
    </style>
</head>
<body>
    <div class="container">
        <!-- 头部 -->
        <header class="header">
            <h1>主题切换示例</h1>
            <p>点击按钮切换不同主题</p>
        </header>

        <!-- 主题切换按钮 -->
        <div class="theme-toggle">
            <button class="theme-btn" data-theme="light">浅色主题</button>
            <button class="theme-btn" data-theme="dark">深色主题</button>
        </div>

        <!-- 卡片 -->
        <div class="cards">
            <div class="card">
                <h2>卡片 1</h2>
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                <a href="#" class="btn">了解更多</a>
            </div>
            <div class="card">
                <h2>卡片 2</h2>
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                <a href="#" class="btn">了解更多</a>
            </div>
            <div class="card">
                <h2>卡片 3</h2>
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                <a href="#" class="btn">了解更多</a>
            </div>
        </div>
    </div>

    <script>
        // 主题切换功能
        document.querySelectorAll('.theme-btn').forEach(button => {
            button.addEventListener('click', () => {
                const theme = button.getAttribute('data-theme');
                
                if (theme === 'dark') {
                    document.body.classList.add('dark-theme');
                } else {
                    document.body.classList.remove('dark-theme');
                }
            });
        });
    </script>
</body>
</html>

核心知识点

  • CSS变量:使用--变量名定义变量,通过var(--变量名)使用变量
  • 主题切换:通过添加/移除CSS类来改变变量值
  • JavaScript事件:使用addEventListener监听按钮点击事件
  • 过渡:使用transition实现平滑的主题切换效果
  • 响应式设计:使用grid-template-columns实现卡片的响应式布局

28.2 鼠标悬浮显示隐藏内容(CSS过渡+JS事件)

功能说明

创建一个鼠标悬浮时显示更多内容的卡片,使用CSS过渡实现平滑的显示效果,结合JavaScript实现更复杂的交互。

实现代码

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>
        /* 全局样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            line-height: 1.6;
            background-color: #f5f5f5;
            color: #333;
        }

        /* 容器 */
        .container {
            max-width: 1200px;
            margin: 2rem auto;
            padding: 0 1rem;
        }

        /* 卡片网格 */
        .card-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 2rem;
        }

        /* 卡片 */
        .card {
            background-color: white;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            cursor: pointer;
        }

        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);
        }

        /* 卡片图片 */
        .card-image {
            width: 100%;
            height: 200px;
            background-color: #3498db;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 3rem;
            color: white;
        }

        /* 卡片内容 */
        .card-content {
            padding: 1.5rem;
        }

        .card-title {
            font-size: 1.2rem;
            font-weight: bold;
            margin-bottom: 0.5rem;
        }

        .card-excerpt {
            color: #666;
            margin-bottom: 1rem;
        }

        /* 隐藏内容 */
        .card-details {
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.3s ease;
            color: #666;
        }

        .card-details.show {
            max-height: 200px;
        }

        /* 显示/隐藏按钮 */
        .toggle-btn {
            background: none;
            border: none;
            color: #3498db;
            cursor: pointer;
            font-weight: bold;
            margin-top: 1rem;
            padding: 0;
        }

        .toggle-btn:hover {
            text-decoration: underline;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 style="text-align: center; margin-bottom: 2rem;">悬浮显示内容示例</h1>
        
        <div class="card-grid">
            <div class="card">
                <div class="card-image">📝</div>
                <div class="card-content">
                    <h3 class="card-title">文章标题 1</h3>
                    <p class="card-excerpt">这是文章的简短描述,鼠标悬浮或点击按钮查看更多内容。</p>
                    <div class="card-details">
                        <p>这是文章的详细内容,包含更多信息和细节。Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                        <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                    </div>
                    <button class="toggle-btn">查看更多</button>
                </div>
            </div>
            
            <div class="card">
                <div class="card-image">💻</div>
                <div class="card-content">
                    <h3 class="card-title">文章标题 2</h3>
                    <p class="card-excerpt">这是文章的简短描述,鼠标悬浮或点击按钮查看更多内容。</p>
                    <div class="card-details">
                        <p>这是文章的详细内容,包含更多信息和细节。Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                        <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                    </div>
                    <button class="toggle-btn">查看更多</button>
                </div>
            </div>
            
            <div class="card">
                <div class="card-image">🎨</div>
                <div class="card-content">
                    <h3 class="card-title">文章标题 3</h3>
                    <p class="card-excerpt">这是文章的简短描述,鼠标悬浮或点击按钮查看更多内容。</p>
                    <div class="card-details">
                        <p>这是文章的详细内容,包含更多信息和细节。Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                        <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
                    </div>
                    <button class="toggle-btn">查看更多</button>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 点击按钮显示/隐藏内容
        document.querySelectorAll('.toggle-btn').forEach(button => {
            button.addEventListener('click', function() {
                const details = this.previousElementSibling;
                details.classList.toggle('show');
                
                // 切换按钮文本
                if (details.classList.contains('show')) {
                    this.textContent = '收起';
                } else {
                    this.textContent = '查看更多';
                }
            });
        });

        // 鼠标悬浮显示内容(可选)
        document.querySelectorAll('.card').forEach(card => {
            card.addEventListener('mouseenter', function() {
                const details = this.querySelector('.card-details');
                if (!details.classList.contains('show')) {
                    details.style.maxHeight = '200px';
                }
            });
            
            card.addEventListener('mouseleave', function() {
                const details = this.querySelector('.card-details');
                if (!details.classList.contains('show')) {
                    details.style.maxHeight = '0';
                }
            });
        });
    </script>
</body>
</html>

核心知识点

  • CSS过渡:使用transition实现内容的平滑显示/隐藏
  • JavaScript事件:使用addEventListener监听点击和鼠标事件
  • DOM操作:使用classList.toggle和style属性修改元素状态
  • 响应式设计:使用grid-template-columns实现卡片的响应式布局
  • 悬停效果:使用:hover伪类实现卡片的悬停动画

28.3 滚动页面导航栏变化(CSS定位+JS滚动事件)

功能说明

创建一个滚动时会变化的导航栏,当页面滚动到一定位置时,导航栏会改变样式(如背景色、高度等)。

实现代码

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>
        /* 全局样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            line-height: 1.6;
            color: #333;
            height: 2000px; /* 为了测试滚动效果 */
        }

        /* 导航栏 */
        .navbar {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            background-color: transparent;
            color: white;
            padding: 1.5rem;
            transition: all 0.3s ease;
            z-index: 1000;
        }

        .navbar.scrolled {
            background-color: white;
            color: #333;
            padding: 1rem;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }

        .navbar-container {
            max-width: 1200px;
            margin: 0 auto;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .navbar-brand {
            font-size: 1.5rem;
            font-weight: bold;
        }

        .navbar-links {
            display: flex;
            gap: 1.5rem;
        }

        .navbar-links a {
            color: inherit;
            text-decoration: none;
            transition: color 0.3s ease;
        }

        .navbar-links a:hover {
            color: #3498db;
        }

        /* 英雄区域 */
        .hero {
            height: 100vh;
            background: linear-gradient(135deg, #3498db, #2ecc71);
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            text-align: center;
        }

        .hero h1 {
            font-size: 3rem;
            margin-bottom: 1rem;
        }

        .hero p {
            font-size: 1.2rem;
            margin-bottom: 2rem;
        }

        /* 内容区域 */
        .content {
            max-width: 1200px;
            margin: 2rem auto;
            padding: 0 1rem;
        }

        .content h2 {
            margin-bottom: 1rem;
        }

        .content p {
            margin-bottom: 1rem;
        }
    </style>
</head>
<body>
    <!-- 导航栏 -->
    <nav class="navbar" id="navbar">
        <div class="navbar-container">
            <div class="navbar-brand">MyWebsite</div>
            <div class="navbar-links">
                <a href="#">首页</a>
                <a href="#">关于</a>
                <a href="#">服务</a>
                <a href="#">联系</a>
            </div>
        </div>
    </nav>

    <!-- 英雄区域 -->
    <section class="hero">
        <div>
            <h1>欢迎来到我的网站</h1>
            <p>滚动页面查看导航栏变化效果</p>
        </div>
    </section>

    <!-- 内容区域 -->
    <section class="content">
        <h2>内容区域</h2>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
        <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
        <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
        <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    </section>

    <script>
        // 滚动事件监听
        window.addEventListener('scroll', function() {
            const navbar = document.getElementById('navbar');
            
            if (window.scrollY > 100) {
                navbar.classList.add('scrolled');
            } else {
                navbar.classList.remove('scrolled');
            }
        });
    </script>
</body>
</html>

核心知识点

  • CSS定位:使用position: fixed固定导航栏
  • JavaScript滚动事件:使用addEventListener监听scroll事件
  • DOM操作:使用classList.add和classList.remove修改导航栏样式
  • 过渡:使用transition实现导航栏样式的平滑变化
  • 响应式设计:使用flex布局实现导航栏的响应式布局

28.4 表单验证样式切换(CSS伪类+JS表单验证)

功能说明

创建一个带有实时验证的表单,当用户输入时,根据输入内容的有效性切换不同的样式状态。

实现代码

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>
        /* 全局样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            line-height: 1.6;
            background-color: #f5f5f5;
            color: #333;
        }

        /* 容器 */
        .container {
            max-width: 600px;
            margin: 2rem auto;
            padding: 2rem;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }

        /* 标题 */
        h1 {
            text-align: center;
            margin-bottom: 2rem;
            color: #3498db;
        }

        /* 表单 */
        .form {
            display: flex;
            flex-direction: column;
            gap: 1.5rem;
        }

        /* 表单组 */
        .form-group {
            position: relative;
        }

        .form-group label {
            display: block;
            margin-bottom: 0.5rem;
            font-weight: bold;
        }

        /* 输入框 */
        .form-group input {
            width: 100%;
            padding: 0.8rem;
            border: 2px solid #ddd;
            border-radius: 4px;
            font-size: 1rem;
            transition: border-color 0.3s ease;
        }

        /* 输入框聚焦 */
        .form-group input:focus {
            outline: none;
            border-color: #3498db;
        }

        /* 输入框有效状态 */
        .form-group input.valid {
            border-color: #2ecc71;
        }

        /* 输入框无效状态 */
        .form-group input.invalid {
            border-color: #e74c3c;
        }

        /* 错误信息 */
        .error-message {
            color: #e74c3c;
            font-size: 0.8rem;
            margin-top: 0.5rem;
            display: none;
        }

        .error-message.show {
            display: block;
        }

        /* 提交按钮 */
        .btn-submit {
            padding: 0.8rem;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 1rem;
            font-weight: bold;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .btn-submit:hover {
            background-color: #2980b9;
        }

        .btn-submit:disabled {
            background-color: #bdc3c7;
            cursor: not-allowed;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>表单验证示例</h1>
        <form class="form" id="validationForm">
            <!-- 用户名 -->
            <div class="form-group">
                <label for="username">用户名</label>
                <input type="text" id="username" placeholder="请输入用户名">
                <div class="error-message" id="usernameError">用户名至少需要3个字符</div>
            </div>
            
            <!-- 邮箱 -->
            <div class="form-group">
                <label for="email">邮箱</label>
                <input type="email" id="email" placeholder="请输入邮箱">
                <div class="error-message" id="emailError">请输入有效的邮箱地址</div>
            </div>
            
            <!-- 密码 -->
            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" id="password" placeholder="请输入密码">
                <div class="error-message" id="passwordError">密码至少需要6个字符</div>
            </div>
            
            <!-- 确认密码 -->
            <div class="form-group">
                <label for="confirmPassword">确认密码</label>
                <input type="password" id="confirmPassword" placeholder="请确认密码">
                <div class="error-message" id="confirmPasswordError">两次输入的密码不一致</div>
            </div>
            
            <button type="submit" class="btn-submit" id="submitBtn" disabled>提交</button>
        </form>
    </div>

    <script>
        // 表单验证逻辑
        const form = document.getElementById('validationForm');
        const username = document.getElementById('username');
        const email = document.getElementById('email');
        const password = document.getElementById('password');
        const confirmPassword = document.getElementById('confirmPassword');
        const submitBtn = document.getElementById('submitBtn');

        // 验证函数
        function validateField(field, errorElement, validationFunction) {
            if (validationFunction(field.value)) {
                field.classList.remove('invalid');
                field.classList.add('valid');
                errorElement.classList.remove('show');
                return true;
            } else {
                field.classList.remove('valid');
                field.classList.add('invalid');
                errorElement.classList.add('show');
                return false;
            }
        }

        // 验证用户名
        function validateUsername(value) {
            return value.length >= 3;
        }

        // 验证邮箱
        function validateEmail(value) {
            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            return emailRegex.test(value);
        }

        // 验证密码
        function validatePassword(value) {
            return value.length >= 6;
        }

        // 验证确认密码
        function validateConfirmPassword(value) {
            return value === password.value;
        }

        // 验证所有字段
        function validateAllFields() {
            const isUsernameValid = validateField(username, document.getElementById('usernameError'), validateUsername);
            const isEmailValid = validateField(email, document.getElementById('emailError'), validateEmail);
            const isPasswordValid = validateField(password, document.getElementById('passwordError'), validatePassword);
            const isConfirmPasswordValid = validateField(confirmPassword, document.getElementById('confirmPasswordError'), validateConfirmPassword);

            // 启用/禁用提交按钮
            submitBtn.disabled = !(isUsernameValid && isEmailValid && isPasswordValid && isConfirmPasswordValid);
        }

        // 添加事件监听器
        username.addEventListener('input', validateAllFields);
        email.addEventListener('input', validateAllFields);
        password.addEventListener('input', validateAllFields);
        confirmPassword.addEventListener('input', validateAllFields);

        // 表单提交
        form.addEventListener('submit', function(e) {
            e.preventDefault();
            if (!submitBtn.disabled) {
                alert('表单提交成功!');
            }
        });
    </script>
</body>
</html>

核心知识点

  • CSS伪类:使用:focus、:valid、:invalid等伪类实现表单状态样式
  • JavaScript表单验证:使用正则表达式和条件判断验证输入内容
  • DOM操作:使用classList.add和classList.remove修改输入框样式
  • 事件监听:使用addEventListener监听输入事件
  • 过渡:使用transition实现输入框边框颜色的平滑变化
  • 表单提交:使用preventDefault阻止表单默认提交行为

© 2026 编程马·菜鸟教程 版权所有