盒模型是网页布局的基础 ——每个元素被表示为一个矩形的盒子,盒子的内容、内边距、边框和外边距像洋葱的膜那样,一层包着一层构建起来。浏览器渲染网页布局时,它会算出每个盒子的内容要用什么样式,周围的洋葱层有多大,以及盒子相对于其它盒子放在哪里。在理解如何创建 CSS 布局之前,你需要理解盒模型——这就是本文中我们将要学习的内容。
Prerequisites: | Basic computer literacy, basic software installed, basic knowledge of working with files, HTML basics (study Introduction to HTML), and an idea of How CSS works (study the previous articles in this module.) |
---|---|
Objective: | To learn how the CSS box model works, and how individual elements are laid out on a page. |
盒子属性
文档的每个元素被构造成文档布局内的一个矩形盒子,盒子每层的大小都可以使用一些特定的CSS属性调整。相关属性如下:
width
和height
-
width
和height
设置内容盒(content box)的宽度和高度。内容盒是盒子内容显示的区域——包括盒子内的文本内容,以及表示嵌套子元素的其它盒子。注意: 还有其他属性可以更巧妙地处理内容的大小 — 设置大小约束而不是绝对的大小。这些属性包括
min-width
、max-width
、min-height
和max-height
。 padding
- padding 盒表示一个 CSS 盒子的内边距 — 这一层位于内容盒的外边缘与边框的内边缘之间。该层的大小可以通过简写属性
padding
一次设置所有四个边,或用padding-top
、padding-right
、padding-bottom
和padding-left
属性一次设置一个边。 border
- CSS 盒的边框(border)是一个分隔层,位于内边距的外边缘以及外边距的内边缘之间。边框的默认大小为0——从而让它不可见——不过我们可以设置边框的厚度、风格和颜色让它出现。
border
简写属性可以让我们一次设置所有四个边,例如border: 1px solid black;
但这个简写可以被各种普通书写的更详细的属性所覆盖: -
border-top
,border-right
,border-bottom
,border-left
: 分别设置某一边的边框厚度/风格/颜色。border-width
,border-style
,border-color
: 分别仅设置边框的厚度/风格/颜色,并应用到全部四边边框。- 你也可以单独设置某一个边的三个不同属性,如
border-top-width
,border-top-style
,border-top-color
,等。
margin
-
外边距(margin)代表 CSS 盒子周围的外部区域,在布局中推开其它 CSS 盒子。其表现与与 padding 很相似;简写属性为
margin
,单个属性分别为margin-top
、margin-right
、margin-bottom
和margin-left
。注意: 外边距有一个特别的行为被称作外边距塌陷(margin collapsing):当两个盒子彼此接触时,它们的间距将取两个相邻外边框的最大值,而非两者的总和。
行动学习: 玩玩盒子
在这里, 让我们进入主动学习部分,并通过进行一些练习来说明一些上面讨论的盒子模型的细节。 您可以在下面的实时编辑器中尝试这些练习,但是如果您在本地创建单独的HTML和CSS文件,并在单独的浏览器窗口中尝试,可能会更容易看到某些效果。您可以在Github上找到示例代码。
如果你犯了错误,你可以随时使用“重置”按钮。如果你有点不知所措,按下“显示”按钮可以看到可能的答案。
在下面可编辑的示例中,有三个盒子,它们都包含文本内容并且已经已经被设计为覆盖整个body的宽度。它们由 <header>
, <main>
, and <footer>
这些元素来标记表示。 我们希望您专注于底部的三个CSS规则,即用于每个单独的盒子的规则,并尝试以下操作:
- 通过打开浏览器开发工具并单击DOM检查器中的元素,查看页面上各个元素的盒子模型。有关如何执行此操作的帮助,请参阅探索浏览器开发工具。每个浏览器都有一个盒子模型查看器,它可以准确显示应用于每个盒子的margin,border和padding,内容框(content box)的大小以及元素占用的总空间。
- Set some
margin-bottom
on the<main>
element, say 20px. Now set somemargin-top
on the<footer>
element, say 15px. Note how the 2nd one of these actions makes no difference to the layout — this shows margin collapsing in action; the smaller margin's effective width is reduced to 0, leaving only the larger margin. - Set a
margin
of 30px and apadding
of 30px on every side of the<main>
element — note how the space around the element (the margin) and the space between the border and the content (the padding) both increase, causing the actual content to take up a small amount of space. Again, check this with the browser developer tools. - Set a larger border on all sides of the
<main>
element, say 40px, and notice how this takes space away from the content rather than the margin or padding. You could do this by setting a complete new set of values for the width, style and color with theborder
property, e.g.60px dashed red
, but since the properties are already set in a previous rule, you could just set a newborder-width
. - By default, the content
width
is set to 100% of the available space (after the margin, border, and padding have taken their share) — if you change the browser window width, the boxes will grow and shrink to stay contained inside the example output window. Theheight
of the content will default to the height of the content inside it. - Try setting a new width and height on the
<main>
element — start with say 400px width and 200px height — and observe the effect. You'll notice that the width no longer changes as the browser window is resized. - Try setting a percentage width on the
<main>
element instead — say 60% width — and observe the effect. You should see that the width now changes again as the browser window is resized. Remove the<main>
element'sheight
setting for now. - Try setting your
<main>
element's padding and margin to be 5% on all sides, and observe the result. If you use your browser developer tools to look at the width of the example output window and compare that to the width of the margin/padding, you'll see that this 5% means "5% of the containing element's width." So as the size of the example output window increases, so does the padding/margins. - Margins can accept negative values, which can be used to cause element boxes to overlap. Try setting margin-top: -50px; on the
<main>
element to see the effect. - Keep experimenting!
Playable code
<div class="body-wrapper" style="font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;"> <h2>HTML Input</h2> <textarea id="code" class="html-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"><div id="wrapper"> <header>Header</header> <main>Main content</main> <footer>Footer</footer> </div></textarea> <h2>CSS Input</h2> <textarea id="code" class="css-input" style="width: 90%;height: 12em;padding: 10px;border: 1px solid #0095dd;">/* General styles */ body { margin: 0; } #wrapper * { padding: 20px; font-size: 20px; border: 20px solid rgba(0,0,0,0.5); } /* specific boxes */ #wrapper header, #wrapper footer { background-color: blue; color: white; } #wrapper main { background-color: yellow; } #wrapper header { } #wrapper footer { }</textarea> <h2>Output</h2> <div class="output" style="width: 90%;height: 20em;padding: 10px;border: 1px solid #0095dd;overflow: auto;"></div> <div class="controls"> <input id="reset" type="button" value="Reset" style="margin: 10px 10px 0 0;"> <input id="solution" type="button" value="Show solution" style="margin: 10px 0 0 10px;"> </div> </div>
var htmlInput = document.querySelector(".html-input"); var cssInput = document.querySelector(".css-input"); var reset = document.getElementById("reset"); var htmlCode = htmlInput.value; var cssCode = cssInput.value; var output = document.querySelector(".output"); var solution = document.getElementById("solution"); var styleElem = document.createElement('style'); var headElem = document.querySelector('head'); headElem.appendChild(styleElem); function drawOutput() { output.innerHTML = htmlInput.value; styleElem.textContent = cssInput.value; } reset.addEventListener("click", function() { htmlInput.value = htmlCode; cssInput.value = cssCode; drawOutput(); }); solution.addEventListener("click", function() { htmlInput.value = htmlCode; cssInput.value = '/* General styles */\n\nbody {\n margin: 0;\n}\n\n#wrapper > * {\n padding: 20px;\n font-size: 20px;\n border: 20px solid rgba(0,0,0,0.5);\n}\n\n/* specific boxes */\n\n#wrapper header, #wrapper footer {\n background-color: blue;\n color: white;\n}\n\n#wrapper main {\n background-color: yellow;\n margin: 2%;\n padding: 2%;\n border: 60px solid rgba(0,0,0,0.5);\n width: 60%;\n}\n\n#wrapper header {\n\n}\n\n#wrapper footer {\n margin-top: 20px;\n}'; drawOutput(); }); htmlInput.addEventListener("input", drawOutput); cssInput.addEventListener("input", drawOutput); window.addEventListener("load", drawOutput);
一些提示及想法:
- 默认情况下
background-color
/background-image
延伸到了边框的边界. 该行为可以使用将在Background_clip 章中学到的background-clip
属性来改变。 - 如果内容盒子变得比示例输出的窗口大,它将从窗口溢出,然后滚动条将会出现允许你滚动窗口来查看盒子剩余的内容 。你可以使用
overflow
属性来控制溢出 — 参看下边的 Overflow 章节。 - 盒子的高度不遵守百分比的长度;盒子的高度总是采用盒子内容的高度,除非指定一个绝对的高度(如:px 或者em),它会比在页面上默认是100%高度更实用。
- 边框也忽略百分比宽度设置。
-
你应该注意的是盒子的总宽度是
width
,padding-right
,padding-left
,border-right
, 以及border-left
属性之和。在一下情况下比较讨厌(例如,假使你想要一个盒子总宽度是50%,那么边框和内边距是用像素来表示?),为了避免这种问题,有可能使用属性box-sizing
来调整盒子模型。使用值border-box,它将盒子模型更改成这个新的模型:
高级的盒子操作
在设置盒子的width, height, border, padding 及margin之外, 还有一些其他的属性可以改变它们的行为。本节讨论这些其他的属性。
Overflow
当你使用绝对的值设置了一个盒子的大小(如,固定像素的宽/高),允许的大小可能不适合放置内容,这种情况下内容会从盒子溢出。我们使用overflow
属性来控制这种情况的发生。它有一些可能的值,但是最常用的是:
auto
: 当内容过多,溢出的内容被隐藏,然后出现滚动条来让我们滚动查看所有的内容。hidden
: 当内容过多,溢出的内容被隐藏。visible
: 当内容过多,溢出的内容被显示在盒子的外边(这个是默认的行为)
该示例展示了这些设置是如何工作的:
首先是HTML代码:
<p class="autoscroll"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris tempus turpis id ante mollis dignissim. Nam sed dolor non tortor lacinia lobortis id dapibus nunc. Praesent iaculis tincidunt augue. Integer efficitur sem eget risus cursus, ornare venenatis augue hendrerit. Praesent non elit metus. Morbi vel sodales ligula. </p> <p class="clipped"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris tempus turpis id ante mollis dignissim. Nam sed dolor non tortor lacinia lobortis id dapibus nunc. Praesent iaculis tincidunt augue. Integer efficitur sem eget risus cursus, ornare venenatis augue hendrerit. Praesent non elit metus. Morbi vel sodales ligula. </p> <p class="default"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris tempus turpis id ante mollis dignissim. Nam sed dolor non tortor lacinia lobortis id dapibus nunc. Praesent iaculis tincidunt augue. Integer efficitur sem eget risus cursus, ornare venenatis augue hendrerit. Praesent non elit metus. Morbi vel sodales ligula. </p>
然后是应用到HTML的CSS代码:
p { width : 400px; height : 2.5em; padding: 1em 1em 1em 1em; border : 1px solid black; } .autoscroll { overflow: auto; } .clipped { overflow: hidden; } .default { overflow: visible; }
上边的代码给出了以下的结果:
背景嵌入的方式 Background clip
盒子的背景是由颜色和图片组成的,它们堆叠在一起(background-color
, background-image
.) 它们被应用到一个盒子里,然后被画在盒子的下面。默认情况下,背景延伸到了边框外边。这通常是OK的,但是在一些情况下比较讨厌(假使你有一个平铺的背景图,你只想要它延伸到内容的边界会怎么做?),该行为可以通过设置盒子的background-clip
属性来调整。
让我们通过一个示例来看看这个是怎么工作的。首先是我们的HTML代码:
<div class="default"></div> <div class="padding-box"></div> <div class="content-box"></div>
然后是CSS代码:
div { width : 60px; height : 60px; border : 20px solid rgba(0, 0, 0, 0.5); padding: 20px; margin : 20px 0; background-size : 140px; background-position: center; background-image : url('https://mdn.mozillademos.org/files/11947/ff-logo.png'); background-color : gold; } .default { background-clip: border-box; } .padding-box { background-clip: padding-box; } .content-box { background-clip: content-box; }
上边的代码产生了以下结果:
Outline
Last but not least, the outline
of a box is something that looks like a border but which is not part of the box model. It behaves like the border but is drawn on top of the box without changing the size of the box (to be specific, the outline is drawn outside the border box, inside the margin area.)
Note: Beware when using the outline property. It is used in some cases for accessibility reasons to highlight active parts of a web page such as links when a user clicks on them. If you do find a use for outlines, make sure you don't make them look just like link highlights as this could confuse users.
CSS 盒子类型
之前我们说的所有对于盒子的应用都表示的是块级元素的,然尔,CSS还有一些表现不同的其他盒子类型。盒子应用通过指定display
属性,这个属性有很多的属性值,在本篇文章,我们将关注三个最普遍的类型:block
, inline
, and inline-block。
- 块盒(
block
box)是定义为堆放在其他盒子上的盒子(例如:其内容会独占一行),而且可以设置它的宽高,之前所有对于盒模型的应用适用于块盒 (block
box) - 行内盒(
inline
box)与块盒是相反的,它随着文档的 文字(例如:它将会和周围的文字和其他行内元素出现在同一行,而且它的内容会像一段中的文字一样随着文字部分的流动而打乱),对行内盒设置宽高无效,设置padding, margin and border都会更新周围文字的位置,但是对于周围的的块盒不会有影响。 - 行内块状盒(
inline-block
box) 像是上述两种的集合:它不会重新另起一行但会像行内盒(inline
box)一样随着周围文字而流动,而且他能够设置宽高,并且像块盒一样保持了其块特性的完整性-它不会在段落行中断开(在下面的示例中,内联框会放在第二行文本上,因为第一行没有足够的空间,并且不会突破两行。)
注意:默认状态下display属性值,块级元素display: block,行内元素
display: inline
这些东西在短时间听起来可能让你很混乱,现在让我们来看一些简单的小例子。
First, the HTML:
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. <span class="inline">Mauris tempus turpis id ante mollis dignissim.</span> Nam sed dolor non tortor lacinia lobortis id dapibus nunc. </p> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. <span class="block">Mauris tempus turpis id ante mollis dignissim.</span> Nam sed dolor non tortor lacinia lobortis id dapibus nunc. </p> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. <span class="inline-block">Mauris tempus turpis id ante mollis dignissim.</span> Nam sed dolor non tortor lacinia lobortis id dapibus nunc. </p>
Now let's add some CSS:
p { padding : 1em; border : 1px solid black; } span { padding : 0.5em; border : 1px solid green; /* That makes the box visible, regardless of its type */ background-color: yellow; } .inline { display: inline; } .block { display: block; } .inline-block { display: inline-block; }
This above code gives this result, which illustrates the different effect of the display types:
What's next
At this point, you should have some familiarity with CSS boxes and how they work. Don't worry if you don't fully understand all of this now — you can feel free to reread this article to gain a better understanding, plus you'll start to understand things better when you start to work through some more practical examples later in the course. Next we will have a look at Debugging CSS.