在理解CSS是如何控制页面显示效果的时候,我们必须要掌握盒模型(Box Model)和定位(position)机制。CSS借助于盒模型和定位机制,结合文档树,能够精确、高效地控制内容在页面中的位置,从而实现页面的布局。今天要学习的是CSS盒模型。
什么是CSS盒模型
html文档中的每个元素(包括内联元素)都可以看作一个盒子,这些矩形盒子通过一个模型来描述其占用空间,这个模型称为盒模型。盒模型通过四个边界来描述:margin(外边距),border(边框),padding(内边距),content(内容区域),如图所示:
- margin属性定义一个盒子的外间距区域的宽度,分为margin-top, margin-right, margin-bottom, margin-left四部分,其值可以是一个固定长度也可以是百分比值或auto,允许负值。
- border属性定义一个盒子的边框区域的宽度(border-width),颜色(border-color),风格样式(border-style),border属性是这三个属性的简写,分为border-top, border-right, border-bottom, border-left四部分。
- padding属性定义一个盒子的内间距区域的宽度,分为padding-top, padding-right,padding-bottom,padding-left四部分。其值可以是一个固定长度也可以是百分比值,不允许负值。
- content属性定义的是盒子的内容,比如文本内容或图片。
margin的叠加
margin外边距叠加是一个相当简单的概念。但是,在实践中对网页进行布局时,它会造成许多混淆。简单的说,当两个或更多个垂直边距相遇时,它们将形成一个外边距。这个外边距的高度等于两个发生叠加的外边距的高度中的较大者。但是注意只有普通文档流中块框的垂直外边距才会发生外边距叠加。行内框、浮动框或绝对定位框之间的外边距不会叠加。
一般来说,垂直外边距叠加有三种情况:
- 元素自身叠加当元素没有内容(即空元素)、内边距、边框时,它的上下边距就相遇了,即会产生叠加(垂直方向)。当为元素添加内容、内边距、边框任何一项,就会取消叠加。
- 相邻元素叠加相邻的两个元素,如果它们的上下边距相遇,即会产生叠加。
- 包含(父子)元素叠加包含元素的外边距隔着父元素的内边距和边框,当这两项都不存在的时候,父子元素垂直外边距相邻,产生叠加。添加任何一项即会取消叠加。
盒子宽度设置问题(W3C盒模型与IE怪异模型)
IE盒模型缺陷(英语:Internet Explorer box model bug)是指早期版本的Internet Explorer调整网页元素大小的方法,和W3C为层叠样式表(CSS)语言推荐的标准方式不同。在Internet Explorer 6中,浏览器支持一种解决了这种差异的可选的渲染模式(叫做“遵从标准模式”)。然而,出于向后兼容的原因,所有版本的IE(截至IE9及IE10 Developer Preview)仍然默认表现为通常的,非标准的模式。Internet Explorer for Mac不受这种非标准行为影响。此外,Internet Explorer 10于其Consumer Preview之中也改变其默认怪异模式为一种更加符合规范的类似于非IE浏览器的怪异模式。
IE怪异模型与W3C盒模型的区别:
- IE怪异模型盒模型的宽度包含内容(content)、内边距(padding)和边框(border)
- 与W3C盒模型的宽度只包含内容(content)
IE怪异模型与W3C盒模型哪个好?
但从名字看,你一定觉得W3C的盒模型要比IE的怪异模式好,但事实并非如此。
在现实世界中,我们描述一个物理盒子的时候,如果谈到尺寸,是不会只计算其盛放的物体的尺寸的,我们还会算上空隙与盒体本身。拿集装箱装箱为例,我们有100只花瓶,每只花瓶用1个纸盒包装,为了防止花瓶破碎,我们在花瓶周围塞上泡沫,这相当于padding,纸盒的外围纸板相当于border,在装集装箱的时候,为了防止纸盒之间相互碰撞,纸盒之间塞上稻草,这相当于margin,很显然,我们向货运公司报告我们货物尺寸的时候,是要将整个纸盒的尺寸,连同纸盒之间需要塞稻草的空隙都告诉他们的,倘若只报告花瓶的尺寸,货运公司是没有办法装箱的。
在W3C盒模型中,你设置一个元素的width与height只会应用到这个元素的内容区。如果这个元素有任何的border或padding,绘制到屏幕上时的盒子宽度和高度会加上设置的边框和内边距值。这意味着当你调整一个元素的宽度和高度时需要时刻注意到这个元素的边框和内边距。当我们实现响应式布局时,这个特性尤其烦人。
虽然W3C永远都不会承认IE怪异模型的怪异模式要自己的盒模型更好,但他们显然意识到了这个问题,重新定义盒子模型是不可能了,所以,在CSS3中,所以他们添加了:box-sizing
box-sizing有两个可选值,一个是默认的content-box,一个是border-box,选用后者,盒子模型将按IE怪异模型的方式进行处理。
一些专家甚至建议所有的Web开发者们将所有的元素的box-sizing都设为border-box:
*, *:before, *:after { /* Chrome 9-, Safari 5-, iOS 4.2-, Android 3-, Blackberry 7- */ -webkit-box-sizing: border-box; /* Firefox (desktop or Android) 28- */ -moz-box-sizing: border-box; /* Firefox 29+, IE 8+, Chrome 10+, Safari 5.1+, Opera 9.5+, iOS 5+, Opera Mini Anything, Blackberry 10+, Android 4+ */ box-sizing: border-box; }
块元素和内联元素与CSS盒模型的关系
块级元素
在html中<div>、<p>、<h1>、<form>、<ul>和<li>就是块级元素。块级元素特点:
- 每个块级元素都从新的一行开始,并且其后的元素也另起一行。
- 元素的高度、宽度、行高以及顶和底边距都可设置。
元素宽度在不设置的情况下,是它本身父容器的100%(和父元素的宽度一致),除非设定一个宽度。
内联元素
在html中,<span>、<a>、<label>、<strong>和<em>就是典型的内联元素(行内元素)(inline)元素。
内联元素特点:
- 和其他元素都在一行上;
- 元素的高度、宽度及顶部和底部边距不可设置;
- 元素的宽度就是它包含的文字或图片的宽度,不可改变。
内联块状元素
内联块状元素(inline-block)就是同时具备内联元素、块状元素的特点。(css2.1新增),<img>、<input>标签就是这种内联块状标签。
inline-block元素特点:
- 和其他元素都在一行上;
- 元素的高度、宽度、行高以及顶和底边距都可设置。
想要清楚的了解哪个HTML标签属于块元素,哪些是内联元素,请查看:http://htmlreference.io/
display属性
可以通过CSS样式中的display熟悉控制元素是呈现块元素还是内联元素。这个属性用于定义建立布局时元素生成的显示框类型:
值 | 描述 |
none | 让元素隐藏、消失,不占据空间位置 |
block | 让元素呈现块属性特点 |
inline | 让元素呈现行属性特点 |
inline-block | 行内块元素,让元素呈现行元素跟块元素的特性 [a.块元素的宽度默认由内容决定,不再是100%;b.行元素可以设置宽高] |
注释:inline-block在IE7开始支持,在IE6下设置_display:inline;也可以实现相同效果,下划线_是只针对IE6所设置的CSS样式,例:_width:100px;
块级元素与内联元素的主要区别
- 块级元素会独占一行(即无法与其他元素显示在同一行内,除非你显式修改元素的display属性),而内联元素则都会在一行内显示。
- 块级元素可以设置width、height属性,而内联元素设置无效。
- 块级元素高度由设置的高度(height)和宽度(weight)以及内外边距和边框宽度决定。
- 内联元素设置width无效,height无效(可以设置line-height),margin上下无效,padding上下无效。内联元素的高度则有具体字体的font-size与line-height决定。
- 块级元素的width默认为100%,而内联元素则是根据其自身的内容或子元素来决定其宽度。
内容分类与内容模型
根据HTML5新规范,不再根据inline和block来区分元素类型。在HTML5新规范中,每个元素会规定如下两项:
- Content categories(内容分类)
- content models(内容模型)
每一个HTML元素都必须遵循定义了它可以包含哪一类内容的规则。这些规则被归类为几个常见的元素内容模型(content model)。每个HTML元素都属于0个、1个或多个内容模型,每个模型都有一些规则使得元素中的内容必须遵循一个HTML规范文档(HTML-conformant document)。
以下是三种类型的内容分类:
- 主内容类,描述了很多元素共享的内容规范;
- 表单相关的内容类,描述了表单相关元素共有的内容规范;
- 特殊内容类,描述了仅仅在某些特殊元素上才需要遵守的内容规范,通常这些元素都有特殊的上下文关系。
内容模型大致分为以下7种:Flow, Metadata, Embedded, Interactive, Heading, Phrasing和Sectioning。其关系如下:
内容模型的作用在于帮助告诉编程者在某个元素之内适合放置什么类型的内容,这有助于缩小某些HTML规则范围,如元素嵌套。但请记住并不是HTML5所有的元素都会属于这些模型,有些会属于其他分类,比如Transparent或Form-associated。
主内容类(Main content categories)
元数据内容(Metadata content)
此类元素修改文档其余部分的陈述或者行为,建立与其他文档的链接,或者传达其他外带信息。属于这一类的元素有:<base>, <command>, <link>, <meta>, <noscript>, <script>, <style> and <title>.
流式元素(Flow content)
此类元素通常包含文本或植入的内容。此类元素有:<a>, <abbr>, <address>, <article>, <aside>, <audio>, <b>, <bdo>, <bdi>, <blockquote>, <br>, <button>, <canvas>, <cite>, <code>, <command>, <data>, <datalist>, <del>, <details>, <dfn>, <div>, <dl>, <em>, <embed>, <fieldset>, <figure>, <footer>, <form>, <h1>, <h2>, <h3>, <h4>, <h5>, <h6>, <header>, <hgroup>, <hr>, <i>, <iframe>, <img>, <input>, <ins>, <kbd>, <keygen>, <label>, <main>, <map>, <mark>, <math>, <menu>, <meter>, <nav>, <noscript>, <object>, <ol>, <output>, <p>, <pre>, <progress>, <q>, <ruby>, <s>, <samp>, <script>, <section>, <select>, <small>, <span>, <strong>, <sub>, <sup>, <svg>, <table>, <template>, <textarea>, <time>, <ul>, <var>, <video>, <wbr> and Text.
属于此类的少数其他元素(仅限于某种特殊情形,这些元素才会属于此类):
- <area>, 仅限于它作为<map>的子节点的情形
- <link>, 仅限于itemprop属性存在的情形
- <meta>, 仅限于itemprop属性存在的情形
<style>, 仅限于 scoped 属性存在的情形</li>
</ul>
<strong>章节元素(Sectioning content)</strong>
隶属于分节内容模型的元素在当前的大纲中创建一个分节,此分节将定义 <header> 元素、<footer> 元素和标题元素(heading content)的范围。属于此类的元素有:<article>, <aside>, <nav> and <section>.
注意:不要将本内容模型与 sectioning root category 混淆,sectioning root category 的作用是把它的内容与常规的大纲隔离。
<strong>标题元素(Heading content)</strong>
标题内容定义了分节的标题,而这个分节可能由一个明确的分节内容元素直接标记,也可能由标题本身隐式地定义。属于此分类的元素有:<h1>, <h2>, <h3>, <h4>, <h5>, <h6> and <hgroup>.
注意:尽管 <header> 可能包含一些标题内容,但 <header> 并不是标题内容本身。
<strong>短语元素(Phrasing content</strong><strong>)</strong>
短语元素(Phrasing content)规定文本和它包含的标记。一些 Phrasing content 就构成了段落。属于此类的元素有:<abbr>, <audio>, <b>, <bdo>, <br>, <button>, <canvas>, <cite>, <code>, <command>, <datalist>, <dfn>, <em>, <embed>, <i>, <iframe>, <img>, <input>, <kbd>, <keygen>, <label>, <mark>, <math>, <meter>, <noscript>, <object>, <output>, <progress>, <q>, <ruby>, <samp>, <script>, <select>, <small>, <span>, <strong>, <sub>, <sup>, <svg>, <textarea>, <time>, <var>, <video>, <wbr> 和 plaintext (仅当所包含的内容不完全为空字符的时候).
一些其他的元素也属于这个分类,但是只有当如下特殊情况时才会实现:
<ul>
<li><a>, 当它仅包含 phrasing content 时</li>
<li><area>, 当它为 <map> 元素的子元素时</li>
<li><del>, 当它仅包含 phrasing content 时</li>
<li><ins>, 当它仅包含 phrasing content 时</li>
<li><link>, 如果 itemprop 属性存在的情形</li>
<li><map>, 当它仅包含 phrasing content 时</li>
<li><meta>, 如果 itemprop 属性存在的情形</li>
</ul>
<strong>嵌入元素(Embedded content</strong><strong>)</strong>
Embedded content 输入另一个资源或者将来自另一种标记语言或命名空间的内容插入到文档中。属于此类的元素有:<audio>, <canvas>, <embed>, <iframe>, <img>, <math>, <object>, <svg>, <video>。
<strong>交互元素(Interactive content)</strong>
交互式内容包含为用户交互而特别设计的元素。属于此类的元素有:<a>,<button>,<details>,<embed>,<iframe>,<keygen>,<label>,<select> 和 <textarea>。
仅在特殊情形下才会属于此类的元素有:
<ul>
<li><audio>, 若 controls 属性存在</li>
<li><img>, 若 usemap 属性存在</li>
<li><input>, 若 type 属性不处于隐藏(hidden)状态</li>
<li><menu>, 若 type 属性处于工具栏(toolbar)状态</li>
<li><object>, 若 usemap 属性存在</li>
<li><video>, 若 controls 属性存在</li>
</ul>
<strong>表单相关内容(Form-associated content)</strong>
表单相关的内容包含拥有表单父节点(exposed by a form attribute)的元素,一个表单父节点可以是 <form> 元素,也可以是其 id 在表单属性中被指定了的元素。此类包含了几个子类:
<ul>
<li>可列举的元素(listed)在 elements 和 fieldset.elements IDL collections 中列举出的元素. 包括 <button>,<fieldset>,<input>,<keygen>,<object>,<output>,<select> 和 <textarea>。</li>
<li>可标签的元素(labelable)和 <label> 相关联的元素。包括 <button>,<input>,<keygen>,<meter>,<output>,<progress>,<select> 和 <textarea>。</li>
<li>可提交的元素(submittable)包括当表单提交时可以用来组成表单数据的元素。包括 <button>,<input>,<keygen>,<object>,<select> 和 <textarea>.</li>
<li>可重置的元素(resettable)当表单重置时会被重置的元素。包括 <input>,<keygen>,<output>,<select> 和 <textarea>.</li>
</ul>
其中,div 和 p 都属于 Flow content。但它们的内容模型并不同,div 的内容模型是 Flow content,而 p 则是 Phrasing content。这就说明了为什么 p 无法嵌套 div 的原因。
至于为什么要这么划分,那就有待我继续学习啦。
参考链接:
<ul>
<li><a href=”https://developer.mozilla.org/zh-CN/docs/Web/Guide/HTML/Content_categories”>内容分类</a></li>
</ul>