本节摘要:属性是 CSS 的词汇表,布局是它的语法。本节以盒模型为轴心:两种 box-sizing 算法的差异与全局设定,边距折叠这个经典陷阱,然后讲弹性布局的主轴交叉轴心智模型,用三五条声明解掉常见版面题,最后过一遍文字与颜色属性要点,收于媒体查询的响应式入门。
阅读完本节,你应当能够:
浏览器把每个元素渲染成一个矩形盒子,从里到外四层:内容、内边距、边框、外边距。内容是文字或子元素的地盘;内边距是内容与边框之间的呼吸空间;边框划界;外边距是盒子与其他盒子之间的社交距离。四层叠加决定盒子占多大地方,而"占多大"有两种算法,这正是新手版面错乱的根源。
content-box(默认):width 只管内容区,实际占宽 = width + 左右内边距 + 左右边框。设宽 200、边距各 20 的盒子实际占 240。border-box:width 管到边框为止,内边距与边框向内挤压内容。同样是 200 宽,内部空间自动缩,盒子占宽恒为 200。
/* 现代项目的标准起手式:全站 border-box */ *, *::before, *::after { box-sizing: border-box; }
这行"通配符重置"的价值在栅格布局里最明显:两栏各 50% 宽,若用 content-box 再加边距,总宽超 100% 版面必炸;border-box 下盒子永远守约。今天几乎所有样式框架都默认它,新项目第一行样式就该是它。
边距折叠是盒模型的另一个经典陷阱:垂直方向相邻的两个外边距不叠加,取大者。上盒子下边距 30、下盒子上边距 20,两者间隔是 30 不是 50。折叠只在常规文档流的垂直方向发生,弹性或网格容器的子项之间不折叠,这一条差异也是"布局用弹性盒子、别用边距硬凑"的理由之一。

