Day 2|CSS 盒模型:把昨天的骨架,变成能看的页面

先看今天的小项目效果

昨天我们搭好了 HTML 骨架。今天只做一件事:搞懂盒模型 。

90% 的"布局对不齐""多出一截空白""宽度超了出现横向滚动条",根源都在这一个知识点里。

文末有一个完整的 index.html,复制保存打开就能看到效果------昨天那个骨架,今天有了真正的样式。


一、一句话记住盒模型

页面上每一个元素,都是一个盒子。

这个盒子从内到外四层:

复制代码
margin(外边距)→ 边框外的空白,透明,会叠加
border(边框)   → 盒子的边界,可以看见
padding(内边距)→ 内容和边框之间的留白
content(内容区)→ 你写的文字、图片实际占的地方

浏览器算这个盒子最终占多大地方,公式是:

复制代码
总宽度 = margin-left + border-left + padding-left + width + padding-right + border-right + margin-right
总高度 = 同理(把 left/right 换成 top/bottom)

注意:width 和 height 默认只指 content 那部分,不包含 padding 和 border。

这就是所有坑的源头。


二、box-sizing:最重要的一个属性

值 含义 表现
content-box(默认) width = 内容区 你设 width: 200px; padding: 20px; border: 2px,实际盒子宽 244px
border-box width = 内容 + padding + border 你设 width: 200px,盒子就是 200px,内容区自动缩水
inherit 继承父元素 少用

企业级项目的第一条 CSS 永远是:

css 复制代码
*, *::before, *::after {
  box-sizing: border-box;
}

加上这一句,你写 width: 25% 的四列卡片,就真的是四列并排,不会莫名其妙挤成三列半再加一个横向滚动条。

为什么通配符不会慢?现代浏览器早就优化过了,这条是行业共识(Normalize.css、Tailwind、Ant Design 全这么写)。


三、逐层拆解

1. content:内容区
  • width / height 控制大小。
  • 块级元素(div、p、h1)默认宽度撑满父元素 ,所以设了 width 才有意义。
  • 行内元素(span、a、strong)设 width/height 无效,宽高由内容决定。
  • min-width / max-width / min-height / max-height:做响应式时比固定值好用得多。
css 复制代码
.card { width: 100%; max-width: 300px; }   /* 小屏占满,大屏不超过 300 */
img   { max-width: 100%; height: auto; }   /* 图片永远不溢出容器,必背 */
2. padding:内边距
  • 让内容呼吸。商品卡片好看不好看,80% 取决于 padding 给得够不够。
  • 简写顺序(顺时针,从上面开始):
css 复制代码
padding: 16px;                  /* 上下左右 */
padding: 12px 24px;             /* 上下 / 左右 */
padding: 8px 16px 24px 32px;    /* 上 / 右 / 下 / 左 ------ 记"顺时针" */
padding-top: 16px;              /* 单边 */
  • padding 不能为负数。
  • 行内元素的左右 padding 有效,上下 padding 视觉上生效但不影响上下行间距(这是经典坑)。
3. border:边框
css 复制代码
border: 1px solid #e5e7eb;          /* 粗细 样式 颜色 */
border-top: 2px dashed #ccc;
border-radius: 8px;                 /* 圆角 */
border-radius: 50%;                 /* 圆形头像 */
outline: 2px solid blue;            /* 轮廓线,不占空间,不影响布局 */

要点:

  • border-style 可选:solid / dashed / dotted / double / none。
  • outline 和 border 的区别:outline 画在盒子外面,但不占尺寸,也不会触发重排。输入框聚焦时的蓝框就是 outline。
  • 去掉输入框默认轮廓要谨慎:outline: none 之后必须给一个 :focus-visible 的替代样式,否则键盘用户找不到焦点(无障碍硬伤)。
4. margin:外边距
  • 盒子之间的距离。可以为负数(负 margin 是做重叠布局的老技巧)。
  • margin: 0 auto 是让块级元素水平居中的经典写法(前提是元素有固定宽度且不是 float/flex 子项)。
css 复制代码
.container { width: 1200px; margin: 0 auto; }

