CSS3从零基础到精通(三):动感地带——过渡、动画、变形与响应式

摘要: 网页的美,不仅在于静态的布局,更在于灵动的交互。本篇将带你走进CSS3最有趣的部分:过渡(transition)、变形(transform)、关键帧动画(animation)和响应式设计(媒体查询)。你将学会如何让按钮在悬停时平滑变色、如何让元素旋转缩放、如何设计出呼吸灯与入场动效,以及如何让同一个页面在手机、平板和电脑上都完美显示。


一、过渡(transition)------让变化变得平滑

1. 为什么需要过渡?

在CSS中,很多属性可以在不同状态之间切换,例如:hover:focus、类名变化。如果没有过渡,变化是瞬间完成的,显得生硬。transition的作用就是给属性变化添加一个平滑的过渡过程,让用户感觉更自然。

举个例子,一个按钮在鼠标悬停时改变背景色:

css 复制代码
.btn {
  background-color: #3498db;
  /* 无过渡:颜色瞬间变化 */
}
.btn:hover {
  background-color: #2980b9;
}

加上transition:

css 复制代码
.btn {
  background-color: #3498db;
  transition: background-color 0.3s ease;
}

现在从蓝色到深蓝会有一个0.3秒的渐变,视觉上舒服很多。

2. transition语法拆解

transition是一个复合属性,可以一次性设置四个子属性,顺序为:

css 复制代码
transition: property duration timing-function delay;

也可以分开写:

  • transition-property:指定要过渡的CSS属性,默认为all(所有可过渡属性都会变化)。常用可过渡属性包括:widthheightbackground-colorcoloropacitytransformlefttopmarginpaddingborder-width等。但不能过渡displaybackground-image等。

  • transition-duration:过渡持续时间,单位s(秒)或ms(毫秒),如 0.5s500ms

  • transition-timing-function:速度曲线,决定过渡过程的快慢变化。

  • transition-delay:延迟多久后开始过渡,单位同duration。

3. 速度曲线详解

transition-timing-function 支持以下值:

  • ease(默认):慢→快→慢,最常用。

  • linear:匀速。

  • ease-in:慢→快。

  • ease-out:快→慢。

  • ease-in-out:慢→快→慢(比ease更平滑)。

  • cubic-bezier(n,n,n,n):自定义贝塞尔曲线,可以精细控制速度变化。例如 cubic-bezier(0.68, -0.55, 0.27, 1.55) 会有一个回弹效果。

可以通过浏览器的开发者工具实时调整贝塞尔曲线,非常直观。

4. 过渡多个属性

用逗号分隔多个过渡设置:

css 复制代码
.box {
  width: 100px;
  height: 100px;
  background: #e74c3c;
  transition: width 0.5s ease, background 0.8s linear, height 0.3s ease-out;
}
.box:hover {
  width: 200px;
  background: #9b59b6;
  height: 150px;
}

如果希望所有属性同时过渡且使用相同时间和缓动,可以直接写 transition: all 0.3s ease;,但性能略差,推荐明确指定属性。

5. 实战:悬停放大卡片

卡片在鼠标划过时向上微微移动并加深阴影,这个效果非常流行。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>纯原始卡片效果</title>
  <style>