弹性盒子(flexbox)解决"一条线上怎么排"的问题:导航条、工具栏、卡片行、表单行,全是一维场景。它只有两个方向要理解——主轴(排列方向)与交叉轴(垂直于主轴)。容器上声明 display 值为 flex,子项立刻沿主轴排队。
.toolbar { display: flex; flex-direction: row; /* 主轴横向,row 为默认 */ justify-content: space-between; /* 主轴分布:两端对齐中间均分 */ align-items: center; /* 交叉轴对齐:垂直居中 */ gap: 12px; /* 子项间距,替代边距社交学 */ }
记住分工口诀:justify-content 管主轴,align-items 管交叉轴。方向一换(row 改 column),两根轴跟着换,同一对属性的含义就对调——先定方向再想对齐,就不会晕。
子项侧最有用的三个弹性属性:flex-grow(瓜分剩余空间的份额,全是 1 就均分;某项是 2 就多拿一倍)、flex-shrink(空间不足时谁缩谁不缩,0 为不缩)、flex-basis(瓜分前的基准尺寸)。日常缩写 flex: 1( grow 一份、基准零)与 flex: 0 0 auto(不伸不缩按内容)覆盖九成场景。
几个高频版面题的三五条声明解法,直接抄:
/* 题一:完美居中(水平垂直) */ .center { display: flex; justify-content: center; align-items: center; min-height: 200px; } /* 题二:两栏自适应——侧栏固定,主栏吃掉剩余 */ .layout { display: flex; gap: 24px; } .sidebar { flex: 0 0 240px; } /* 不伸不缩,恒 240 */ .main { flex: 1; } /* 剩余全归我 */ /* 题三:等宽卡片行,放不下自动换行 */ .cards { display: flex; flex-wrap: wrap; gap: 16px; } .cards > * { flex: 1 1 240px; } /* 基准240,可伸可缩 */ /* 题四:导航条——品牌靠左,菜单靠右 */ .nav { display: flex; align-items: center; gap: 16px; } .nav .menu { margin-left: auto; } /* auto 边距吃掉全部剩余空间 */
题四的 margin-left: auto 是弹性布局的隐藏好牌:auto 边距吸收主轴剩余空间,一行实现"推到最右"。gap 属性则终结了"子项之间加边距、首尾再掏掉"的祖传技巧——间距写在容器上,子项零心理负担。二维版面(行与列同时要管)交给网格布局,本节入门阶段记住"一维用弹性、二维用网格"的分界即可,综合实战章会用网格搭整体版面。
版面之外的高频属性集中在文字与颜色两族。文字族:font-size(字号,注意用相对单位更利于缩放)、font-weight(字重)、line-height(行高,推荐无单位数值让字号缩放时行高按比例跟)、text-align(对齐)、text-decoration(下划线等)。颜色族:color(文字)、background(背景,可叠色、图、渐变)、border(边框简写:宽度 样式 颜色)。
组织原则是继承打底、例外覆盖:字体、字号、颜色、行高在 body 或容器层设一次,后代全继承;个别区域不同再局部覆盖。反面教材是每个元素都写一遍字体字号——改版时几百处要动。这套"全局打底"也是排版一致性的来源:全站行高统一 1.7、正文字号统一一处声明,视觉质感立刻不同。
间距体系同理:把常用间距收敛成几档(如 8 的倍数:8、16、24、48),全站只用这几档。散乱的 13px、17px、29px 边距是视觉毛糙的主因,收敛档位是最低成本的"设计系统入门"。
版面最后一个维度是屏幕宽度。媒体查询让样式按条件生效,核心语法一句话:@media 加条件,内部写覆盖规则。
.cards { display: flex; gap: 16px; } .cards > * { flex: 1 1 240px; } /* 窄屏:卡片纵向堆叠 */ @media (max-width: 600px) { .cards { flex-direction: column; } .layout { flex-direction: column; } .sidebar { flex: 0 0 auto; } }
写法惯例是"移动优先":默认样式面向小屏,媒体查询里用 min-width 逐级增强宽屏。这与第 2 章多媒体的降级思路一致——基础体验最稳,增强能力按条件叠加。媒体查询里最常用的条件就是宽度断点(max-width / min-width),选断点的依据是内容而非设备型号:内容在多窄开始拥挤,断点就设在哪。真正做好响应式还需要相对单位与图片自适应配合,这里立框架,深化留给实战章。
弹性布局解决"排队",但有几类需求本质是"出队"——提示气泡、模态遮罩、吸顶导航。这就是定位属性的位置:position 取 relative(相对原位偏移,原位保留)、absolute(相对最近的已定位祖先脱离文档流)、fixed(相对视口,滚动不动)、sticky(滚动到阈值前常规流、越界后吸附)。其中 sticky 一条声明就实现吸顶表头与导航,是性价比最高的定位值。
/* 吸顶导航:滚出视口前正常排队,越界后钉在顶部 */ .site-nav { position: sticky; top: 0; background: #fff; border-bottom: 1px solid #eee; } /* 提示气泡:父容器 relative,气泡 absolute 出队 */ .badge-wrap { position: relative; } .badge-wrap .tip { position: absolute; top: -28px; left: 50%; transform: translateX(-50%); /* 自身宽度的一半回拉,水平居中的标准写法 */ background: #2c3e50; color: #fff; padding: 2px 8px; border-radius: 4px; }
absolute 的参照物是"最近的 position 值非 static 的祖先",没有则退到初始包含块。这个规则制造了大量"气泡飞到页面角落"事故——解法永远是检查祖先链上谁被定位了。定位脱流的元素会层叠,层叠顺序(谁盖住谁)由 z-index 参与,但其生效前提是元素已被定位或有其他层叠触发条件;"z-index 死活不生效"的第一嫌疑人就是忘了加 position。定位是布局的补丁库而不是主工具:能用正常流与弹性解决的排队问题,不要用绝对定位硬摆——绝对定位的盒子互相不知道对方的存在,内容一变就互相覆盖。
再加一个综合口诀收束本节的定位知识:静态排队用文档流、出队吸附用 sticky、一维排队用弹性、二维对齐用网格、绝对坐标是最后手段——五级工具从稳到险,先用前面的。
问:行内元素之间的"诡异空隙"怎么来的,怎么去?
第 1 章埋的伏笔这里收:源码里行内元素之间的换行被折叠成一个空格,显示为几像素的缝。去掉办法有四:标记写在同一行、父容器字号设为零、用弹性容器排版(子项无缝)、注释填补法。现代工程首选弹性容器——它从布局模型上就没有这个缝。
问:min-height 和 height 什么时候用哪个?
内容量不可预知时用 min-height:容器至少这么高、内容多了自动撑开;height 则钉死,内容溢出会被裁剪或溢出可见。表单区、空状态占位、首屏图区都该用 min-height。顺手记住 height 百分比生效的前提是父级有明确高度——"百分比高度不生效"的祖传问题,根因几乎都在祖先链断了高度。
弹性盒子管一条线,网格(grid)管一个面。当版面同时需要"行与列都对齐"——整页骨架、图片墙、表单双列——网格是更贴手的工具。最小可用集只有三条:容器声明 display 值为 grid;grid-template-columns 定义列轨道(几列、各多宽);gap 管间距。列宽写法里最有表达力的是分数单位:三列写"1fr 2fr 1fr"表示按 1:2:1 瓜分可用宽度,比百分比优雅在自带间距计算。
.page { display: grid; grid-template-columns: 220px 1fr; /* 侧栏固定,主区吃剩余 */ grid-template-rows: auto 1fr auto; /* 头部、内容、页脚三行 */ min-height: 100vh; gap: 0; }
这五行就是"侧栏加主区、页头页脚贴边"的整页骨架,配合 min-height 实现页脚沉底——老技术栈里要用各种边距技巧硬凑的经典题,网格时代一个声明组合终结。网格与弹性不是竞争关系而是分界关系:容器内部的一维排队用弹性,容器之间的二维对齐用网格,整页骨架网格搭、骨架内每个区域弹性排,是现代布局的标准姿势。实战章会把这套姿势组装成完整页面。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>布局三题</title> <style> *, *::before, *::after { box-sizing: border-box; } body { font-family: sans-serif; margin: 0; padding: 16px; line-height: 1.7; } .center { display: flex; justify-content: center; align-items: center; min-height: 120px; border: 1px dashed #bbb; margin-bottom: 16px; } .layout { display: flex; gap: 24px; } .sidebar { flex: 0 0 220px; background: #eaf2fc; padding: 12px; } .main { flex: 1; background: #eefaf0; padding: 12px; } @media (max-width: 640px) { .layout { flex-direction: column; } .sidebar { flex: 0 0 auto; } } </style> </head> <body> <div class="center">我在正中央(题一)</div> <div class="layout"> <aside class="sidebar">侧栏固定 220(题二)</aside> <main class="main">主栏吃掉剩余宽度,拖动窗口试试。窄屏下两栏变堆叠(响应式)。</main> </div> </body> </html>
三件事动手做:拖动浏览器窗口看两栏自适应与断点切换;把通配符 box-sizing 那行注释掉,给两个盒子加上大内边距,观察版面如何被撑爆;把 align-items 改成 flex-start,体会交叉轴方向的差异。十分钟做完,轴模型与两种算法就长在手上了。
💡 关键直觉:布局排错时先量盒子。开发者工具悬停任意元素,四层盒模型直接描边显示在页面上——先看盒子实际多大、边距多宽,再回头查声明,比盯代码猜快得多。
(布局是肌肉记忆型知识,三题实验值得隔周重做一次,直到不看小抄也能写出居中、两栏与响应式三题为止。)
第 3 章收官。结构有了、外观有了,下一章给页面做体检:规范、可访问性、SEO 与验证。祝你的下一个版面一次成型、条纹整齐、页脚沉底、窄屏堆叠不乱。