四、三个必踩的坑

坑 1:外边距折叠(Margin Collapsing)

两个垂直相邻的块级元素,上下 margin 会合并,取较大的那个,而不是相加。

css 复制代码
.p1 { margin-bottom: 30px; }
.p2 { margin-top: 20px; }
/* 实际间距 = 30px,不是 50px */

还会发生在:父元素没有 padding/border 时,子元素的 margin-top 会"穿出去"变成父元素的 margin。

解决办法(任选一个):

  • 只在一个方向用 margin(推荐:统一只用 margin-bottom)。
  • 给父元素加 overflow: hidden / display: flow-root 触发 BFC。
  • 用 padding 代替 margin。

横向 margin 不会折叠。

坑 2:宽度爆炸
css 复制代码
.box { width: 100%; padding: 20px; }   /* 实际宽度 = 100% + 40px → 出现横向滚动条 */

解法:box-sizing: border-box,或者 width: calc(100% - 40px)。

坑 3:inline-block 的幽灵空白
html 复制代码
<div class="card"></div><div class="card"></div>

写成两行,中间会产生一个 4px 左右的空隙(换行符被当成空格渲染)。

解法:父元素 font-size: 0、HTML 里不换行、或者干脆改用 flex(Day 3 讲)。


五、display:决定盒子怎么排

值 行为
block 独占一行,可设宽高。div/p/h/ul/form/section
inline 同行排列,宽高无效,只有左右 margin/padding 可靠。span/a/strong/em/img
inline-block 同行排列 + 可设宽高。适合标签、按钮
none 盒子彻底消失,不占位,不在渲染树
flex / grid 弹性/网格布局,Day 3 专门讲

display: none vs visibility: hidden vs opacity: 0:

方式 是否占位 能否响应点击 是否触发重排
display: none 不占位 不能 是(最贵)
visibility: hidden 占位 不能 否
opacity: 0 占位 能(仍可点到) 否(可做动画)

做下拉菜单隐藏时选错,就会出现"菜单看不见但还能点到"的诡异 bug。


六、溢出控制 overflow

css 复制代码
overflow: visible;   /* 默认,内容溢出照样显示 */
overflow: hidden;    /* 裁掉,常用于圆角卡片、清除浮动 */
overflow: scroll;    /* 永远显示滚动条 */
overflow: auto;      /* 需要时才显示(推荐) */
overflow-x: hidden;  /* 单方向控制 */
text-overflow: ellipsis;  /* 配合下面两条做单行省略号 */
white-space: nowrap;
overflow: hidden;

多行省略(商品标题常用):

css 复制代码
.title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

七、单位:盒模型离不开它

单位 说明 典型用法
px 绝对像素 边框、图标、精确尺寸
% 相对父元素 宽度、响应式
em 相对自身字体大小 padding/margin 随字号缩放
rem 相对根元素字体大小 全站统一缩放
vw/vh 视口宽高的 1% 全屏横幅
calc() 表达式 width: calc(100% - 200px)
css 复制代码
html { font-size: 16px; }
.card { padding: 1rem; }        /* = 16px,改根字号就能整体缩放 */
.header { height: calc(100vh - 60px); }

经验:布局用 %/flex/grid,间距用 rem,边框和阴影用 px。


八、装饰性属性(让页面从"能看"到"好看")

css 复制代码
/* 阴影:商城卡片、弹窗、下拉菜单的灵魂 */
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
box-shadow: 0 4px 12px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04); /* 双层更细腻 */

/* 圆角 */
border-radius: 8px;
border-radius: 8px 8px 0 0;     /* 只圆上面两个角 */