.card {
  width: 280px;
  padding: 20px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.card:hover {
  transform: translateY(-8px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.15);
}
  </style>
</head>
<body>
  <!-- 卡片1:短内容 -->
  <div class="card">
    这是短内容卡片
  </div>

  <br><br>

  <!-- 卡片2:中等内容 -->
  <div class="card">
    这是中等内容卡片,包含更多的文字信息,卡片会自动撑开高度。
  </div>

  <br><br>

  <!-- 卡片3:长内容(完全自适应) -->
  <div class="card">
    这是长内容卡片,无论内容有多少,卡片都会自动调整高度来适应。
    这是长内容卡片,无论内容有多少,卡片都会自动调整高度来适应。
    这是长内容卡片,无论内容有多少,卡片都会自动调整高度来适应。
  </div>
</body>
</html>

transform 属性我们很快就会学到,这里先用它实现位移。


二、变形(transform)------让元素随心所欲地改变

transform允许我们对元素进行旋转、缩放、倾斜、移动等操作,完全不影响文档流,其他元素不会移动,只是视觉效果变化。它常和transition、animation搭配使用,创造丰富动效。

1. 2D变形函数

① translate(平移) translate(x, y) 将元素沿X轴和Y轴移动。如果只写一个值,只移动X轴。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>平移效果</title>
  <style>
    .box {
      width: 100px;
      height: 100px;
      background: #409eff;
      color: white;
      text-align: center;
      line-height: 100px;
      border-radius: 8px;
      margin: 20px;
      display: inline-block;
    }

    /* 平移变换:向右50px,向下20px */
    .translate {
      transform: translate(50px, 20px);
    }
  </style>
</head>
<body>
  <h3>平移 translate(x, y)</h3>
  <p>元素沿x轴和y轴平移,x正向右负向左,y正向下负向上</p>
  
  <div class="box">原始</div>
  <div class="box translate">平移后</div>
</body>
</html>

常用简化:translateX(50px)translateY(20px)

② scale(缩放) scale(sx, sy) 缩放元素,1为原始大小,0.5为一半,2为两倍。也可以单独设置X和Y。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>缩放效果</title>
  <style>
    .box {
      width: 100px;
      height: 100px;
      background: #67c23a;
      color: white;
      text-align: center;
      line-height: 100px;
      border-radius: 8px;
      margin: 30px;
      display: inline-block;
    }

    /* 缩放变换:等比例放大1.5倍 */
    .scale {
      transform: scale(1.5);
    }

    /* 也可以分别设置x轴和y轴缩放:transform: scaleX(1.2) scaleY(0.8); */
  </style>
</head>
<body>
  <h3>缩放 scale(x, y)</h3>
  <p>元素沿x轴和y轴缩放,大于1放大,小于1缩小,只写一个参数表示等比例缩放</p>
  
  <div class="box">原始</div>
  <div class="box scale">放大1.5倍</div>
</body>
</html>

③ rotate(旋转) rotate(deg) 顺时针旋转,单位deg(度)。例如 rotate(45deg)。也可以写负值逆时针。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>旋转效果</title>
  <style>
    .box {
      width: 100px;
      height: 100px;
      background: #e6a23c;
      color: white;
      text-align: center;
      line-height: 100px;
      border-radius: 8px;
      margin: 40px;
      display: inline-block;
    }

    /* 旋转变换:顺时针旋转45度 */
    .rotate {
      transform: rotate(45deg);
    }

    /* 逆时针旋转:transform: rotate(-30deg); */
    /* 旋转原点默认在中心,可通过 transform-origin 改变 */
  </style>
</head>
<body>
  <h3>旋转 rotate(angle)</h3>
  <p>元素绕中心顺时针旋转,单位为deg(角度),负数表示逆时针旋转</p>
  
  <div class="box">原始</div>
  <div class="box rotate">旋转45°</div>
</body>
</html>

④ skew(倾斜) skew(ax, ay) 沿X轴或Y轴倾斜,单位deg。比如 skew(10deg, 5deg)。较少使用,但可以做平行四边形。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>倾斜效果</title>
  <style>
    .box {
      width: 100px;
      height: 100px;
      background: #f56c6c;
      color: white;
      text-align: center;
      line-height: 100px;
      border-radius: 8px;
      margin: 30px;
      display: inline-block;
    }

    /* 倾斜变换:x轴倾斜15度,y轴倾斜5度 */
    .skew {
      transform: skew(15deg, 5deg);
    }

    /* 只倾斜x轴:transform: skewX(20deg); */
    /* 只倾斜y轴:transform: skewY(10deg); */
  </style>
</head>
<body>
  <h3>倾斜 skew(x-angle, y-angle)</h3>
  <p>元素沿x轴和y轴倾斜,单位为deg(角度),正数表示顺时针倾斜</p>
  
  <div class="box">原始</div>
  <div class="box skew">倾斜后</div>
</body>
</html>

2. 组合变形

可以用空格分隔多个函数,顺序很重要,因为变形的顺序会影响最终效果。例如先移动再旋转与先旋转再移动完全不同。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>组合变形过渡效果</title>
  <style>
    body {
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      background: #f5f7fa;
      margin: 0;
      font-family: 'Microsoft YaHei', sans-serif;
    }

    .box {
      width: 120px;
      height: 120px;
      background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
      color: white;
      text-align: center;
      line-height: 120px;
      border-radius: 12px;
      box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
      font-size: 16px;
      font-weight: 500;
      
      /* 所有 transform 变化都会在 2 秒内平滑完成 */
      transition: transform 2s ease-in-out;
    }

    /* 鼠标悬停时应用最终的组合变形 */
    .box:hover {
      /* 注意:transform 的顺序很重要!后面的变形会在前面的基础上叠加 */
      transform: 
        translate(100px, 0)    /* 第1步:向右平移100px */
        rotate(45deg)          /* 第2步:顺时针旋转45度 */
        scale(1.5)             /* 第3步:放大1.5倍 */
        translate(100px, 100px) /* 第4步:再向右100px,向下100px */
        rotate(45deg)          /* 第5步:再旋转45度(总共90度) */
        skew(10deg, 5deg);     /* 第6步:最后添加倾斜效果 */
    }
  </style>
</head>
<body>
  <div class="box">悬停看效果</div>
</body>
</html>

3. transform-origin 变形中心点

默认的变形中心点是元素的中心(50% 50%)。可以通过 transform-origin 改变,比如让旋转围绕左上角:

css 复制代码
.box {
  transform-origin: top left;
  transform: rotate(45deg);
}

也可以使用具体像素或关键字组合(left、top、right、bottom)。

4. 3D变形简介

2D已经够用,但3D能带来更炫酷的效果。开启3D空间需要给父元素设置 perspective,给子元素进行 rotateX()rotateY() 等操作。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>3D卡片翻转效果</title>
  <style>
    .scene {
      perspective: 800px;
    }
    .card-3d {
      transition: transform 0.6s;
      transform-style: preserve-3d;
    }
    .card-3d:hover {
      transform: rotateY(180deg);
    }

    /* 场景容器样式 */
    .scene {
      width: 300px;
      height: 200px;
      margin: 150px auto;
    }

    /* 3D卡片容器样式 */
    .card-3d {
      width: 100%;
      height: 100%;
      position: relative;
    }

    /* 卡片正面和背面的通用样式 */
    .card-front, .card-back {
      position: absolute;
      width: 100%;
      height: 100%;
      backface-visibility: hidden; /* 隐藏元素背面 */
      display: flex;
      justify-content: center;
      align-items: center;
      border-radius: 12px;
      font-size: 24px;
      font-weight: bold;
      color: white;
    }

    /* 卡片正面样式 */
    .card-front {
      background: #409eff;
    }

    /* 卡片背面样式 */
    .card-back {
      background: #67c23a;
      transform: rotateY(180deg); /* 初始翻转180度,隐藏背面 */
    }
  </style>
</head>
<body>
  <div class="scene">
    <div class="card-3d">
      <div class="card-front">卡片正面</div>
      <div class="card-back">卡片背面</div>
    </div>
  </div>
</body>
</html>

这可以制作卡片翻转效果,正面和背面各放内容。


三、动画(animation)------更丰富的关键帧动效

过渡只能实现从一种状态到另一种状态的简单动画,而animation能定义多个关键帧,实现循环播放、来回播放、延迟开始、暂停等控制,非常强大。

1. @keyframes 定义动画

首先用 @keyframes 规则定义动画的各个阶段(关键帧),格式如下:

css 复制代码
@keyframes 动画名 {
  0% { /* 起始状态 */ }
  100% { /* 结束状态 */ }
}

也可以用 fromto 关键字代替0%和100%。中间可以添加任意百分比的帧。

示例:一个元素从透明淡入并从下方滑入

css 复制代码
@keyframes fadeInUp {
  0% {
    opacity: 0;
    transform: translateY(30px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

2. 将动画应用到元素

使用 animation 属性调用定义好的动画,可以分别设置多个子属性:

  • animation-name:动画名称(自定义的名字)。

  • animation-duration:动画持续时间,如 2s

  • animation-timing-function:速度曲线,和过渡类似。

  • animation-delay:延迟时间。

  • animation-iteration-count:播放次数,数字或 infinite(无限循环)。

  • animation-direction:播放方向,normal(正向)、reverse(反向)、alternate(先正后反交替)、alternate-reverse

  • animation-fill-mode:动画结束后保持在什么状态。forwards(保持结束状态)、backwards(保持开始状态)、both

  • animation-play-state:运行状态,running(播放)或 paused(暂停),配合交互可做暂停效果。

简写形式(推荐):

css 复制代码
.box {
  animation: fadeInUp 0.6s ease-out 0s 1 forwards;
}

3. 实战案例:呼吸灯效果

制作一个红点,无限循环地放大缩小,模拟呼吸或脉冲。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>脉冲呼吸红点</title>
  <style>
    /* 页面居中样式 */
    body {
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      background: #f5f7fa;
      margin: 0;
    }

    @keyframes pulse {
      0%, 100% {
        transform: scale(1);
        opacity: 1;
      }
      50% {
        transform: scale(1.4);
        opacity: 0.7;
      }
    }

    .dot {
      width: 20px;
      height: 20px;
      background: red;
      border-radius: 50%;
      animation: pulse 2s ease-in-out infinite;
    }

    /* 可选:添加阴影增强立体感 */
    .dot {
      box-shadow: 0 0 10px rgba(255, 0, 0, 0.5);
    }
  </style>
</head>
<body>
  <div class="dot"></div>
</body>
</html>

4. 实战案例:渐变背景流动

配合 background-position 动画,让渐变背景动起来,制作流光效果。

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 {
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      gap: 40px;
      background: #f5f7fa;
      font-family: 'Microsoft YaHei', sans-serif;
    }

    .gradient-flow {
      background: linear-gradient(90deg, #ff7e5f, #feb47b, #86a8e7, #91eae4);
      background-size: 300% 300%;
      animation: flow 4s ease infinite;
    }

    @keyframes flow {
      0% { background-position: 0% 50%; }
      50% { background-position: 100% 50%; }
      100% { background-position: 0% 50%; }
    }

    /* 示例1:流光按钮 */
    .flow-button {
      padding: 12px 36px;
      border: none;
      border-radius: 8px;
      color: white;
      font-size: 18px;
      font-weight: 500;
      cursor: pointer;
      box-shadow: 0 4px 15px rgba(0,0,0,0.2);
    }

    /* 示例2:流光卡片 */
    .flow-card {
      width: 300px;
      padding: 40px;
      border-radius: 12px;
      color: white;
      text-align: center;
      font-size: 20px;
      box-shadow: 0 8px 25px rgba(0,0,0,0.15);
    }

    /* 示例3:流光文字(进阶效果) */
    .flow-text {
      font-size: 48px;
      font-weight: bold;
      background-clip: text;
      -webkit-background-clip: text;
      color: transparent;
    }
  </style>
</head>
<body>
  <!-- 示例1:流光按钮 -->
  <button class="gradient-flow flow-button">
    流光按钮
  </button>

  <!-- 示例2:流光卡片 -->
  <div class="gradient-flow flow-card">
    这是一个流光卡片
  </div>

  <!-- 示例3:流光文字 -->
  <h1 class="gradient-flow flow-text">
    流光文字效果
  </h1>
</body>
</html>

5. 控制动画的暂停与播放

可以利用 :hover 改变 animation-play-state 实现鼠标悬停暂停动画。

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 {
      background: #f5f7fa;
      font-family: 'Microsoft YaHei', sans-serif;
      padding: 50px 0;
      display: flex;
      flex-direction: column;
      gap: 30px;
    }

    .container {
      max-width: 800px;
      margin: 0 auto;
      width: 100%;
      padding: 0 20px;
    }

    h2 {
      margin-bottom: 15px;
      color: #333;
      font-size: 18px;
    }

    .scroll-box {
      overflow: hidden;
      white-space: nowrap;
      animation: scroll-left 10s linear infinite;
    }

    .scroll-box:hover {
      animation-play-state: paused;
    }

    @keyframes scroll-left {
      0% { transform: translateX(100%); }
      100% { transform: translateX(-100%); }
    }

    /* 跑马灯容器样式 */
    .marquee-container {
      background: #409eff;
      color: white;
      padding: 12px 0;
      border-radius: 8px;
      overflow: hidden;
    }

    /* 跑马灯文字样式 */
    .scroll-text {
      display: inline-block;
      font-size: 16px;
    }

    /* 变体1:从左向右滚动 */
    .scroll-right {
      animation-name: scroll-right;
    }

    @keyframes scroll-right {
      0% { transform: translateX(-100%); }
      100% { transform: translateX(100%); }
    }

    /* 变体2:垂直向上滚动 */
    .scroll-up-container {
      height: 150px;
      background: #67c23a;
      color: white;
      border-radius: 8px;
      overflow: hidden;
    }

    .scroll-up {
      white-space: normal;
      animation: scroll-up 8s linear infinite;
    }

    @keyframes scroll-up {
      0% { transform: translateY(100%); }
      100% { transform: translateY(-100%); }
    }

    /* 变体3:无缝循环跑马灯(推荐) */
    .seamless-marquee {
      overflow: hidden;
      background: #e6a23c;
      color: white;
      padding: 12px 0;
      border-radius: 8px;
    }

    .seamless-scroll {
      display: inline-block;
      animation: seamless-scroll 15s linear infinite;
    }

    /* 复制一份内容实现无缝衔接 */
    .seamless-scroll span {
      display: inline-block;
      padding-right: 50px;
    }

    @keyframes seamless-scroll {
      0% { transform: translateX(0); }
      100% { transform: translateX(-50%); }
    }

    .seamless-marquee:hover .seamless-scroll {
      animation-play-state: paused;
    }
  </style>
</head>
<body>
  <div class="container">
    <!-- 基础版:从右向左滚动 -->
    <h2>1. 基础版(鼠标悬停暂停)</h2>
    <div class="marquee-container">
      <div class="scroll-box scroll-text">
        这是一条跑马灯滚动字幕,鼠标悬停时会暂停,移开后继续滚动。非常适合用于公告、通知、广告等场景。
      </div>
    </div>
  </div>

  <div class="container">
    <!-- 变体1:从左向右滚动 -->
    <h2>2. 从左向右滚动</h2>
    <div class="marquee-container">
      <div class="scroll-box scroll-text scroll-right">
        这是从左向右滚动的跑马灯,只需要修改动画的transform方向即可实现。
      </div>
    </div>
  </div>

  <div class="container">
    <!-- 变体2:垂直向上滚动 -->
    <h2>3. 垂直向上滚动</h2>
    <div class="scroll-up-container">
      <div class="scroll-box scroll-up" style="padding: 15px;">
        这是垂直向上滚动的跑马灯<br>
        可以用于展示多条通知信息<br>
        每条信息占一行<br>
        鼠标悬停同样可以暂停滚动
      </div>
    </div>
  </div>

  <div class="container">
    <!-- 变体3:无缝循环跑马灯(推荐) -->
    <h2>4. 无缝循环跑马灯(推荐)</h2>
    <div class="seamless-marquee">
      <div class="seamless-scroll">
        <span>这是无缝循环的跑马灯,通过复制一份内容实现真正的无缝衔接,不会出现空白间隔。</span>
        <span>这是无缝循环的跑马灯,通过复制一份内容实现真正的无缝衔接,不会出现空白间隔。</span>
      </div>
    </div>
  </div>
</body>
</html>

这在制作跑马灯或滚动字幕时很实用。


四、变形与过渡、动画的实战组合

让我们把三者融合,制作一些常见的UI动效。

1. 按钮波纹扩散(伪元素 + 过渡)

鼠标悬停时从按钮中心扩展出一个圆形波纹,常称为"水波纹"效果。这个实现相对复杂,但可以展示动画能力。

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 {
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      background: #f5f7fa;
      margin: 0;
      font-family: 'Microsoft YaHei', sans-serif;
    }

    .btn-ripple {
      position: relative;
      background: #6c5ce7;
      color: white;
      border: none;
      padding: 12px 28px;
      border-radius: 30px;
      cursor: pointer;
      transition: box-shadow 0.4s;
      overflow: hidden;/* 隐藏溢出的波纹 */
      font-size: 16px;
      font-weight: 500;
    }

    .btn-ripple:hover {
      box-shadow: 0 0 0 12px rgba(108,92,231,0.2);
    }

    /* 创建波纹元素 */
    .btn-ripple::after {
      content: '';
      position: absolute;
      top: 50%;
      left: 50%;
      width: 0;
      height: 0;
      background: rgba(255,255,255,0.3);
      border-radius: 50%;
      transform: translate(-50%, -50%);
      transition: all 0.6s ease-out;
      pointer-events: none; /* 让波纹不影响点击事件 */
    }

    /* 点击时触发波纹动画 */
    .btn-ripple:active::after {
      width: 200px;
      height: 200px;
      opacity: 0;
    }
  </style>
</head>
<body>
  <button class="btn-ripple">点击看涟漪效果</button>
</body>
</html>

2. 加载动画

制作一个旋转的圆环加载器。

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 {
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      background: #f5f7fa;
      margin: 0;
      gap: 60px;
      flex-wrap: wrap;
    }

    .loader-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 15px;
    }

    .loader-text {
      color: #666;
      font-size: 14px;
      font-family: 'Microsoft YaHei', sans-serif;
    }

    .spinner {
      width: 40px;
      height: 40px;
      border: 4px solid #e0e0e0;
      border-top: 4px solid #3498db;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }

    @keyframes spin {
      to { transform: rotate(360deg); }
    }

    /* 变体1:小尺寸加载器 */
    .spinner-sm {
      width: 24px;
      height: 24px;
      border-width: 3px;
    }

    /* 变体2:大尺寸加载器 */
    .spinner-lg {
      width: 60px;
      height: 60px;
      border-width: 5px;
    }

    /* 变体3:绿色加载器 */
    .spinner-green {
      border-color: #e0e0e0;
      border-top-color: #2ecc71;
    }

    /* 变体4:红色加载器 */
    .spinner-red {
      border-color: #e0e0e0;
      border-top-color: #e74c3c;
    }

    /* 变体5:紫色加载器 */
    .spinner-purple {
      border-color: #e0e0e0;
      border-top-color: #9b59b6;
    }

    /* 变体6:双环加载器 */
    .spinner-double {
      position: relative;
      width: 40px;
      height: 40px;
    }

    .spinner-double::before,
    .spinner-double::after {
      content: '';
      position: absolute;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }

    .spinner-double::before {
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border: 4px solid #e0e0e0;
      border-top-color: #3498db;
    }

    .spinner-double::after {
      top: 8px;
      left: 8px;
      width: calc(100% - 16px);
      height: calc(100% - 16px);
      border: 4px solid #e0e0e0;
      border-top-color: #e74c3c;
      animation-direction: reverse;
      animation-duration: 0.8s;
    }
  </style>
</head>
<body>
  <!-- 基础版加载器 -->
  <div class="loader-container">
    <div class="spinner"></div>
    <div class="loader-text">基础加载器</div>
  </div>

  <!-- 小尺寸加载器 -->
  <div class="loader-container">
    <div class="spinner spinner-sm"></div>
    <div class="loader-text">小尺寸</div>
  </div>

  <!-- 大尺寸加载器 -->
  <div class="loader-container">
    <div class="spinner spinner-lg"></div>
    <div class="loader-text">大尺寸</div>
  </div>

  <!-- 绿色加载器 -->
  <div class="loader-container">
    <div class="spinner spinner-green"></div>
    <div class="loader-text">绿色</div>
  </div>

  <!-- 红色加载器 -->
  <div class="loader-container">
    <div class="spinner spinner-red"></div>
    <div class="loader-text">红色</div>
  </div>

  <!-- 双环加载器 -->
  <div class="loader-container">
    <div class="spinner-double"></div>
    <div class="loader-text">双环反向</div>
  </div>

  <!-- 带文字的加载器 -->
  <div class="loader-container">
    <div class="spinner"></div>
    <div class="loader-text">加载中...</div>
  </div>
</body>
</html>

五、响应式设计------让页面适配所有设备

截止目前,我们的页面都只在桌面端看着不错。但在手机上可能横向拉伸、文字太小、布局混乱。响应式设计就是让同一个页面在不同尺寸屏幕上自动调整布局,提供最优体验。

1. 视口 meta 标签

在HTML <head> 中必须加上:

html 复制代码
<meta name="viewport" content="width=device-width, initial-scale=1.0">

它告诉移动浏览器,页面宽度等于设备宽度,初始缩放比例为1。不加的话,很多手机会把页面缩小成桌面宽度,导致字很小。

2. 媒体查询 @media

媒体查询可以根据设备特性(如屏幕宽度、高度、分辨率等)应用不同的CSS样式。最常用的是按宽度划分断点。

css 复制代码
/* 当屏幕宽度 ≤ 768px 时(常见平板竖屏及手机) */
@media (max-width: 768px) {
  .container {
    flex-direction: column;
  }
}

也可以设置移动优先,从小屏幕写基础样式,用 min-width 为更大屏幕添加增强样式:

css 复制代码
/* 基础样式用于手机 */
.container {
  display: flex;
  flex-direction: column;
}
/* 大于等于768px时 */
@media (min-width: 768px) {
  .container {
    flex-direction: row;
  }
}

3. 常见断点

没有绝对标准,但通常参考:

  • 手机:< 576px

  • 平板竖屏:576px ~ 768px

  • 平板横屏 / 小桌面:768px ~ 992px

  • 桌面:992px ~ 1200px

  • 大桌面:≥ 1200px

实际开发按需取2~3个断点即可。

4. 响应式布局策略

① 弹性盒子和网格天然响应式 使用 flex-wrap: wrap 让弹性项目自动换行;使用 grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)) 让网格列数根据容器自动变化。这些不需要媒体查询就能响应。

② 流式单位与限制 用百分比、vw、vh、fr等相对单位代替固定px。但要注意设置最大最小宽高(max-width、min-width),避免过宽或过窄。

③ 响应式图片 让图片不超出容器:

css 复制代码
img {
  max-width: 100%;
  height: auto;
}

④ 响应式排版 可以结合媒体查询调整根字号,然后使用rem单位,或者直接在不同断点改变字号。

css 复制代码
html { font-size: 16px; }
@media (max-width: 768px) {
  html { font-size: 15px; }
}
h1 { font-size: 2.5rem; } /* 随根字号变化 */

5. 实战:响应式布局

假设我们有一个包含侧边栏和主内容的两栏Flex布局:

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: 'Microsoft YaHei', sans-serif;
      line-height: 1.6;
      color: #333;
      background-color: #f5f7fa;
      /* 最小高度占满视口,为页脚吸底做准备 */
      min-height: 100vh;
      /* 使body成为flex容器,实现页脚自动吸底 */
      display: flex;
      flex-direction: column;
    }

    /* 统一链接样式 */
    a {
      text-decoration: none;
      color: inherit;
      transition: all 0.3s ease;
    }

    /* 统一列表样式 */
    ul {
      list-style: none;
    }

    /* ========================================
       通用组件样式
       ======================================== */
    /* 容器类:统一页面宽度和内边距 */
    .container {
      max-width: 1200px;
      margin: 0 auto;
      padding: 0 20px;
      width: 100%;
    }

    /* 卡片类:统一白色背景、圆角和阴影效果 */
    .card {
      background-color: white;
      border-radius: 8px;
      padding: 20px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.05);
      margin: 20px 0;
    }

    /* ========================================
       头部导航样式
       ======================================== */
    header {
      background-color: #3498db;
      color: white;
      padding: 15px 0;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      /* 头部固定在顶部 */
      position: sticky;
      top: 0;
      z-index: 100;
    }

    .header-content {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .logo {
      font-size: 24px;
      font-weight: bold;
    }

    /* ========================================
       核心布局样式(你提供的原始代码)
       ======================================== */
    .page {
      /* 启用flex布局,实现两栏并排 */
      display: flex;
      /* 两栏之间的间距 */
      gap: 20px;
    }

    .sidebar {
      /* flex简写:不放大(0)、不缩小(0)、基础宽度250px */
      flex: 0 0 250px;
    }

    .content {
      /* 主内容区自动填充剩余所有空间 */
      flex: 1;
    }

    /* ========================================
       响应式适配:768px以下屏幕(手机端)
       ======================================== */
    @media (max-width: 768px) {
      .page {
        /* 改为垂直排列 */
        flex-direction: column;
      }

      .sidebar {
        /* 取消固定宽度,自动占满容器 */
        flex: none;
        /* 调整顺序:让侧边栏显示在主内容上方 */
        order: -1;
      }
    }

    /* ========================================
       侧边栏内容样式
       ======================================== */
    .sidebar {
      /* 继承卡片样式 */
      background-color: white;
      border-radius: 8px;
      padding: 20px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.05);
      margin: 20px 0;
      /* 高度适应内容 */
      height: fit-content;
      /* 粘性定位:滚动时固定在顶部 */
      position: sticky;
      top: 80px; /* 避开头部高度 */
    }

    .sidebar-title {
      font-size: 18px;
      font-weight: bold;
      margin-bottom: 15px;
      padding-bottom: 10px;
      border-bottom: 1px solid #eee;
    }

    .sidebar-nav li {
      margin-bottom: 10px;
    }

    .sidebar-nav a {
      display: block;
      padding: 8px 12px;
      color: #666;
      border-radius: 4px;
    }

    .sidebar-nav a:hover,
    .sidebar-nav a.active {
      background-color: #3498db;
      color: white;
    }

    /* ========================================
       主内容区样式
       ======================================== */
    .content {
      /* 继承卡片样式 */
      background-color: white;
      border-radius: 8px;
      padding: 20px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.05);
      margin: 20px 0;
    }

    .content h1 {
      font-size: 24px;
      margin-bottom: 20px;
      color: #333;
    }

    .content p {
      margin-bottom: 15px;
      color: #666;
      line-height: 1.8;
    }

    /* ========================================
       页脚样式
       ======================================== */
    footer {
      background-color: #333;
      color: white;
      text-align: center;
      padding: 20px 0;
      /* 自动向上推,实现页脚吸底 */
      margin-top: auto;
    }
  </style>
