Skip to content

布局与响应式

HTML 搭结构、CSS 加样式,但元素还是从上到下堆叠。真实页面要左右分栏(侧栏+内容区)、横向工具栏(标题+按钮同一行)、小屏幕自动变单栏——这些都是布局的事。

布局核心工具是 Flex(弹性盒)。一个 display: flex 就能让子元素横向或纵向排列,控制对齐、间距和空间分配。

一、文档流与显示类型

浏览器默认按 HTML 出现顺序摆放元素。块级元素(divpsection)各占一行,行内元素(aspan)跟文字流动排在一行。这个默认行为叫文档流——不写任何 CSS 就有的排列方式。

display 属性改变元素的排列行为:block(独占一行)、inline(跟文字排)、inline-block(一行内排但能设宽高)、flex(子元素按弹性盒排)。

css
.tag {
  display: inline-block;
  padding: 2px 8px;
  border: 1px solid #d1d5db;
  border-radius: 999px;
}

inline-block 常用于小标签、短状态这类内容——它不像行内元素那样难控制尺寸。

二、Flex 基础

给父元素设 display: flex,它的直接子元素就进入 Flex 布局:

html
<div class="toolbar">
  <h2>文章列表</h2>
  <button type="button">新增</button>
</div>
css
.toolbar {
  display: flex;
  align-items: center;          /* 垂直居中 */
  justify-content: space-between;  /* 两端分散:标题在左,按钮在右 */
  gap: 12px;                    /* 子元素间距 */
}

justify-content: space-between 把标题推到最左、按钮推到最右——这是页面工具栏最常见的布局。

Flex 的几个关键属性:flex-directionrow 横向排、column 纵向排)、gap(子元素间距)、justify-content(主轴对齐:space-between 两端分散、center 居中)、align-items(交叉轴对齐:center 居中、stretch 拉伸)、flex-wrapwrap 放不下时换行)。

三、弹性尺寸

Flex 子元素可以用 flex 属性控制占用多少空间:

html
<div class="layout">
  <nav class="sidebar">导航</nav>
  <main class="content">文章内容</main>
</div>
css
.layout {
  display: flex;
  gap: 16px;
}

.sidebar {
  width: 220px;
  flex: none;    /* 固定宽度,不伸缩 */
}

.content {
  flex: 1;       /* 占用剩余空间 */
  min-width: 0;  /* 防止内容撑爆 */
}

flex: none 让侧栏保持 220px 不变;flex: 1 让内容区吃掉剩下的所有空间。min-width: 0 在 Flex 内容区里很关键——不写的话,长文本、宽表格会把内容区撑出屏幕,因为 Flex 子元素默认 min-width: auto,不会收缩到比内容更小。

卡片列表换行排列:

css
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.card {
  flex: 1 1 240px;   /* 基础宽度 240px,多了变宽,少了收缩换行 */
  min-width: 0;
}

四、常见页面结构

管理类页面通常长这样:顶部标题栏 + 左侧导航 + 右侧内容区。用 Flex 搭:

html
<div class="shell">
  <header class="header">
    <h1>文章管理</h1>
  </header>
  <div class="body">
    <nav class="sidebar">
      <a href="#published">已发布</a>
      <a href="#drafts">草稿箱</a>
    </nav>
    <main class="content">
      <!-- 文章列表 -->
    </main>
  </div>
</div>
css
.shell {
  min-height: 100vh;    /* 至少占满整个视口高度 */
}

.header {
  padding: 16px 24px;
  border-bottom: 1px solid #e5e7eb;
  background-color: #ffffff;
}

.body {
  display: flex;        /* 侧栏和内容区左右排列 */
}

.sidebar {
  width: 220px;
  flex: none;
  padding: 16px;
  border-right: 1px solid #e5e7eb;
}

.content {
  flex: 1;
  min-width: 0;
  padding: 24px;
}

.body 用 Flex 让侧栏和内容区左右排。侧栏固定 220px,内容区 flex: 1 占剩余空间。这就是大多数后台管理页面的骨架。

五、响应式——小屏幕自适应

同一个页面在桌面(宽屏)和手机(窄屏)上都要能用。桌面左右分栏,手机改成上下排列。用媒体查询@media)在不同宽度下切换布局:

css
@media (max-width: 720px) {
  .body {
    flex-direction: column;   /* 左右排列改成上下排列 */
  }

  .sidebar {
    width: auto;              /* 不再固定 220px */
    border-right: 0;
    border-bottom: 1px solid #e5e7eb;
  }
}

视口宽度小于等于 720px 时,.body 从横向变纵向,侧栏从左侧变成顶部。720px 这个值叫断点——不是固定标准,按内容决定。常见做法:960px 以下减少留白、720px 以下双栏改单栏、480px 以下进一步压缩。

