CSS 实战项目

学了 12 篇基础,是时候把它们串起来做点真东西了。这一章给三个完整、可直接保存成 .html 双击运行的项目——响应式个人主页、动画合集、组件库,每个都从需求出发,给出完整 HTML + CSS 和要点讲解。三个项目分别覆盖 CSS 最核心的三类任务:布局(Flex + Grid + 媒体查询)、动效(transition + keyframes + transform)、工程化(变量 + BEM + 可复用)。建议你把代码复制下来亲手跑一遍,改改颜色、间距、断点,看着效果变化——CSS 是"调"出来的,光看不练永远学不会。

实战 1:响应式个人主页(Flexbox + Grid + 媒体查询)

需求:做一个简洁的个人主页——顶部导航栏 + 主体卡片网格。要求三种屏幕都好看:桌面 3 列、平板 2 列、手机 1 列;手机端导航还要纵向堆叠。一个 HTML 文件搞定,不依赖任何框架。

涉及知识:Flexbox 一维布局(justify-content / align-items)、Grid 二维布局(grid-template-columns + repeat)、媒体查询 @media、box-sizing、视口 meta、盒阴影 box-shadow。

<!-- 响应式个人主页:Flexbox 顶栏 + Grid 卡片网格 + 媒体查询适配 -->
<!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>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: -apple-system, "PingFang SC", sans-serif;
           color: #333; background: #f5f7fa; }

    /* 顶部导航:Flexbox 横向布局,两端对齐 */
    .header {
      display: flex;
      justify-content: space-between;   /* logo 左、导航右 */
      align-items: center;              /* 垂直居中 */
      padding: 16px 32px;
      background: #4f8cff;
      color: #fff;
    }
    .nav { display: flex; gap: 24px; }
    .nav a { color: #fff; text-decoration: none; font-size: 14px; }
    .nav a:hover { text-decoration: underline; }

    /* 主体:Grid 自适应卡片网格 */
    .main { max-width: 960px; margin: 32px auto; padding: 0 16px; }
    .cards {
      display: grid;
      grid-template-columns: repeat(3, 1fr);   /* 默认 3 列等宽 */
      gap: 20px;
    }
    .card {
      background: #fff;
      border: 1px solid #eee;
      border-radius: 10px;
      padding: 20px;
      box-shadow: 0 2px 8px rgba(0,0,0,.06);
    }
    .card h3 { margin-bottom: 8px; color: #4f8cff; }
    .card p  { color: #666; line-height: 1.6; font-size: 14px; }

    /* 平板:2 列,顶栏纵向堆叠 */
    @media (max-width: 768px) {
      .cards { grid-template-columns: repeat(2, 1fr); }
      .header { flex-direction: column; gap: 8px; }
    }
    /* 手机:1 列,导航纵向居中 */
    @media (max-width: 480px) {
      .cards { grid-template-columns: 1fr; }
      .nav { flex-direction: column; align-items: center; gap: 6px; }
    }
  </style>
</head>
<body>
  <header class="header">
    <h1>我的主页</h1>
    <nav class="nav">
      <a href="#">首页</a>
      <a href="#">文章</a>
      <a href="#">关于</a>
      <a href="#">联系</a>
    </nav>
  </header>

  <main class="main">
    <section class="cards">
      <div class="card"><h3>文章 1</h3><p>Vue 3 Composition API 入门要点。</p></div>
      <div class="card"><h3>文章 2</h3><p>CSS Grid 实战布局技巧。</p></div>
      <div class="card"><h3>文章 3</h3><p>SQL 索引与慢查询优化。</p></div>
      <div class="card"><h3>文章 4</h3><p>Python 自动化脚本分享。</p></div>
      <div class="card"><h3>文章 5</h3><p>前端构建工具横向对比。</p></div>
      <div class="card"><h3>文章 6</h3><p>设计模式在前端的应用。</p></div>
    </section>
  </main>
</body>
</html>

要点讲解:

实战 2:CSS 动画合集(transition + @keyframes + transform)

需求:做一个动画演示页,集中展示五类常用动效——悬停过渡(按钮变色上浮)、循环旋转(加载转圈)、入场淡入(元素从下方淡入)、3D 翻转(卡片翻面)、弹跳循环(球弹跳)。看完这一页,日常 80% 的动画需求都能覆盖。

涉及知识:transition(属性过渡)、@keyframes(关键帧定义)、animation(动画应用)、transform(变换)、opacity、perspective + preserve-3d + backface-visibility(3D 翻转三件套)、infinite / both 等动画选项。

<!-- CSS 动画合集:transition / @keyframes / transform / hover 交互 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>CSS 动画合集</title>
  <style>
    body { font-family: sans-serif; padding: 40px; background: #f5f7fa; }
    section { margin-bottom: 32px; }
    h2 { margin-bottom: 12px; color: #333; }

    /* 1. transition:状态过渡(按钮 hover 变色 + 上浮) */
    .btn {
      padding: 10px 20px;
      background: #4f8cff; color: #fff; border: none;
      border-radius: 6px; cursor: pointer; font-size: 14px;
      transition: background .3s, transform .3s;   /* 哪些属性过渡、多久 */
    }
    .btn:hover {
      background: #3a78e0;
      transform: translateY(-2px);                 /* 鼠标移上轻微上浮 */
    }

    /* 2. @keyframes:循环动画(加载转圈指示器) */
    @keyframes spin {
      from { transform: rotate(0deg); }
      to   { transform: rotate(360deg); }
    }
    .loader {
      width: 36px; height: 36px;
      border: 4px solid #ddd;
      border-top-color: #4f8cff;                   /* 只染顶边 = 旋转的圈 */
      border-radius: 50%;
      animation: spin 1s linear infinite;          /* 1 秒一圈,匀速,无限循环 */
    }

    /* 3. @keyframes:渐入动画(元素淡入 + 上移) */
    @keyframes fadeInUp {
      from { opacity: 0; transform: translateY(20px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    .fade-in { animation: fadeInUp .8s ease-out both; }
    /* both = 动画前后都保持关键帧状态(避免结束后跳回初始) */

    /* 4. transform + transition:3D 翻转卡片 */
    .flip-card { width: 160px; height: 100px; perspective: 800px; }
    .flip-inner {
      position: relative; width: 100%; height: 100%;
      transition: transform .6s;
      transform-style: preserve-3d;               /* 子元素保持 3D 位置 */
    }
    .flip-card:hover .flip-inner { transform: rotateY(180deg); }
    .flip-front, .flip-back {
      position: absolute; width: 100%; height: 100%;
      backface-visibility: hidden;                /* 背面不可见,实现翻转效果 */
      border-radius: 8px;
      display: flex; align-items: center; justify-content: center;
      color: #fff; font-weight: bold;
    }
    .flip-front { background: #4f8cff; }
    .flip-back  { background: #42b883; transform: rotateY(180deg); }

    /* 5. hover 弹跳:用 keyframes 配合 hover 触发 */
    @keyframes bounce {
      0%, 100% { transform: translateY(0); }
      50%      { transform: translateY(-12px); }
    }
    .ball {
      width: 40px; height: 40px; border-radius: 50%;
      background: #e74c3c;
    }
    .ball:hover { animation: bounce .5s ease infinite; }
  </style>
</head>
<body>
  <section>
    <h2>1. 按钮 hover 过渡</h2>
    <button class="btn">悬停看我变色上浮</button>
  </section>

  <section>
    <h2>2. 加载转圈</h2>
    <div class="loader"></div>
  </section>

  <section>
    <h2>3. 淡入动画(刷新页面可见)</h2>
    <div class="fade-in">我是一段淡入显示的文字</div>
  </section>

  <section>
    <h2>4. 翻转卡片(悬停)</h2>
    <div class="flip-card">
      <div class="flip-inner">
        <div class="flip-front">正面</div>
        <div class="flip-back">背面</div>
      </div>
    </div>
  </section>

  <section>
    <h2>5. 弹跳球(悬停)</h2>
    <div class="ball"></div>
  </section>
</body>
</html>

要点讲解:

实战 3:组件库实战(CSS 变量 + BEM + 可复用)

需求:用纯 CSS 实现一套迷你组件库——按钮(多种颜色 + 尺寸)、卡片(图片 + 正文 + 操作栏)、导航(品牌名 + 菜单 + 选中态)。所有配色、间距、圆角都抽成CSS 变量(design token),命名一律用 BEM 规范,改一处全站生效。

涉及知识::root + --var 定义设计 token、var(--name) 引用、BEM(block__element--modifier)命名、修饰符组合复用、transition 配合 token、组件结构语义化。

<!-- 组件库实战:按钮/卡片/导航,用 CSS 变量 + BEM 命名 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>CSS 组件库</title>
  <style>
    /* === 设计 token:全站配色/间距/圆角的"单一真相源" === */
    /* 改这里一处,全站所有组件自动跟着变 */
    :root {
      --color-primary:      #4f8cff;
      --color-primary-dark: #3a78e0;
      --color-danger:       #e74c3c;
      --color-success:      #42b883;
      --color-text:         #333;
      --color-text-light:   #666;
      --color-bg:           #fff;
      --color-border:       #e5e7eb;
      --radius:             8px;
      --space:              16px;
      --shadow:             0 2px 8px rgba(0,0,0,.08);
      --transition:         .2s ease;
    }

    /* === BEM 命名:block__element--modifier === */
    /* .btn            块(block):独立的组件 */
    /* .btn__icon      元素(element):块内部的子部分 */
    /* .btn--danger    修饰符(modifier):块的状态/变体 */


    /* ---------- 按钮组件 ---------- */
    .btn {
      display: inline-flex; align-items: center; gap: 6px;
      padding: 10px 20px;
      background: var(--color-primary);
      color: #fff; border: none; border-radius: var(--radius);
      font-size: 14px; cursor: pointer;
      transition: background var(--transition), transform var(--transition);
    }
    .btn:hover  { background: var(--color-primary-dark); transform: translateY(-1px); }
    .btn:active { transform: translateY(0); }       /* 点击时下沉 */

    /* 颜色修饰符:不同语义 */
    .btn--danger { background: var(--color-danger); }
    .btn--ghost  { background: transparent;
                   color: var(--color-primary);
                   border: 1px solid var(--color-primary); }
    /* 尺寸修饰符 */
    .btn--small  { padding: 6px 12px; font-size: 12px; }
    .btn--large  { padding: 14px 28px; font-size: 16px; }


    /* ---------- 卡片组件 ---------- */
    .card {
      background: var(--color-bg);
      border: 1px solid var(--color-border);
      border-radius: var(--radius);
      box-shadow: var(--shadow);
      overflow: hidden;
      max-width: 280px;
    }
    .card__image {
      width: 100%; height: 140px;
      background: #dfe6f0;            /* 真实项目用 <img src> */
      display: flex; align-items: center; justify-content: center;
      color: #999; font-size: 14px;
    }
    .card__body   { padding: var(--space); }
    .card__title  { font-size: 16px; margin: 0 0 8px; color: var(--color-text); }
    .card__text   { font-size: 14px; color: var(--color-text-light);
                    line-height: 1.6; margin: 0; }
    .card__footer { padding: 0 var(--space) var(--space);
                    display: flex; gap: 8px; }


    /* ---------- 导航组件 ---------- */
    .nav {
      display: flex; align-items: center; gap: var(--space);
      background: var(--color-bg);
      border-bottom: 1px solid var(--color-border);
      padding: 0 var(--space);
      height: 56px;
    }
    .nav__brand { font-weight: bold; font-size: 18px;
                  color: var(--color-primary); }
    .nav__list  { display: flex; gap: var(--space);
                  list-style: none; margin: 0; padding: 0; }
    .nav__link  { color: var(--color-text); text-decoration: none;
                  font-size: 14px;
                  transition: color var(--transition); }
    .nav__link:hover        { color: var(--color-primary); }
    .nav__link--active      { color: var(--color-primary); font-weight: bold; }
  </style>
</head>
<body>
  <!-- 导航 -->
  <nav class="nav">
    <span class="nav__brand">MyUI</span>
    <ul class="nav__list">
      <li><a class="nav__link nav__link--active" href="#">首页</a></li>
      <li><a class="nav__link" href="#">产品</a></li>
      <li><a class="nav__link" href="#">文档</a></li>
    </ul>
  </nav>

  <!-- 按钮:各种修饰符组合 -->
  <div style="padding:24px;display:flex;gap:12px;flex-wrap:wrap;align-items:center">
    <button class="btn">默认按钮</button>
    <button class="btn btn--danger">危险按钮</button>
    <button class="btn btn--ghost">幽灵按钮</button>
    <button class="btn btn--small">小按钮</button>
    <button class="btn btn--large">大按钮</button>
  </div>

  <!-- 卡片 -->
  <div style="padding:0 24px 24px">
    <div class="card">
      <div class="card__image">图片占位</div>
      <div class="card__body">
        <h3 class="card__title">组件化思想</h3>
        <p class="card__text">把界面拆成可复用的独立单元,每个组件管自己的结构和样式,通过 BEM 命名避免冲突。</p>
      </div>
      <div class="card__footer">
        <button class="btn btn--small">详情</button>
        <button class="btn btn--small btn--ghost">收藏</button>
      </div>
    </div>
  </div>
</body>
</html>

要点讲解:

小结

三个项目对应 CSS 三大核心场景:布局(响应式主页)、动效(动画合集)、工程化(组件库)。它们都用到前面学的基础——盒模型、选择器、Flex / Grid、定位、transition / animation、变量——只是组合起来做出真实可用的东西。建议你至少把其中一个改造成自己的版本:给主页加暗色模式、给动画加滚动触发、给组件库加更多组件(输入框、模态框、表格)——做过一遍比读十遍更扎实。

恭喜!到这里 CSS 系列就真正完结了。接下来可以深入——CSS 架构(Tailwind / CSS Modules / CSS-in-JS)、动画库(GSAP / Framer Motion)、设计系统(读懂 Element Plus 源码)、CSS Houdini / 容器查询——方向很多,但底层 CSS 你已经具备。

← 上一篇 CSS 变量

返回 CSS 教程目录

✈️💬