</head>
<body>
  <!-- 页面头部:包含Logo和导航 -->
  <header>
    <div class="container header-content">
      <div class="logo">网站Logo</div>
      <div>导航菜单</div>
    </div>
  </header>

  <!-- 页面主体:包含侧边栏和主内容 -->
  <main class="container page">
    <!-- 侧边栏:导航菜单 -->
    <aside class="sidebar">
      <h3 class="sidebar-title">侧边栏导航</h3>
      <ul class="sidebar-nav">
        <li><a href="#" class="active">首页</a></li>
        <li><a href="#">产品介绍</a></li>
        <li><a href="#">服务支持</a></li>
        <li><a href="#">关于我们</a></li>
        <li><a href="#">联系我们</a></li>
      </ul>
    </aside>

    <!-- 主内容区:页面主要内容 -->
    <article class="content">
      <h1>主内容区域</h1>
      <p>这是一个使用Flex布局实现的响应式两栏页面。在桌面端,侧边栏固定宽度250px,主内容区自动填充剩余空间;在屏幕宽度小于768px的移动端,布局会自动切换为上下排列,侧边栏会移动到顶部并占满整个宽度。</p>
      <p>Flex布局是现代网页布局中最常用的布局方式之一,它提供了强大的对齐、分布和排序能力,能够轻松实现各种复杂的布局需求。</p>
      <p>这种布局结构非常适合用于博客、后台管理系统、企业官网等类型的网站,既保证了桌面端的良好体验,又兼顾了移动端的可用性。</p>
      <p>你可以根据实际需求修改侧边栏的宽度、间距、颜色等样式,或者调整媒体查询的断点值,以适应不同的设计要求。</p>
    </article>
  </main>

  <!-- 页面页脚:版权信息等 -->
  <footer>
    <div class="container">
      <p>© 2026 响应式布局示例 版权所有</p>
    </div>
  </footer>