响应式先看内容能不能读、能不能点、会不会横向溢出。动画和细节可以晚点处理。

六、内容溢出

小屏幕上最容易出问题的几种溢出:

宽表格——列多时表格比屏幕宽,加横向滚动容器:

html
<div class="table-wrap">
  <table>
    <!-- 列很多的表格 -->
  </table>
</div>
css
.table-wrap {
  overflow-x: auto;      /* 横向滚动 */
}

.table-wrap table {
  min-width: 520px;      /* 表格本身不压缩,外层滚动 */
}

长文本——长链接或长英文单词不断行会撑宽容器:

css
.content {
  overflow-wrap: anywhere;   /* 长文本强制换行 */
}

固定宽度——写死 width: 320px 在窄屏上会溢出,加 max-width: 100% 兜底:

css
.card {
  width: 320px;
  max-width: 100%;
}

七、完整布局页面

把前面的布局技术合到一个文章管理页面。桌面端双栏(侧栏+内容区),720px 以下自动变单栏。

文件:index.html

html
<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <title>文章管理</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div class="shell">
      <header class="header">
        <h1>文章管理</h1>
      </header>

      <div class="body">
        <nav class="sidebar">
          <a href="#published">已发布</a>
          <a href="#drafts">草稿箱</a>
        </nav>

        <main class="content">
          <section class="card">
            <div class="toolbar">
              <h2>已发布</h2>
              <button type="button">新增</button>
            </div>
            <div class="table-wrap">
              <table>
                <thead>
                  <tr>
                    <th>标题</th>
                    <th>分类</th>
                    <th>状态</th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <td>Python 入门</td>
                    <td>技术</td>
                    <td>已发布</td>
                  </tr>
                  <tr>
                    <td>CSS 布局笔记</td>
                    <td>技术</td>
                    <td>已发布</td>
                  </tr>
                </tbody>
              </table>
            </div>
          </section>
        </main>
      </div>
    </div>
  </body>
</html>

文件:style.css

css
* {
  box-sizing: border-box;
}

body {
  margin: 0;
  color: #111827;
  background-color: #f3f4f6;
  font-family: Arial, "Microsoft YaHei", sans-serif;
  line-height: 1.6;
}

.shell {
  min-height: 100vh;
}

.header {
  padding: 16px 24px;
  border-bottom: 1px solid #e5e7eb;
  background-color: #ffffff;
}

.header h1 {
  margin: 0;
  font-size: 24px;
}

.body {
  display: flex;
}

.sidebar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 220px;
  flex: none;
  padding: 16px;
  border-right: 1px solid #e5e7eb;
  background-color: #ffffff;
}

.sidebar a {
  color: #2563eb;
  text-decoration: none;
}

.content {
  flex: 1;
  min-width: 0;
  padding: 24px;
}

.card {
  padding: 16px;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background-color: #ffffff;
}

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.toolbar h2 {
  margin: 0;
  font-size: 18px;
}

button {
  padding: 8px 12px;
  border: 1px solid #2563eb;
  border-radius: 6px;
  color: #ffffff;
  background-color: #2563eb;
  cursor: pointer;
}

.table-wrap {
  overflow-x: auto;
}

table {
  width: 100%;
  min-width: 400px;
  border-collapse: collapse;
}

th, td {
  padding: 10px 12px;
  border-bottom: 1px solid #e5e7eb;
  text-align: left;
}

th {
  background-color: #f9fafb;
  font-weight: 600;
}

/* 小屏幕:双栏改单栏 */
@media (max-width: 720px) {
  .body {
    flex-direction: column;
  }

  .sidebar {
    width: auto;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 12px;
    border-right: 0;
    border-bottom: 1px solid #e5e7eb;
  }

  .content {
    padding: 16px;
  }
}

拖动浏览器窗口宽度到 720px 以下,侧栏从左边移到顶部,内容区变成全宽——这就是响应式。整个页面到现在还是静态的:点新增按钮没有反应,表格数据是写死的。交互需要 JavaScript,那是接下来的事。

八、常见问题

现象常见原因排查入口
子元素没有横向排列父元素没设 display: flex父元素样式
内容区被表格撑宽Flex 子元素缺 min-width: 0.content 的 min-width
小屏幕仍是双栏媒体查询没命中或被覆盖DevTools 视口宽度、Styles 面板
元素间距不一致混用了 margin 和 gap统一用 gap

布局排查时,开发者工具选中元素看盒模型尺寸、父元素 display、是否命中媒体查询,基本能定位。F12 打开 DevTools,Elements 面板选元素,Computed 区域看实际生效的 display 和尺寸。