/* 背景 */
background-color: #fff;
background-image: linear-gradient(135deg, #667eea, #764ba2);
background-size: cover;
background-position: center;

/* 鼠标悬停过渡 */
.card { transition: box-shadow 0.2s, transform 0.2s; }
.card:hover { box-shadow: 0 8px 24px rgba(0,0,0,0.12); transform: translateY(-2px); }

transition 只能加在"初始状态"上,不要写在 :hover 里,否则鼠标移开时会瞬间跳回去。


九、调试:学会看 DevTools 的 Box 面板

Chrome 里右键 → 检查元素,右侧 Styles 面板最下面有一个 Box 模型示意图(蓝=content,绿=padding,黄=border,橙=margin)。

排查布局问题的标准动作:

  1. 选中元素,看 Box 面板四边的数字对不对。
  2. 勾选 box-sizing 旁边的复选框切换观察。
  3. 在 Elements 面板右上角打开 Show rulers / 显示元素信息,直接看尺寸。
  4. 怀疑 margin 折叠?看 Computed 里的 margin 实际计算值。
  5. 临时改样式直接在 Styles 里点数字按 ↑↓ 微调,调好再回代码里写。

十、企业级项目的 CSS 起手式

css 复制代码
/* 1. 重置 */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* 2. 基准字号与行高 */
html { font-size: 16px; }
body { font-family: system-ui, -apple-system, "PingFang SC", sans-serif;
       line-height: 1.6; color: #222; background: #f5f5f5; }

/* 3. 图片不溢出 */
img, video { max-width: 100%; height: auto; display: block; }

/* 4. 链接与按钮继承字体 */
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; }

/* 5. 统一容器 */
.container { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 16px; }

这 20 行代码,是所有后台系统、商城前端脚手架的公共基础。


今日小项目:MiniMall 商品列表页(盒模型实战)

目标 :基于昨天的 HTML,用纯 CSS 做出一个带页头、导航、横幅、商品卡片网格、参数表、表单、侧边栏、页脚的完整页面。

重点练 :box-sizing、padding/margin、border-radius/box-shadow、inline-block 与 block、overflow 省略、hover 过渡、响应式。

用法 :复制全部内容 → 存成 index.html → 双击打开 → 试着改 .card 的 padding 和 gap,感受布局变化。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>MiniMall - Day2 CSS 盒模型实战</title>
  <meta name="description" content="企业级商城实战第2天:CSS盒模型完整演示">
  <style>
    /* ===== 0. 重置(企业级起手式) ===== */
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    html { font-size: 16px; }
    body {
      font-family: system-ui, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
      line-height: 1.6; color: #1f2937; background: #f3f4f6;
    }
    img { max-width: 100%; height: auto; display: block; }
    a { color: inherit; text-decoration: none; }
    button, input, select, textarea { font: inherit; }
    ul, ol { list-style: none; }
    table { border-collapse: collapse; }

    /* ===== 1. 容器 ===== */
    .container { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 16px; }

    /* ===== 2. 页头 ===== */
    .site-header {
      background: #fff;
      border-bottom: 1px solid #e5e7eb;
      padding: 16px 0;
    }
    .site-header .container {
      display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px;
    }
    .logo { font-size: 1.5rem; font-weight: 700; color: #111; }
    .logo small { display: block; font-size: 0.75rem; color: #6b7280; font-weight: 400; margin-top: 2px; }
    .search-form { display: flex; gap: 0; }
    .search-form input {
      width: 280px; padding: 8px 12px;
      border: 1px solid #d1d5db; border-right: none; border-radius: 6px 0 0 6px;
      outline: none;
    }
    .search-form input:focus { border-color: #6366f1; box-shadow: 0 0 0 2px rgba(99,102,241,0.2); }
    .search-form button {
      padding: 8px 20px; background: #6366f1; color: #fff; border: none;
      border-radius: 0 6px 6px 0; cursor: pointer; transition: background 0.2s;
    }
    .search-form button:hover { background: #4f46e5; }

    /* ===== 3. 导航 ===== */
    .main-nav { background: #1f2937; }
    .main-nav ul { display: flex; flex-wrap: wrap; }
    .main-nav a {
      display: inline-block; padding: 12px 18px; color: #e5e7eb;
      border-bottom: 2px solid transparent; transition: all 0.2s;
    }
    .main-nav a:hover, .main-nav a.active { color: #fff; background: #374151; border-bottom-color: #818cf8; }

    /* ===== 4. 横幅 ===== */
    .banner {
      background: linear-gradient(135deg, #6366f1, #8b5cf6);
      color: #fff; text-align: center; padding: 56px 16px;
    }
    .banner h2 { font-size: 2rem; margin-bottom: 8px; }
    .banner p { opacity: 0.9; margin-bottom: 4px; }
    .badge {
      display: inline-block; padding: 4px 12px; background: rgba(255,255,255,0.2);
      border-radius: 999px; font-size: 0.85rem; margin-top: 12px;
    }

    /* ===== 5. 主体布局:主栏 + 侧栏 ===== */
    .layout { display: flex; gap: 20px; margin-top: 20px; margin-bottom: 40px; align-items: flex-start; }
    .main { flex: 1; min-width: 0; }          /* min-width:0 防止 flex 子项溢出 */
    .aside { width: 280px; flex-shrink: 0; }

    /* ===== 6. 区块通用 ===== */
    .section {
      background: #fff; border-radius: 10px;
      padding: 20px; margin-bottom: 20px;
      box-shadow: 0 1px 3px rgba(0,0,0,0.06);
    }
    .section-title { font-size: 1.125rem; font-weight: 600; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid #f3f4f6; }

    /* ===== 7. 商品网格(盒模型核心演示) ===== */
    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
      gap: 16px;
    }
    .card {
      background: #fff; border: 1px solid #e5e7eb; border-radius: 10px;
      overflow: hidden;               /* 保证内部图片不溢出圆角 */
      transition: box-shadow 0.2s, transform 0.2s;
      display: flex; flex-direction: column;
    }
    .card:hover { box-shadow: 0 8px 24px rgba(0,0,0,0.1); transform: translateY(-3px); }
    .card-img {
      width: 100%; height: 180px; background: #e5e7eb;
      display: flex; align-items: center; justify-content: center; color: #9ca3af; font-size: 0.875rem;
    }
    .card-body { padding: 14px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
    .card-title {
      font-size: 0.95rem; font-weight: 500; line-height: 1.4;
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    }
    .card-title a:hover { color: #6366f1; }
    .card-tags { display: flex; gap: 6px; flex-wrap: wrap; }
    .tag {
      display: inline-block; padding: 2px 8px; font-size: 0.75rem;
      border: 1px solid #e5e7eb; border-radius: 4px; color: #6b7280;
    }
    .tag.hot { border-color: #fecaca; color: #dc2626; background: #fef2f2; }
    .card-price { margin-top: auto; display: flex; align-items: baseline; gap: 8px; }
    .price { color: #dc2626; font-size: 1.25rem; font-weight: 700; }
    .price-old { color: #9ca3af; font-size: 0.85rem; text-decoration: line-through; }
    .card-footer { padding: 0 14px 14px; }
    .btn {
      display: inline-block; width: 100%; padding: 9px 16px; text-align: center;
      border-radius: 6px; border: none; cursor: pointer; font-weight: 500;
      transition: background 0.2s, box-shadow 0.2s;
    }
    .btn-primary { background: #6366f1; color: #fff; }
    .btn-primary:hover { background: #4f46e5; box-shadow: 0 4px 12px rgba(99,102,241,0.35); }
    .btn-outline { background: #fff; color: #6366f1; border: 1px solid #6366f1; margin-top: 8px; }
    .btn-outline:hover { background: #eef2ff; }
    .btn:disabled { background: #d1d5db; color: #9ca3af; cursor: not-allowed; box-shadow: none; }

    /* ===== 8. 表格 ===== */
    .table-wrap { overflow-x: auto; }
    .data-table { width: 100%; }
    .data-table th, .data-table td { padding: 10px 12px; border: 1px solid #e5e7eb; text-align: left; font-size: 0.9rem; }
    .data-table th { background: #f9fafb; font-weight: 600; }
    .data-table tbody tr:hover { background: #f9fafb; }

    /* ===== 9. 定义列表(参数) ===== */
    .param-list { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 24px; }
    .param-list dt { color: #6b7280; font-size: 0.875rem; }
    .param-list dd { font-weight: 500; font-size: 0.9rem; margin-bottom: 8px; }

    /* ===== 10. 表单 ===== */
    .form-group { margin-bottom: 14px; }
    .form-group label { display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 6px; }
    .form-control {
      width: 100%; padding: 9px 12px; border: 1px solid #d1d5db; border-radius: 6px;
      outline: none; transition: border-color 0.2s, box-shadow 0.2s;
    }
    .form-control:focus { border-color: #6366f1; box-shadow: 0 0 0 3px rgba(99,102,241,0.15); }
    .form-row { display: flex; gap: 12px; }
    .form-row .form-group { flex: 1; }
    .radio-group, .check-group { display: flex; flex-wrap: wrap; gap: 12px; }
    .radio-group label, .check-group label { display: inline-flex; align-items: center; gap: 4px; font-weight: 400; cursor: pointer; }
    .form-actions { display: flex; gap: 10px; margin-top: 18px; }
    .help-text { font-size: 0.8rem; color: #9ca3af; margin-top: 4px; }

    /* ===== 11. 侧边栏 ===== */
    .filter-card { background: #fff; border-radius: 10px; padding: 16px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
    .filter-card h3 { font-size: 0.95rem; margin-bottom: 12px; }
    .filter-list li { margin-bottom: 8px; }
    .filter-list label { display: inline-flex; align-items: center; gap: 6px; font-size: 0.9rem; cursor: pointer; }
    .rank-list { counter-reset: rank; }
    .rank-list li {
      counter-increment: rank; padding: 8px 0; border-bottom: 1px solid #f3f4f6;
      display: flex; align-items: center; gap: 10px; font-size: 0.9rem;
    }
    .rank-list li::before {
      content: counter(rank); display: inline-flex; align-items: center; justify-content: center;
      width: 22px; height: 22px; border-radius: 4px; background: #f3f4f6; font-size: 0.8rem; color: #6b7280; flex-shrink: 0;
    }
    .rank-list li:nth-child(-n+3)::before { background: #6366f1; color: #fff; }

    /* ===== 12. FAQ details ===== */
    details { border: 1px solid #e5e7eb; border-radius: 8px; margin-bottom: 8px; }
    summary { padding: 12px 16px; cursor: pointer; font-weight: 500; list-style: none; display: flex; justify-content: space-between; align-items: center; }
    summary::-webkit-details-marker { display: none; }
    summary::after { content: "+"; font-size: 1.2rem; color: #6b7280; }
    details[open] summary::after { content: "−"; }
    details > p { padding: 0 16px 14px; color: #4b5563; font-size: 0.9rem; }

    /* ===== 13. 页脚 ===== */
    .site-footer { background: #1f2937; color: #9ca3af; text-align: center; padding: 32px 16px; margin-top: 20px; }
    .site-footer nav { margin-bottom: 12px; }
    .site-footer a { color: #e5e7eb; margin: 0 10px; font-size: 0.9rem; }
    .site-footer a:hover { color: #fff; }
    .site-footer small { font-size: 0.8rem; }

    /* ===== 14. 工具类 & 演示块 ===== */
    .box-demo { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
    .box-item {
      width: 140px; padding: 16px; border: 2px dashed #6366f1; background: #eef2ff;
      text-align: center; font-size: 0.85rem; color: #4338ca; border-radius: 8px;
    }
    .box-item.wide { padding: 16px; border-style: solid; border-color: #dc2626; background: #fef2f2; color: #b91c1c; }
    .muted { color: #6b7280; font-size: 0.9rem; }

    /* ===== 15. 响应式 ===== */
    @media (max-width: 900px) {
      .layout { flex-direction: column; }
      .aside { width: 100%; }
      .search-form input { width: 180px; }
    }
    @media (max-width: 600px) {
      .grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
      .param-list { grid-template-columns: 1fr; }
      .form-row { flex-direction: column; gap: 0; }
      .banner h2 { font-size: 1.4rem; }
      .section { padding: 14px; }
    }
  </style>
</head>
<body>

<!-- 页头 -->
<header class="site-header">
  <div class="container">
    <a href="/" class="logo">MiniMall<small>企业级商城实战 · Day 2 · CSS 盒模型</small></a>
    <form class="search-form" action="/search" method="GET" role="search">
      <input type="search" name="kw" placeholder="搜索商品..." aria-label="搜索商品">
      <button type="submit">搜索</button>
    </form>
  </div>
</header>

<!-- 导航 -->
<nav class="main-nav" aria-label="主导航">
  <div class="container">
    <ul>
      <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>
      <li><a href="#">排行榜</a></li>
    </ul>
  </div>
</nav>

<!-- 横幅 -->
<div class="banner">
  <h2>新春焕新季</h2>
  <p>全场满 299 减 50 · 部分商品限时直降</p>
  <p><small>2026-02-01 至 2026-02-15</small></p>
  <span class="badge">点击查看活动规则</span>
</div>

<div class="container">
<div class="layout">

<!-- 主栏 -->
<main class="main">

  <!-- 盒模型可视化演示 -->
  <section class="section">
    <h2 class="section-title">盒模型对照(今天的主角)</h2>
    <p class="muted" style="margin-bottom:12px;">左边 content-box(默认),右边 border-box。两者都写了 <code>width:140px; padding:16px; border:2px</code>,实际占地不一样。</p>
    <div class="box-demo">
      <div class="box-item" style="box-sizing:content-box;">content-box<br><small>实际宽 180px</small></div>
      <div class="box-item wide" style="box-sizing:border-box;">border-box<br><small>实际宽 140px</small></div>
    </div>
    <p class="muted">这就是为什么企业项目第一行 CSS 一定是 <code>*{box-sizing:border-box}</code>。</p>
  </section>

  <!-- 商品列表 -->
  <section class="section">
    <h2 class="section-title">热销商品</h2>
    <div class="grid">
      <article class="card">
        <div class="card-img">商品图 300×180</div>
        <div class="card-body">
          <h3 class="card-title"><a href="#">无线降噪耳机 Pro 主动降噪 40h 续航 蓝牙5.3</a></h3>
          <div class="card-tags"><span class="tag hot">热销</span><span class="tag">自营</span></div>
          <div class="card-price"><span class="price">¥299</span><span class="price-old">¥599</span></div>
        </div>
        <div class="card-footer"><button class="btn btn-primary" type="button">加入购物车</button></div>
      </article>
      <article class="card">
        <div class="card-img">商品图</div>
        <div class="card-body">
          <h3 class="card-title"><a href="#">机械键盘 87 键 热插拔 三模 PBT 键帽</a></h3>
          <div class="card-tags"><span class="tag">新品</span></div>
          <div class="card-price"><span class="price">¥199</span></div>
        </div>
        <div class="card-footer"><button class="btn btn-primary" type="button">加入购物车</button></div>
      </article>
      <article class="card">
        <div class="card-img">商品图</div>
        <div class="card-body">
          <h3 class="card-title"><a href="#">4K 显示器 27英寸 IPS Type-C 反向供电</a></h3>
          <div class="card-tags"><span class="tag hot">爆款</span><span class="tag">包邮</span></div>
          <div class="card-price"><span class="price">¥1299</span><span class="price-old">¥1699</span></div>
        </div>
        <div class="card-footer"><button class="btn btn-primary" type="button">加入购物车</button></div>
      </article>
      <article class="card">
        <div class="card-img">商品图</div>
        <div class="card-body">
          <h3 class="card-title"><a href="#">Type-C 扩展坞 七合一 4K@60Hz HDMI</a></h3>
          <div class="card-tags"><span class="tag">配件</span></div>
          <div class="card-price"><span class="price">¥149</span></div>
        </div>
        <div class="card-footer"><button class="btn btn-outline" type="button" disabled>暂时缺货</button></div>
      </article>
    </div>
  </section>

  <!-- 参数表 -->
  <section class="section">
    <h2 class="section-title">商品参数对比</h2>
    <p class="muted" style="margin-bottom:12px;">同一份数据两种写法:定义列表(键值少)vs 表格(多 SKU 对比)。</p>
    <h4 style="margin-bottom:8px;">定义列表</h4>
    <dl class="param-list" style="margin-bottom:20px;">
      <dt>品牌</dt><dd>MiniMall 自营</dd>
      <dt>型号</dt><dd>MM-2026-A</dd>
      <dt>重量</dt><dd>256 g</dd>
      <dt>连接</dt><dd>蓝牙 5.3 / 有线</dd>
    </dl>
    <h4 style="margin-bottom:8px;">表格</h4>
    <div class="table-wrap">
      <table class="data-table">
        <thead><tr><th scope="col">参数</th><th scope="col">标准版</th><th scope="col">Pro</th><th scope="col">Max</th></tr></thead>
        <tbody>
          <tr><th scope="row">续航</th><td>30h</td><td>40h</td><td>50h</td></tr>
          <tr><th scope="row">降噪</th><td>---</td><td>主动降噪</td><td>自适应降噪</td></tr>
          <tr><th scope="row">价格</th><td>¥199</td><td>¥299</td><td>¥399</td></tr>
        </tbody>
      </table>
    </div>
  </section>

  <!-- 下单表单 -->
  <section class="section">
    <h2 class="section-title">快速下单</h2>
    <form action="/order" method="POST" autocomplete="on">
      <div class="form-row">
        <div class="form-group">
          <label for="uname">姓名</label>
          <input class="form-control" id="uname" name="name" required placeholder="张三">
        </div>
        <div class="form-group">
          <label for="uphone">手机号</label>
          <input class="form-control" id="uphone" name="phone" type="tel" pattern="^1[3-9]\d{9}$" placeholder="13800000000">
          <p class="help-text">用于接收发货通知</p>
        </div>
      </div>
      <div class="form-group">
        <label for="uaddr">收货地址</label>
        <textarea class="form-control" id="uaddr" name="address" rows="3" maxlength="200" placeholder="省市区 + 详细地址"></textarea>
      </div>
      <div class="form-group">
        <label>版本</label>
        <div class="radio-group">
          <label><input type="radio" name="ver" value="std" checked> 标准版 ¥199</label>
          <label><input type="radio" name="ver" value="pro"> Pro ¥299</label>
          <label><input type="radio" name="ver" value="max"> Max ¥399</label>
        </div>
      </div>
      <div class="form-row">
        <div class="form-group">
          <label for="color">颜色</label>
          <select class="form-control" id="color" name="color">
            <option>曜石黑</option><option>珍珠白</option><option>深海蓝</option>
          </select>
        </div>
        <div class="form-group">
          <label for="qty">数量</label>
          <input class="form-control" type="number" id="qty" name="qty" min="1" max="10" value="1">
        </div>
      </div>
      <div class="check-group" style="margin-top:8px;">
        <label><input type="checkbox" name="gift"> 礼品包装</label>
        <label><input type="checkbox" name="agree" required> 同意<a href="#" style="color:#6366f1;text-decoration:underline;">《用户协议》</a></label>
      </div>
      <div class="form-actions">
        <button class="btn btn-primary" type="submit" style="width:auto;padding:9px 32px;">提交订单</button>
        <button class="btn btn-outline" type="reset" style="width:auto;margin-top:0;">重置</button>
      </div>
    </form>
  </section>

  <!-- FAQ -->
  <section class="section">
    <h2 class="section-title">常见问题</h2>
    <details open>
      <summary>支持哪些支付方式?</summary>
      <p>支持微信支付、支付宝、银联云闪付,企业采购可对公转账。</p>
    </details>
    <details>
      <summary>发货时效?</summary>
      <p>工作日 16:00 前下单当日发出,预计 2--3 天送达。</p>
    </details>
    <details>
      <summary>如何开发票?</summary>
      <p>下单时勾选开票,电子发票将在确认收货后发送至邮箱。</p>
    </details>
  </section>

</main>

<!-- 侧栏 -->
<aside class="aside">
  <div class="filter-card">
    <h3>筛选</h3>
    <ul class="filter-list">
      <li><label><input type="checkbox" checked> 仅看有货</label></li>
      <li><label><input type="checkbox"> 包邮</label></li>
      <li><label><input type="checkbox"> 自营</label></li>
      <li><label><input type="checkbox"> 新品</label></li>
    </ul>
    <button class="btn btn-outline" type="button" style="margin-top:10px;">应用筛选</button>
  </div>
  <div class="filter-card">
    <h3>销量排行</h3>
    <ol class="rank-list">
      <li><a href="#">无线降噪耳机 Pro</a></li>
      <li><a href="#">机械键盘 87 键</a></li>
      <li><a href="#">4K 显示器 27"</a></li>
      <li><a href="#">Type-C 扩展坞</a></li>
      <li><a href="#">人体工学椅</a></li>
    </ol>
  </div>
  <div class="filter-card">
    <h3>订阅优惠</h3>
    <div class="form-group" style="margin-bottom:10px;">
      <input class="form-control" type="email" placeholder="你的邮箱">
    </div>
    <button class="btn btn-primary" type="button">订阅</button>
  </div>
</aside>

</div><!-- /layout -->
</div><!-- /container -->

<footer class="site-footer">
  <nav aria-label="页脚导航">
    <a href="#">关于我们</a><a href="#">用户协议</a><a href="#">隐私政策</a><a href="#">站点地图</a>
  </nav>
  <p><small>&copy; 2026 MiniMall · 《企业级平台技术底座》Day 2 配套演示</small></p>
</footer>

</body>
</html>
这个页面覆盖了今天的全部要点

✅ box-sizing: border-box 全局重置 + content-box 对比演示

✅ margin / padding / border 三层拆解 + 简写顺序

✅ border-radius、box-shadow、outline 区别

✅ display: block/inline/inline-block/none

✅ visibility / opacity / display 三者差异

✅ overflow、单行与多行省略号

✅ width/height/min-width/max-width、img 防溢出

✅ px / % / em / rem / vw/vh / calc()

✅ margin 折叠现象与规避

✅ inline-block 幽灵空白

✅ transition 写在初始状态

✅ 表格、表单、按钮的统一样式与 :focus 可见性

✅ flex 主侧栏布局 + grid 商品网格 + 响应式断点

动手任务(10 分钟)
  1. 把 *{box-sizing:border-box} 注释掉,看网格是不是立刻崩了------这个实验做一次终身不忘。
  2. 把 .card 的 padding 从 14px 改成 4px,感受"卡片丑了"的原因。
  3. 给页头加一条 border-bottom,把 logo 和搜索框的间距调到你觉得舒服的值。
  4. 在 DevTools 里选中一张卡片,看 Box 面板上四圈数字分别对应什么。

明天做什么

Day 3:Flex 与 Grid 布局 ------ 今天的网格用了 grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)) 一行搞定四列自适应,明天就把这行语法拆开讲透,顺便实现:顶部导航、商品列表、后台表格、移动端适配,全部不用一行 JS。

相关推荐
Amos_Web3 小时前
我做了一个 Chrome 插件,专治“这篇文章我明明看过,但重点去哪了?”
前端·浏览器
abcyuu3 小时前
用友 U8 Cloud 生产制造模块深度解析:从 BOM 建立到成本核算的技术实现
前端·数据库·制造
零基础1233 小时前
为什么 Agent 用 SQLite 数据库?
前端·人工智能·sqlite·开源
xuyanzhuqing3 小时前
如何在一周内将一个巨石工程实现国际化
前端
数据掘金3 小时前
小程序埋点方案的埋点覆盖率怎么算?
前端
true8033 小时前
跨端开发的相册选择:弃用 uni-app 原生选图 API,直调 Android MediaStore 实现自定义相册架构
前端
数据掘金3 小时前
多AI平台回答快照的差异校验
前端
于航3 小时前
从 Multi-Agent 到 Skill+CLI:个人助理 1.0 → 2.0 架构演进
前端
2301_786756603 小时前
2026 JCR 秋季数据重载解读:影响因子为什么会变?附期刊影响力数据批量追踪方案
java·服务器·前端