</body>
</html>

这样在手机上侧边栏会跑到上面并占满宽度,主内容在下方。

6. 纯CSS汉堡菜单的思路

移动端导航栏通常需要隐藏菜单并用一个"汉堡"图标代替,点击展开。过去这需要JS,但可以利用 :checked 伪类配合隐藏的checkbox实现纯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>纯CSS汉堡菜单</title>
<style>
/* 核心基础样式 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

ul {
  list-style: none;
}

a {
  text-decoration: none;
  color: #333;
}

.mobile-nav {
  position: relative;
  padding: 0 20px;
  height: 60px;
  line-height: 60px;
}

/* 隐藏复选框开关 */
.menu-toggle {
  display: none;
}

/* 汉堡图标 */
.hamburger {
  display: none;
  font-size: 28px;
  cursor: pointer;
}

/* 桌面端菜单 */
.menu {
  display: flex;
  gap: 20px;
}

/* 移动端适配 */
@media (max-width: 768px) {
  .hamburger {
    display: block;
  }
  .menu {
    display: none;
    flex-direction: column;
    position: absolute;
    top: 60px;
    left: 0;
    width: 100%;
    background: #fff;
    box-shadow: 0 2px 5px rgba(0,0,0,0.2);
    padding: 10px 20px;
  }
  /* 复选框选中,展开菜单(核心:checked用法) */
  .menu-toggle:checked ~ .menu {
    display: flex;
  }
}
</style>
</head>
<body>

<nav class="mobile-nav">
  <input type="checkbox" id="menu-toggle" class="menu-toggle">
  <label for="menu-toggle" class="hamburger">&#9776;</label>
  <ul class="menu">
    <li><a href="#">首页</a></li>
    <li><a href="#">服务</a></li>
    <li><a href="#">关于</a></li>
  </ul>
</nav>

</body>
</html>

注意:这种方式在真实项目中有无障碍和焦点问题,但作为学习CSS能力已经足够惊艳。


六、综合练习:制作一个带有动效的响应式介绍区

让我们把本篇学到的所有知识融合到一个组件中。需求:

  • 一个居中的卡片区块,包含头像、名字、简短介绍和一个按钮。

  • 头像有持续的柔光扩散动画,名字从下方淡入上滑。

  • 按钮悬停时放大并改变背景色,有过渡。

  • 卡片在桌面端采用横向布局(头像左,文字右),手机端纵向堆叠。

HTML结构:

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>
</head>
<body>

<div class="intro-card">
  <div class="avatar-wrapper">
    <div class="avatar-pulse"></div>
    <img src="https://picsum.photos/400/300?random=3" class="avatar" alt="头像">
  </div>
  <div class="intro-text">
    <h2 class="name">张三</h2>
    <p class="bio">一名热爱前端的开发者,专注于CSS动效与响应式设计。</p>
    <a href="#" class="btn">了解更多</a>
  </div>
</div>

</body>
</html>

CSS(关键部分):

css 复制代码
/* 基础重置 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: Arial, sans-serif;
}

body {
  background-color: #f5f7fa;
  padding: 20px;
}

/* 卡片主体 */
.intro-card {
  display: flex;
  align-items: center;
  gap: 30px;
  max-width: 600px;
  margin: 40px auto;
  padding: 30px;
  background: #fff;
  border-radius: 20px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.08);
}

/* 头像容器 + 扩散光环 */
.avatar-wrapper {
  position: relative;
}

.avatar {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  object-fit: cover;
  position: relative;
  z-index: 1;
  background: #ddd; /* 无图片时的占位色 */
}

/* 柔光扩散动画 */
.avatar-pulse {
  position: absolute;
  top: -10px;
  left: -10px;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: rgba(52,152,219,0.3);
  animation: pulse-ring 2s ease-out infinite;
  z-index: 0;
}

@keyframes pulse-ring {
  0% {
    transform: scale(1);
    opacity: 1;
  }
  100% {
    transform: scale(1.5);
    opacity: 0;
  }
}

/* 文字区域 */
.intro-text {
  flex: 1;
}

/* 文字从下往上淡入动画 */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.intro-text .name {
  font-size: 24px;
  color: #333;
  animation: fadeInUp 0.8s ease-out;
}

.intro-text .bio {
  animation: fadeInUp 0.8s ease-out 0.2s both;
  color: #666;
  margin: 10px 0;
  line-height: 1.5;
}

/* 按钮样式 + 悬停过渡 */
.btn {
  display: inline-block;
  padding: 10px 24px;
  background: #3498db;
  color: white;
  border-radius: 30px;
  text-decoration: none;
  transition: background 0.3s, transform 0.3s;
  margin-top: 10px;
}

.btn:hover {
  background: #217dbb;
  transform: scale(1.05);
}

/* 移动端响应式:纵向堆叠 */
@media (max-width: 600px) {
  .intro-card {
    flex-direction: column;
    text-align: center;
  }
}

七、总结

我们一口气掌握了:

  • 过渡 :让状态变化平滑,提升交互体验,核心属性 transition

  • 变形transform 进行平移、缩放、旋转、倾斜,可组合,可3D。

  • 动画@keyframes + animation 实现复杂多阶段动效,支持循环、延迟、方向、暂停。

  • 响应式设计:视口标签、媒体查询、弹性单位和Flex/Grid的配合,适配不同设备。

  • 多个实战案例串联,从微交互到页面响应式结构。


如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享 ,也可以留言告诉我你遇到的其它问题,我会尽快回复。动手练习是掌握编程最快的方法,请务必亲手敲一遍本文的所有示例代码,并截图保存你的成果。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。

相关推荐
KaMeidebaby2 小时前
卡梅德生物技术快报|Western Blot 实验应用:肺肠轴机制研究全流程技术解析
前端·数据库·人工智能·算法·百度
达达爱吃肉2 小时前
claude 接入deepseek 运行报错
java·服务器·前端
jingling5552 小时前
Flutter | Dio网络请求实战
android·开发语言·前端·flutter
freeinlife'2 小时前
精准秒表计时器实现---基于js
开发语言·前端·javascript
王文?问2 小时前
ESP32-S3 实战教程:本地语音识别控制 Web 塔防游戏,从固件到前端完整跑通
前端·游戏·语音识别
Hoshizola3 小时前
uniapp与蓝牙设备连接详细步骤
前端·uni-app
优雅格子衫3 小时前
uniapp 拍照相册选取后超级好用的裁剪组件,增加水印完全自定义
开发语言·前端·javascript·uni-app·vue
Dxy12393102163 小时前
HTML如何写鼠标事件
前端·html·计算机外设
AI砖家3 小时前
前端 JavaScript 异步处理全方案详解:从回调到 Observable
开发语言·前端·javascript