Article Title
…
Section Title
…
…
…
为了用 CSS 样式化一个元素,我们需要能够定位它。进入 CSS 选择器,它允许我们定位 DOM 中的特定元素。
使用 CSS3 选择器,我们可以在比以前更细粒度的层次上定位元素。这意味着你的标记可以非常简洁、语义化和灵活。此外,新元素状态伪类允许额外突出动态状态变化。
在前一章中,你已经复习了级联、继承和 CSS 特性。在这一章中,我们将提醒自己选择器的基础知识。然后我们将看看 CSS3 属性选择器,接着是结构元素状态、:target
和否定伪类。然后,我们将简要介绍 CSS 2.1 的生成内容伪元素:before
和:after
,看看它们如何很好地处理 HTML5 的部分,我们将在 CSS3 中引入新的双冒号语法。我们还将看看当前浏览器对 CSS 选择器的支持,以及 CSS 选择器的前景。最后,我们将简要讨论第七章中描述的 Selectivzr polyfill,它允许你在所有浏览器中使用这些新的选择器。
W3C 选择器级别 3 ( [
j.mp/w3cselectors](http://j.mp/w3cselectors)<sup>1</sup>
)模块在 2011 年 9 月成为推荐标准。它列出了所有的选择器(总共不到 40 个),而不仅仅是 CSS3 中的那些。正如您已经了解到的,这是因为 CSS3 并不是一个全新的规范,而是建立在 CSS1 和 CSS 2.1 之上的。如果你认为 40 个选择器需要学习很多,不要担心——你可能已经知道很多了。
CSS1 中引入了以下选择器:
p {...}
、blockquote {...}
)blockquote p {...}
)<article id="content">
上的#content {...}
< article class="hentry">
上的.hentry {...}
a:link {...}
或a:visited {...}
)a:active {...}
):first-line
伪元素(如p:first-line {...}
:first-letter
伪元素(如p:first-letter {...}
如果其中任何一个你看起来不熟悉(我们会原谅最后两个),那么我们建议你查一下。SitePoint CSS 参考是一个很好的起点。 2
CSS 2.1 中又增加了 11 个选择器。
* {...}
)a:hover {...}
和a:focus {...}
):lang()
伪类(例如article:lang(fr) {...}
)p:first-child {...}
):before
和:after
伪元素(如blockquote:before {...}
或a:after {...}
h2 > p {...}
)h2 + p {...}
)input [required] {...}
)input [type="checkbox"] {...}
)input [class~="long-field"] {...}
)input [lang|="en"] {...}
)1
2
其中一些你可能知道。但是,如果您以前没有看到它们,也不用担心,因为 CSS3 选择器 3 级模块是在这些基础上构建的,并添加了功能。
我们将在本章中看到的 CSS3 中添加的选择器如下:
h1 ~ pre {...}
)a[href^="http://"] {...}
)开头a[href$=".pdf"] {...}
)结尾a[href*="twitter"] {...}
):target()
伪类(例如section:target {...}
)nth-child
(例如tr:nth-child(even) td {...}
)nth—last-child
(例如tr:nth—last-child(-n+5) td {...}
)last-child
(例如ul li:last-child {...}
)only-child
(例如ul li:only-child {...}
)first-of-type
(例如p:first-of-type {...}
)last-of-type
(例如p:last-of-type {...}
)nth-of-type
(例如li:nth-of-type(3n) {...}
)nth-last-of-type
(例如li:nth-last-of-type(1) {...}
)only-of-type
(例如article img:only-of-type {...}
)empty
(例如aside:empty {...}
)root
(例如:root {...}
):disabled
和:enabled
(如input:disabled {...}
):checked
(例如input[type="checkbox"]:checked {...}
):not
(例如abbr:not([title]} {...}
)通过查看这三个列表,我们可以得出结论,CSS3 中引入的 CSS 选择器数量与 CSS 1 和 CSS 2.1 中引入的数量相同。这对我们来说太难了,所以让我们直入主题吧。
我们已经到了有趣的部分——CSS3 选择器。由于有一系列不同的选择器可供我们使用,所以很难决定使用哪种类型的选择器。随着新的 CSS3 选择器的引入,我们将为它们提供真实世界的用例,您可以从今天开始在您的项目中使用它们。首先是组合子。
假设你以前使用过 CSS,你几乎肯定遇到过组合子。毫无疑问,您知道后代选择器,之所以这样称呼是因为它们的目标是子元素、孙元素或文档树中给定元素的后续元素。最简单的情况是,后代组合子允许您将位于另一个元素类型中的单个元素类型的所有实例作为目标,比如article p {...}
。
相反,子组合子只针对那些父元素的直接子元素。他们使用大于号(>
)运算符。因此,article > p {...}
的目标是那些属于article
的子段落,而不是嵌套在文章下面的section
中的段落,如下面的代码示例所示:
article > p { font-size:125%; }
下一个组合子,相邻兄弟,目标是在文档树中彼此相邻并具有相同父元素的元素。再次使用前面的例子,我们可以使用+
操作符编写h2 + p {...}
来设计每个section
(假设它们都使用h2
标题)的开头段落:
h2 + p { font-weight:bold; }
以下代码显示了哪个选择器针对哪个段落:
`
…
…
…
…
到目前为止我们看到的例子都是 CSS 2.1 中包含的组合子,那么 CSS3 呢?
CSS3 添加了通用的兄弟组合符,它使用波浪号(~
)操作符。当使用一般的兄弟组合子时,第二个选择器不必紧跟着第一个选择器;但是,选择器的两个部分必须仍然共享同一个父级。扩展这个例子,我们可以在深度嵌套的部分中使用一般的兄弟组合来定位ul
,如下所示:
`h3 ~ ul {
list-style-type:binary;
}
...
...
...
...
...
...
这展示了 CSS 中组合子的力量,特别是 CSS3 如何让我们对目标元素有更多的控制。
在本章的介绍中,你学习了 CSS 2.1 引入了属性选择器。CSS3 通过增加工具箱中子串选择器的数量,扩展了我们可以使用的属性选择器列表。这意味着我们现在可以瞄准一个规则,并根据属性值的一部分将 CSS 样式应用于元素。简而言之,我们将看到如何使用它们来样式化文档下载链接或电子邮件地址,但是首先让我们简单回顾一下 CSS 2.1 的属性和子串选择器。
如果给定的属性存在,最基本的属性选择器允许您设置元素的样式。例如,我们可以使用下面的代码来设计任何具有title
属性的缩写元素的样式:
abbr[title] { border-bottom:1px dotted #000; }
或者我们可以通过使用您在第六章的中遇到的required
属性来指出那些需要的字段。
input[required] { background:url(img/mandatory-icon.png) 100% 50% no-repeat;
padding-right:20px; }
使用 equals ( =
)操作符,我们的属性选择器可以匹配给定属性的特定值,比如复选框。
input[type="checkbox"] { width:20px; height:20px; }
目前还没有太疯狂的事。接下来,我们可以使用波浪号(~
)操作符从一列空格分隔的值中指定一个特定的属性值。这对于用微格式或微数据标记的内容非常有用,这些内容通常使用多个属性值。
<a ... rel="external license">...</a>
以rel
属性的license
值为目标的 CSS 应该是:
a[rel~="license"] { background:url(img/copyright.png) 100% 50% no-repeat; padding-right:20px; }
最后一个 CSS 2.1 属性选择器不经常使用,但是如果您在使用多种语言的站点上工作,它会很有用。竖线(|
)操作符允许您从特定值开始定位包含在带连字符列表中的元素。假设您想要将指定了英语语言的锚点作为目标,而不管它是英式英语(en-GB)还是美式英语(en-US)(因为它们都包含“en”)。
a[hreflang|="en"] { border-bottom:3px double #000; }
最后两个例子介绍了两个操作符,我们可以用它们来匹配属性值的子串部分。CSS3 更进一步,使用^
、$
和*
操作符提供了三个额外的子串选择器。它们非常有用,可以用来确保您的标记保持超级干净,没有不必要的类,同时增强用户的体验。
脱字符号(^
)操作符,当与子字符串选择器相关时,意味着“开始于”例如,我们可以使用它来定位我们内容中的所有外部链接,并添加一个小图标来指示它们是外部链接。下面的代码通过使用^
属性子串选择器向所有以http://
开头的链接添加背景图像和填充:
a[href^="http://"] { background:url(img/external.png) 100% 50% no-repeat; padding-right:15px; }
在图 8-1 中,你可以看到外部链接在锚点的末端有一个小图标。这个图标,一个有箭头指向的盒子,已经成为一个被广泛认可的外部链接符号。
**图 8-1。**使用^
属性子串选择器样式的外部链接
这是一个快速添加图标到外部链接的好方法,但是你可能有一些以http://
开头的链接不是外部链接,比如你自己网站的链接。在这种情况下,您不希望图标出现。我们可以通过在最初的规则下添加另一个规则(因为它们具有相同的特异性)来解决这个异常,从而使我们域的外部链接的属性集无效。因为链接可能指向站点内的不同页面,所以保留了^
操作符。
`a[href^=“http://”] {
background:url(img/external.png) 100% 50% no-repeat;
padding-right:15px;
}
a[href^=“http://thewebevolved.com”] {
background:none;
padding-right:0;
}`
图 8-2 显示了这一点。有两个用图标表示的外部链接和一个图标被移除的内部链接(“许多猴子”)。
**图 8-2。**使用^
属性子串选择器进行样式化的外部链接和以http://
开头但没有样式化的内部链接
^
操作符的另一个用途可能是指向以mailto:
字符串开始的电子邮件链接,并添加一个图标和填充。
a[href^="mailto:"] { background:url(img/email.png) 100% 50% no-repeat; padding-right:15px; }
我们已经讨论了“始于”,现在让我们来看看“止于”这个操作符是美元符号$
,语法与^
语法完全相同。常见用途包括添加图标来表示文档下载的不同文件类型或指示不同的提要类型。
要指示链接指向 PDF 文档,您可以使用
a[href$=".pdf"] { background:url(img/pdf.png) 100% 50% no-repeat; padding-right:18px; }
在图 8-3 中,文本“生活杂志”链接到一个 PDF 文档。使用前面的代码,我们在链接中添加了一个小的 PDF 图标来表示这一点。
**图 8-3。**使用$
属性子串选择器样式化的 PDF 链接
您可以使用此方法来定位任何文件类型,如。医生。jpg 或. xml。
我们要查看的最后一个子字符串选择器使用了星号或星号(*
)操作符,它代表“contains”它允许您将应用了多个类的元素作为目标。它还可以用于定位锚点中的特定域。在下面的例子中,它被用来突出显示那些链接到一个人的 Twitter 账户的锚(结果见图 8-4 ):
a[href*="twitter"] { background:url(img/twitter.png) 100% 50% no-repeat; padding-right:20px; }
**图 8-4。**使用*
属性子串选择器设计的 Twitter 账户链接
使用^
操作符和值[
twitter.com](http://twitter.com)
可以达到同样的效果,但是使用*
操作符可以帮助我们节省一些字节。当我们想要根据 Twitter 句柄(例如, [
twitter.com/ZsaZsa](http://twitter.com/ZsaZsa)
)对其中一个 Twitter 链接进行不同的样式化时,*
子字符串选择器的真正威力就显现出来了。为了澄清,所有的链接都包含“twitter”,就像前面的例子一样,但是只有一个包含“ZsaZsa”。
a[href*="ZsaZsa"] { background:url(img/twitter.png) 100% 50% no-repeat; padding-right:20px; color:#ff0; }
我们还可以使用*
操作符,通过使用 XFN 微格式来表明我们与朋友、家人和其他人的关系状态,正如在第四章中介绍的那样。例如,如果我们想表明玛丽莲·梦露是我们的心上人,我们的标记可能如下所示:
<a href="http://twitter.com/marilynmonroe" rel="met sweetheart friend">Marilyn Monroe</a>
因为rel
属性有三个值,使用^
或$
操作符很难确定目标,所以*
(包含)成为一个选项,CSS 2.1 波浪号(~
)也是如此,它也可以在这个实例中使用,因为值是用空格分隔的。对于这个例子,我们将使用新的 CSS3 子串选择器*
:
a[rel*="sweetheart"] { background:url(img/sweetheart.png) 100% 50% no-repeat; padding-right:20px; }
你有它!玛丽莲·梦露是我们的心上人(见图 8-5 )。
**图 8-5。**使用*
属性子串选择器样式化的甜心关系
不过,你可能已经发现了一个问题:玛丽莲的 Twitter 图标不见了。这是因为两种样式规则具有相同的特异性,并且a[rel*="sweetheart"] {...}
规则出现在样式表的更下方。我们可以通过在甜心规则中添加一些额外的填充来解决这个问题,并使用多个背景图片(更多细节,见第十一章)来添加放置在不同位置的两个图标。
a[rel*="sweetheart"] { background: url(img/sweetheart.png) 100% 50% no-repeat, url(img/twitter.png) 85% 50% no-repeat; padding-right:40px; }
大多数表单元素都有可能被启用、禁用或选中。通过使用 UI 元素状态伪类,我们可以在这些元素处于特定状态时定位它们,比如复选框被选中。让我们看一个基本的登录表单,看看如何实现这些元素状态伪类。图 8-6 显示了正常情况下的表单。
**图 8-6。**正常样式的登录表单
现在假设用户名和密码字段以及登录按钮已经被禁用。接下来显示了这方面的 HTML,并在需要的地方应用了disabled
属性。
`
Login `我们现在需要适当地设置字段的样式,以显示它们已被禁用。我们可以在那些需要的元素上使用:disabled
伪类来设计这些状态(在本例中是所有的input
)。
input:disabled { background:#999; border:1px solid #666; }
我们将禁用字段和按钮的背景颜色设置为灰色,这样它们看起来就不“活动”或不可点击。这显示在图 8-7 的右侧中。
**图 8-7。**使用:disabled
、:enabled
和:checked
UI 元素状态的登录表单的两个实例
:checked
和:enabled
伪类的工作方式完全相同。正如你在图 8-7 左侧的表格中看到的,我们已经高亮显示了选中复选框旁边的“记住我”标签(使用相邻的兄弟组合符)。我们还用不同的边框颜色突出显示了已启用的字段(属性选择器用于确保更高的特异性)。
`input[type=“checkbox”]:checked + label {
display:inline;
background: #F9FDA2;
}
input[type=“text”]:enabled, input[type=“password”]:enabled {
border:1px solid #75aadb;
}`
当状态为活动时,这些 UI 元素状态伪类被切换(选中/未选中)并应用。使用它们可以为用户提供有用的视觉反馈,并改善您的网站体验,而无需您付出太多努力。
CSS 基本用户界面模块三级
选择器模块之外是另一个包含伪类的模块,CSS 基本用户界面模块 Level 3 ( [
j.mp/css3uimodule](http://j.mp/css3uimodule)<sup>3</sup>
)。在这个模块中,你会发现一些额外的 UI 状态伪类,类似于上面讨论的那些。它们是:
默认必需
有效可选
无效只读
范围内读/写
范围外
当与我们在第六章中遇到的 HTML5 表单一起考虑时,这些伪类非常有用。浏览器支持类似于 CSS3 选择器。有些需要厂商前缀,但请放心,它们很快就会出现在您附近的浏览器中。更多细节和支持,请阅读瑞安·塞登斯的“前瞻性思维形式验证”文章。
CSS3 引入了一个新的:target
伪类。:target
被设计为当所选元素成为链接的活动目标(URL 中指向它的片段标识符)时工作。虽然你以前可能没有遇到过术语片段标识符,但是你会用到它们。片段标识符是页面中特定元素(例如,#flight
)上的命名锚或 id。当您点击以片段标识符结尾的链接时,该链接所引用的元素就变成了:target
。
我们可以像设计:hover
或:focus
一样设计:target
的样式。用例范围很广,从简单的 FAQ 列表到目录页面、页面内导航和脚注。
这里有一个例子,它突出显示了你从页面内导航链接到的页面部分。这是页面的基本标记:
`
...
3
4
注意每个section
和div
是如何被赋予自己的 ID 的。然后我们在nav
中为这些 id 添加了相应的锚。这为我们提供了使用:target
所需的片段标识符(id)。
我们将添加一个规则,以便在从导航中单击相应的部分时高亮显示该部分。将:target
伪类添加到 ID 为(片段标识符)的元素中,而不是将添加到锚中。因为我们有两种带有片段标识符的元素,所以我们将通过对选择器进行分组,将规则添加到section
和div
元素中。
section:target, div:target { background: #F9FDA2; }
图 8-8 显示了点击锚点后高亮显示的部分。为了更进一步,你可以使用 CSS 动画制作背景颜色的变化,这在第十二章中有介绍。
**图 8-8。**通过使用:target
伪类实现高亮显示的部分。
当然,对所有类型的元素应用:target
可能会变得相当混乱,但是我们可以通过使用通用选择器(*
来解决这个问题,如下面的代码所示。然而,使用*
选择器会对站点性能产生负面影响,所以要小心使用。
*:target { background: #F9FDA2; }
可爱!一个简单的规则,你可以添加到你的 CSS 中,帮助用户在通过页面内链接导航时容易地看到他们在文档中的位置。
作为一个额外的例子,我们现在将创建一个基本的 CSS 标签式界面,类似于您习惯用 JavaScript 使用:target
创建的界面。以下是选项卡式面板和相关导航的简化标记:
`
Lorem ipsum dolor set amet.
Lorem ipsum dolor set amet.
Lorem ipsum dolor set amet.
Lorem ipsum dolor set amet.
我们将选项卡区域包装在一个<article>
中,然后包含了导航链接。接下来是一个<div>
(用于造型)和几个<section>
,每个都有一个唯一的 ID,每个锚点都将链接到这个 ID。请注意,我们没有使用<nav>
标签,也没有将导航项目放在列表中,原因稍后会解释。
我们现在将对article
、div
和section
应用一些基本样式,以绝对定位它们,并作为选项卡式内容区域。
`article, div {
position:relative;
}
section {
display:block;
position:absolute;
top:10px;
left:0;
background:#333;
color:#fff;
width:100%;
min-height:400px;
}`
下一步是激活:target
伪类。我们希望将它应用到每个section
,我们将更改z-index
属性,使该部分显示在其他部分之上。记住,我们将 :target
应用于带有片段标识符的元素,而不是锚。由于示例的简单性,我们可以创建一个针对文档中所有部分的规则。
section:target { z-index:2; }
为了确保第一个选项卡在初始页面加载时是可见的,我们将使用:first-of-type
选择器(本章后面会详细介绍)来改变它的z-index
。
section:target, section:first-of-type { z-index:2; }
这给了我们一个基本的 CSS 标签切换器。下一步是让活动选项卡以某种方式突出显示。要做到这一点,我们需要能够定位标记中位于section
之上的锚。在我们的例子中,section
是周围div
的孩子,而后者又是锚的兄弟。这给你提出了一个问题;仅使用 CSS,您无法定位父元素(毕竟,CSS 本质上是“层叠的”),这是高亮显示活动选项卡所需的和。为了解决这个问题,我们需要为每个锚点添加一个 ID,如下所示:
<a href="#one" id="one">One</a> | <a href="#two" id="two">Two</a> | <a href="#three" id="three">Three</a> | <a href="#four" id="four">Four</a>
然后,我们将:target
应用于我们的锚来设置活动状态。
a:target { background:#f5f5f5; font-weight:bold; }
这解决了活动标签的问题,但破坏了不再切换的标签面板。为了解决这个问题,使用子和相邻兄弟组合符(本章前面介绍过)来定位每个section
。
#one:target ~ div > section#s-one, #two:target ~ div > section#s-two, #three:target ~ div > section#s-three, #four:target ~ div > section#s-four, section:first-of-type { z-index:2; }
该规则被设置为针对每个section
元素,该元素是与标记中的锚相邻(~
操作符)的div
的子元素(使用>
操作符)。还包括默认的section:first-of-type
规则,以确保第一部分在页面加载时高亮显示。因为,如前所述,您不能使用 CSS 选择父元素,这就是为什么不在ul
或nav
元素中放置锚点的原因。如果我们以那种方式编写标记,这将意味着前面的规则无法实现。现在我们有了:一个使用 CSS3 的:target
伪类构建的简单选项卡式界面(见图 8-9 )。
**图 8-9。**使用 CSS3 的:target
伪类构建的选项卡式界面
虽然这种技术并不完全可靠,但是还有其他创建 CSS 标签的技术可以进一步研究,如 Corey Mwamba 在 Dev 上所描述的。Opera ( [
j.mp/operatargettabs](http://j.mp/operatargettabs)<sup>5</sup>
)和 Chris Coyier 上 CSS-Tricks ( [
j.mp/targettabs](http://j.mp/targettabs)<sup>6</sup>
)。
如果你更喜欢冒险,你可以通过使用:target
来创建图片库([
j.mp/targetgallery](http://j.mp/targetgallery)<sup>7</sup>
)、幻灯片和手风琴([
j.mp/targetaccordion](http://j.mp/targetaccordion)<sup>8</sup>
)来减少页面中对 JavaScript 的需求。为了进一步拓展边界,你可以将:target
与 CSS 过渡或转换结合起来,你将在第十二章中了解到,添加那些微妙的点缀来改善用户体验。
我们已经看到了几个伪类::target
和 UI 元素状态伪类。现在该看看超级强大的结构伪类了。这些选择器允许我们对 DOM 中的元素或元素的一部分进行样式化,但是如果不添加 id 或类,就不能通过使用其他选择器来定位。它们开始被用来最大限度地减少在标记中添加额外的类,无论是源代码中的类,还是使用 jQuery 等 JavaScript 库动态添加的类。
5
6
7 [
rem.im/css-gallery/](http://rem.im/css-gallery/)
8
除了一个结构伪类,其他的都在 CSS3 中引入了,但是因为我们对你很好,我们甚至会给你一点奖励,解释一下:first-child
,它是在 CSS 2.1 中引入的。另外,这似乎是我们开始研究结构化伪类的一个好地方。
如果你曾经在列表的第一项或文章的第一段添加过一个first
类,请举手。有罪?请放心,我们也举手了。别担心,我们不会告诉任何人,但我们会告诉你如何避免。顾名思义,:first-child
允许您定位文档树中给定元素的第一个子元素。
以本章前面的示例页面为例,假设我们想要增加引言中第一段的字体大小和粗细。我们可以通过在 ID 为“introduction”的div
中的段落上使用:first-child
伪类来做到这一点
div#introduction p:first-child { font-size:18px; font-weight:bold; }
图 8-10 显示了这一点。
**图 8-10。**第一段使用:first-child
伪类增加字号
如你所见,这是一个简单而有效的方法,可以帮助你避免患上严重的 classitis。
注:Internet Explorer 7 中有一个非常奇怪的 bug,带有:first-child,由罗伯特·尼曼(Robert Nyman)发现。如果你在第一个元素(你试图定位的元素)前放置一个注释,IE 7 会把这个注释当作第一个子元素,因此不会把这个规则应用到你试图定位的元素上。解决方案?如果可以的话,移动你的评论。罗伯特在他的博客上写下了这些。
猜猜这个选择器会帮助你瞄准什么,没有奖励。它也是 CSS3 伪选择器中的第一个。图 8-11 显示了一个导航菜单的例子,其中每个项目都有一个右边框。
**图 8-11。**导航菜单,每个项目都有一个右边框
我们可以使用:last-child
从最后一个列表项中移除边框,就像这样:
nav li:last-child { border-right:0; }
您可以在图 8-12 中看到,边框已经从最后一个列表项中移除。非常简单,你不觉得吗?
**图 8-12。**导航菜单使用:last-child
从最后一个菜单项中移除右边框
伪类是事情开始变得有点棘手的地方,因为我们需要开始使用数学。我们确信你们都对这一前景感到兴奋,但是相信我们,这并没有那么难。
9
:nth-child
允许您定位给定父元素的一个或多个特定子元素。它可以采用数字(整数)、关键字(odd
或even
)或计算(表达式)的形式。当你想设计如图 8-13 中所示的数据表时,这真的很方便。
**图 8-13。**样式简单的 HTML 数据表
我们将从使用关键字值even
开始,并添加一种背景色,在交替的表格行上创建斑马条纹效果,以提高可读性。
tr:nth-child(even) td { background-color:#eee; }
图 8-14 展示了我们配有斑马条纹的桌子。
图 8-14。 HTML 数据表用斑马条纹表用:nth-child
现在,俗话说,“剥猫皮的方法不止一种。”对于前面的例子,我们可以使用表达式2n
或2n+0
达到相同的效果,这意味着“每隔一行设置样式”
tr:nth-child(2n) td { background-color:#eee; }
如果我们想要反转行并对奇数行应用背景色,我们可以使用关键字odd
或表达式2n+1
,这意味着“从第一行开始每隔一行”以下示例具有完全相同的效果:
`tr:nth-child(odd) td {
background-color:#eee;
}
tr:nth-child(2n+1) td {
background-color:#eee;
}`
到目前为止一切顺利吗?很好,因为我们会稍微增加复杂性。使用类似于我们以前见过的那些表达式,让我们假设我们想要将表的每第四行作为目标。我们可以简单地使用
tr:nth-child(4n) td { background-color:#eee; }
从第二排开始每隔四个项目怎么样?
tr:nth-child(4n+2) td { background-color:#eee; }
你可以看到这里出现了一种模式。现在让我们来对付班上那个想倒数的聪明孩子。假设您想要样式化表格中的前五行。您可以通过对n
使用负值来做到这一点。
tr:nth-child(-n+5) td { background-color:#eee; }
在我们追求最少标记的终极样式的过程中,另一个可用的选择是:nth-last-child
伪类,它本质上与:nth-child
相同,但从的最后一个元素开始计数。使用与上一个示例相同的表达式突出显示表中的最后五行(注意与上一个示例中的前五行的不同之处)。
tr:nth-last-child(-n+5) td { background-color:#eee; }
同样,就像:nth-child
,:nth-last-child
接受odd
和even
参数,而不必为n
使用负值。
在我们继续之前,还有一个“子”伪类要看,那就是:only-child
。它像您所期望的那样工作,将任何元素作为其父元素的唯一子元素。如果您有一个只包含一个项目的动态生成的列表,这可能会很方便,在这种情况下,您可能希望减少边距。
ul li:only-child { margin-bottom:2em; }
“类型”伪类的工作方式与“子”选择器相同,关键区别在于“类型”伪类只针对那些与选择器所应用的元素相同的元素。当您不能保证不会有任何不同的子元素时,它们是最有用的。例如,如果在每个段落之间放置了一个hr
,通过使用:first-of-type
,我们可以确保我们只针对段落。
以我们之前的:first-child
为例,我们可以使用<div id="introduction">
作为一个样式挂钩。使用:first-of-type
,我们可以写
div#introduction p:first-of-type { font-size:18px; font-weight:bold; }
为了增加乐趣,我们可以将 CSS1(是的,1)中的:first-of-type
和::first-letter
伪元素结合起来,以样式化引言中第一段的第一个字母(如图图 8-15 )。CSS3 为伪元素引入了新的双冒号(::
)语法,以区分伪元素和伪类,如:hover
。下面是一个示例中的双冒号语法:
div#introduction p:first-of-type::first-letter { font-size:60px; float:left; width:auto; height:50px; line-height:1; margin-right:5px; }
**图 8-15。**使用 CSS 伪选择器样式的第一段的第一个字母
和:first-of-type
一样,使用:last-of-type
可以达到和:last-child
一样的效果。要从最后一个菜单项中移除右边框,可以使用
nav li:last-of-type { border-right:0; }
:nth-of-type
的工作方式与:nth-child
相同,使用相同的语法。然而,如果你的目标之间存在某种因素,它会比:nth-child
更有用。让我们来看看下面的例子,一个section
带有一个标题,后面是太空图片中的动物列表:
`
现在,删除列表创建的项目符号,浮动每个li
并添加一些边距。
`#animals ul {
list-style-type:none;
}
#animals li {
float:left;
width:200px;
text-align:center;
margin-right:2em;
margin-bottom:2em;
}`
图 8-16 显示了到目前为止你所拥有的;您可以看到边距导致第三个列表项被放到新的一行上。问题是你的设计要求每行应该有三张图片。
**图 8-16。**太空动物列表
现在使用:nth-of-type
瞄准每三个列表项(3n
),并移除右边距以确保它们不会掉到新的一行。
#animals li:nth-of-type(3n) { margin-right:0; }
结果如图 8-17 所示。
**图 8-17。**太空中的动物列表,每行三个项目
与:nth-child
一样,您也可以使用表达式(2n+1
)或关键字(odd
或even
)来定位特定的元素。
您还可以使用表达式li:nth-of-type(1) {...}
使用:nth-of-type
来定位组中的第一个项目,这与使用:first-of-type
具有相同的效果。
使用:nth-last-of-type(1) {...}
和使用:last-of-type
是一样的,但是结合表达式,允许你从最后一项开始倒计数,就像:nth-last-child
一样。使用nth-of-type
的例子,通过增加一个大的左边距将最后一只孤独的动物移到中间(见图 8-18 )。
#animals li:nth-last-of-type(1) { margin-left:232px; }
图 8-18。最后一项居中的太空动物列表
:only-of-type
目标元素的父元素没有其他相同类型的子元素。假设你有一篇文章,可能包含几幅图片;但是,如果只有一个图像,您希望对它进行不同的处理,比如让它全幅显示。这就是:only-of-type
发挥作用的地方。
article img:only-of-type { width:100%; }
:empty
可以是极其有用的伪类。它表示一个没有内容的元素。假设我们的页面中有一个动态生成的aside
,它没有任何内容;我们可以用:empty
隐藏它。
aside:empty { display:none; }
在你高兴地跳起来之前,有一个警告:如果浏览器发现一个字符,甚至是空白,这个元素将被呈现,因为它不再正确地匹配:empty
选择器。垃圾。向标记中添加 HTML 注释是安全的,但是要确保没有空格。
我们不能忽略的一个结构伪类是:root
类。HTML 中文档的根通常是html
元素,这正是:root
的目标。如果您想出了这个选择器的一个用例(我们确信一定有人想到了),请务必让我们知道。为了完整起见,它是这样工作的:
:root { background-color:red; }
我们在本章前面简要讨论了::first-letter
伪元素,以及 CSS3 如何为伪元素引入新的双冒号(::
)语法,以区分伪元素和伪类。这个新语法适用于 CSS1 和 CSS2 中的下列伪元素:
::first-letter
::first-line
::before
::after
虽然这些伪元素可以在以前的 CSS 版本中找到,但直到最近它们才获得广泛的浏览器支持。因此,我们将简要地看一下如何使用::before
和::after
伪元素。
::before
和::after
伪元素用于在一个元素的内容(或另一个伪元素)之前或之后生成内容。“在元素的内容之后”这个短语在这里很重要。这意味着您不能在具有空内容模型的元素上使用::before
和::after
,比如<img>
或<input>
。这是不幸的,因为::before
和::after
有几种可能的用例,比如用input type="range"
来显示最小值和最大值。为此,需要更改规范。Opera 目前允许这样做,但是这样做违背了规范。
虽然生成不存在于您的标记中的内容可能会令人不快,但正如我们将看到的,有许多合法的用例。这些伪元素的生成内容由content
属性提供,该属性可以采用以下一个或多个值:
首先,我们来看看添加一个字符串。要在每个<figcaption>
元素前插入单词“Figure ”,我们应该写
figcaption::before { content:"Figure:"; }
该字符串必须用引号括起来。还可以包含 unicode 字符,需要用反斜杠(\
)进行转义。考虑下面的例子,在这个例子中,我们想要在页面顶部的链接末尾添加一个向上箭头符号(Unicode 2191)。HTML 代码片段如下:
<p><a href="#top">Back to top</a></p>
接下来是使用::after
伪元素添加箭头的 CSS 规则(见图 8-19 )。它使用一个属性选择器来只定位带有#top href
的锚点。
a[href="#top"]::after { content:" \2191"; }
**图 8-19。**一个锚点使用生成的内容在元素的内容后添加一个箭头符号
现在让我们看看如何使用content
属性追加属性值。这个例子显示了当一个锚点有焦点(或悬停)时的链接的 URL。我们只希望外部链接出现这种情况,所以我们将使用本章前面描述的“starts with”(^
)子串选择器。
a[href^="http://"]:hover::after, a[href^="http://"]:focus::after { content:attr(href); position:absolute; width:auto; bottom:-22px;
left:0; padding:0 5px; color:#fff; }
您使用了带有带有href
参数的attr
值的content
属性。然后,您将内容放置在链接下面。
最后,为了展示如何组合几个值,我们添加了一个字符串(“外部链接”),后跟href
属性。
a[href^="http://"]:hover::after, a[href^="http://"]:focus::after { content:"External Link " attr(href); position:absolute; width:auto; bottom:-22px; left:0; padding:0 5px; color:#fff; }
伪元素的潜力非常广泛,从页面卷曲到章节的自动编号。您甚至可以在打印样式表中包含 URL。现在浏览器对伪元素的支持正在改善(尽管它从 CSS 2.1 就已经存在),这也有助于删除不必要的用于样式目的的div
。
如果您希望进一步研究,看看如何实现计数器、引号等等,我们建议您阅读 CSS 2.1 ( [
j.mp/css2gencontent](http://j.mp/css2gencontent)<sup>10</sup>
)和 CSS3 规范([
j.mp/css3content](http://j.mp/css3content)<sup>11</sup>
)的相应部分。
关于利用你将在第十一章中遇到的一些属性的许多其他用途,看看尼古拉斯·加拉格尔的个人网站([
j.mp/necolas](http://j.mp/necolas)<sup>12</sup>
),在那里他详细介绍了几个使用伪元素的实验。最后,乔恩·希克斯写了一篇 24ways 的详细文章,讲述如何结合 HTML5 data-* attributes、@font-face(见第十章),生成内容显示图标而不使用图像([
j.mp/hicksfonts](http://j.mp/hicksfonts)<sup>13</sup>
)。这确实是一项非常创新和聪明的技术。
我们要看的最后一个选择器是否定伪类,:not()
。在许多方面,它的工作原理与其他选择器相反,因为它允许你定位那些与选择器的参数不匹配的元素。我们知道这很奇怪,但它仍然非常实用——而且你会发现自己会越来越多地使用它。
10
11
12
13
一个主要的例子是样式化所有表单输入,这些表单输入不是提交按钮。
input:not([type="submit"]) { width:250px; border:1px solid #333; }
这使您不必仅仅为了设计样式而向 Submit 按钮添加额外的类。或者从另一个角度来看,它让你不必每隔一个input
添加一个类。这些标记看起来已经精简了,对吗?
您还可以在测试期间使用 negation 伪类来捕捉那些验证不会捕捉到的东西。例如,如果您想查看所有没有指定title
属性的缩写,只需使用
abbr:not([title]) { outline:2px dotted red; }
图 8-20 显示了通过使用:not()
伪类显示出来的虚线轮廓。
**图 8-20。**没有title
属性的abbr
使用否定伪类进行样式化。
您可以使用相同的技术来突出显示没有指定alt
属性的图像。
img:not([alt]) { outline:2px dotted red; }
这是 Eric Meyer 在他的诊断样式表中使用的一种技术。您可以在测试时添加诊断 CSS 来捕捉所有这些错误并修复它们。当您准备好部署到站点时,只需删除该文件。
IE9+、Firefox 3.5+、Chrome 4+、Safari 4+和 Opera 10+完全支持 CSS3 选择器(尽管有三个小的例外)。
14
IE6、IE7 和 IE8 中的支持实际上是不存在的(IE7 和 IE8 支持一般的兄弟组合、:first-child
和所有的属性选择器),但是您可以通过用本地 JavaScript 或 jQuery 库进行多填充来解决这个问题。
Internet Explorer 的另一个警告是,如果你正在分组选择器,IE 遇到一个它不理解的选择器,它将忽略整个规则。例如,如果你有
ul li:nth-child(3n), ul li.last { margin-right: 0; }
IE 不会识别规则,所以你需要把它们拆分成自己的规则,就像这样:
`ul li:nth-child(3n) {
margin-right: 0;
}
ul li.last {
margin-right: 0;
}`
上一章介绍的 selective Zr([
j.mp/selectivzr](http://j.mp/selectivzr)<sup>15</sup>
)是一个有用的 polyfill。该库模拟了 5.5 到 8 版本中的伪类选择器。不幸的是,目前,当与某些 JavaScript 库一起使用时,它并不能模拟本章所涉及的所有属性选择器或组合子。
或者,您可以决定,如果这些小图标只是作为增强功能添加的,对网站的功能并不重要,那么它们不显示在功能较弱的浏览器中也没关系。选择权在你。
尽管这本书关注的是 CSS3,我们还是想让你知道一个小秘密。CSS4 就在眼前。嗯,就选择者而言。选择器 4 级模块目前处于“工作草案”阶段,并定期更新。尽管还处于早期阶段(预计会有重大的修改),一些选择器已经从选择器规范中移除,一些已经被添加。那些被排除在外的包括伪元素,将被重新安置在其他地方。相比之下,当前基本用户界面规范中的 UI 状态伪类已经被合并到选择器第 4 级模块中。目前还有许多其他的变化正在进行中,比如扩大了 negation ( :not
)伪类的范围。
就新的选择器而言,目前有许多选择器,包括匹配相似选择器字符串的选择器(:matches
)、语言伪类(:dir
)、时间维伪类(:current
、:past
和:future
)、网格结构选择器(:column
、:nth-column
、:nth-last-column
),以及令人兴奋的父选择器(语法待定)。当然,要了解比我们在这里提供的更多的细节,你可以阅读规范([
j.mp/css4selectors](http://j.mp/css4selectors)<sup>16</sup>
)。或者,http://j.mp/storeycss4 在他的博客上写了一篇精彩的总结,但请记住,当你读到这篇文章时,它可能已经过时了。
15
在这一章中,你学习了通过使用强大的 CSS3 选择器,我们不需要添加不必要的类和 id 到我们的标记中,确保我们能够真正地将我们的内容和表现彼此分开。您看到了如何定位一个组中的第一个、最后一个、奇数个或偶数个项目。我们还展示了如何单独使用表达式和元素来定位元素组。
您看到了如何使用负伪类来帮助您的测试和诊断。我们引入了在适当的地方添加生成内容的想法。我们还向您展示了如何通过使用:target
和 UI 元素状态伪类给出更好的反馈来改善用户体验。最后,我们通过简单地看一下 CSS4 选择器和(如 Storey 先生所描述的)magic unicorn 父选择器,让您对未来有所了解。
现在,您已经掌握了定位页面中各种元素的方法,下一章将向您展示如何使用新发现的选择器功能来创建漂亮的基于 CSS 的布局,这些布局可以无缝地跨设备工作。
16
17 [
generatedcontent.org/post/10865123182/selectors4](http://generatedcontent.org/post/10865123182/selectors4)
对于您的家庭作业,首先创建您自己的诊断样式表,然后对您的站点进行测试,以挑选任何空属性或缺失值。
继续查看您正在开发的站点,并决定在哪里可以利用这些新的强大的选择器,以使您不必在标记中添加类或 id。你应该能够包含一些我们在本章中使用过的选择器。接下来通过使用::before
和::after
伪元素集成一些生成的内容。
最后,仅使用:target
选择器构建一个仅支持 CSS 的图库。
表 8-1 是 CSS 选择器的表格,它们的含义,它们被描述的规范部分,以及它们被添加到哪个版本的 CSS 中。这个表是基于 W3C 在[www.w3.org/TR/css3-selectors/#selectors](http://www.w3.org/TR/css3-selectors/#selectors)
的表。
在这一章中,你将学习如何使用 CSS 来定位元素,并创建 CSS 布局。这是 CSS 在历史上的弱点——基于 CSS 2.1 的布局技术使用了最初不用于页面布局的属性,并且不适合今天的 web 应用。我们将从重温基础知识开始:CSS 盒子模型、浮动、定位和朋友,以及如何使用它们来创建灵活和固定的布局。然后,我们将看看@media
媒体查询的隐藏力量,看看如何在响应式 Web 设计的旗帜下,根据设备的功能来调整 CSS,为设备提供定制的体验。然后,我们将以一瞥 CSS3 布局规范的未来来结束。但是首先让我们回顾一下过去,看看影响 CSS 布局的一些趋势,并为为什么媒体查询最近变得如此重要做好准备。
1989 年 3 月,蒂姆·伯纳斯·李在写万维网的最初提案时,提到“异构性”是需求之一。
需要从不同类型的系统中访问相同的数据
-信息管理:蒂姆·伯纳斯·李爵士的提议
[
j.mp/html-proposal](http://j.mp/html-proposal)<sup>1</sup>
这是指蒂姆·伯纳斯·李在欧洲粒子物理研究所工作的系统,所列举的系统(VM/CMS、Macintosh、VAX/VMS、UNIX)可能并不都是大家熟悉的。然而,这种精神已经成为网络的基础,并作为通用访问的核心原则的一部分存在于 HTML 的设计原则中。
在可能的情况下,功能应该能够跨不同的平台、设备和媒体工作。
-HTML 设计原则,W3C
[
j.mp/html-principles-5-1](http://j.mp/html-principles-5-1)<sup>2</sup>
我们所听到的对这一观点的最佳总结来自热情如火的 Molly Holschlag,她在 2009 年西南偏南(SxSW)的 Web 标准项目(WaSP)年会上宣称:
任何人,任何地方,任何用户代理,一张网。
——Molly Holschlag,在 WaSP 年会上的发言,SxSW 2009[播客;1:03:30]
(
[
j.mp/wasp-2009audio.sxsw.com/2009/podcasts/D4%20SXSW_PODCASTS/031609_PM2_HILB_WASP_Annual_Meeting.mp3](http://j.mp/wasp-2009audio.sxsw.com/2009/podcasts/D4%20SXSW_PODCASTS/031609_PM2_HILB_WASP_Annual_Meeting.mp3)
)
那么为什么这个原则如此重要呢?这是因为现在,比以往任何时候,我们使用和构建的网络是由许多设备组成的网络。这一趋势还在加速,我们应该采用新的技术来迎接挑战。
追溯到 20 世纪 90 年代,任何浏览互联网的人都可能使用 800x600 像素的屏幕。随着平均显示器尺寸的增加,web 设计者在 2000 年开始瞄准 800x600 px 显示器,然后在 2007 年左右瞄准 1024x768 px 显示器(具有许多固定宽度 CSS 框架今天使用的 960 px 宽度)。(【http://j.mp/960px-width】)3
然而,2006 年关于是否是时候从 800x600 像素转移的争论与最近的发展相比显得苍白无力。虽然移动浏览早在 1998 年就出现了,但直到最近几年,手机才真正开始浏览“一个网络”,而不是早期 WAP 和 cHTML 尝试的病态替代品。当前所谓的智能手机和平板电脑的爆炸式增长给大众带来了真正的移动浏览。虽然许多智能手机都集中在 320x480 px 的屏幕尺寸上,但在尺寸和像素密度方面有很多变化。在撰写本文时,国际上最常见的移动屏幕尺寸是 240x320 px,通常为 152 ppi(每英寸像素),但屏幕尺寸和分辨率有很大的差异(并且越来越大)。
在光谱的另一端,非常大的屏幕最近变得负担得起,并且高分辨率显示器也正在出现。除了手机、平板电脑和电脑,我们现在还有电视、游戏机,甚至是显示网页的汽车和冰箱,所有这些设备的显示屏尺寸、浏览器功能和带宽都千差万别。
很明显,我们行业以前的固定宽度布局标准无法应对挑战。面对这一大堆设备和功能,斯科特·简森称之为“电子产品的僵尸启示录”(j.mp/zombie-devices
design mind . frog design . com/blog/the-coming-zombie-启示录-small-cheap-devices-will-disrupt-our-old-school-UX-assumptions . htm),我们该怎么办?
一种方法是创建针对各类设备优化的网站。目前,这通常意味着桌面电脑的标准网站和智能手机的优化网站。平板电脑的到来可能会给这个列表增加另一类设备。通过这样做,您可以根据每个平台的优势设计定制的体验,并确保设计运行良好。
在某些方面,这是一个很好的解决方案。与在家或工作时相比,人们在旅途中访问网站时通常有非常不同的内容需求。此外,通常还有不同的功能,例如小得多的屏幕的限制或在移动设备上访问地理位置数据的能力。(【http://j.mp/mobile-web-friendly】)4
1
2
但是,很快连三个版本都可能不够。这也意味着复杂性的大幅增加,因为现在您需要测试和维护多个站点。虽然在理想的情况下,你有足够的资源来处理好每一个网站,除非你非常专注(并且有足够的资金),这通常会导致一个维护良好的网站,而其他版本会被忽视。
多年来,人们试图以各种方式解决不同设备能力的问题。在过去,这通常意味着浏览器嗅探,根据用户代理字符串检测浏览器,然后从服务器发送定制内容,或者定制网站在客户端的显示。如果执行得不好,这种方法是非常脆弱的,当新的浏览器发布时经常会崩溃。更现代和更负责任的对等物是功能嗅探,使用 Modernizr 和 YepNope 等工具检测设备的功能并根据功能定制内容。这是渐进增强的扩展,为支持它的用户代理增加了额外的功能。Internet Explorer 的条件注释也起到了一定的作用,例如一直流行的 IE6 通用样式表(j.mp/universal-ie6-css
通用 Internet Explorer 6 样式表by Andy Clarke stuffandnonsense.co.uk/blog/about/universal_internet_explorer_6_css
)。
理想的方法是创建一个网站,这个网站能够适应用来浏览它的设备。虽然这听起来像是需要魔法的事情,但实际上我们需要做的只是接受媒体的固有特性,因为适应性是网络默认的功能。约翰·奥尔索普在十多年前写了一篇关于这个问题的文章,这篇文章可能是我们这个行业的开创性文章,“网页设计之道”
灵活是网络的本质,作为设计者和开发者,我们的职责应该是拥抱这种灵活性,并制作出所有人都可以通过灵活访问的页面。
约翰·奥尔索普于 2000 年出版的《网页设计之道》
(
[
j.mp/dao-web](http://j.mp/dao-web)
5 )
3 Cameron Moll 在“1024 像素分辨率的最佳宽度?”中介绍了 960 像素网格的开发(www.cameronmoll.com/archives/001220.html)
4 Bruce Lawson 在 Opera 的“移动网络优化指南”中介绍了如何变得对移动设备友好(dev.opera.com/articles/view/the-mobile-web-optimization-guide
)
虽然默认情况下 Web 可能是灵活的,但默认样式的页面也不那么引人注目。这并不是完美的解决方案,但是容纳众多设备的网络的最简单的方法就是好好编码,使用灵活的布局。然而,在讨论灵活布局之前,让我们快速回顾一下内容在浏览器中显示的基础知识。
元素在 CSS 中的可视化布局可能很复杂,但本质上是相当简单的。显示的每个元素都由一个或多个框组成。这些盒子可以有不同的属性,可以以不同的方式相互作用,但基本的事实是一切都是一个盒子。当然,CSS 也有一个模型——盒子模型。
想到盒子,你可能会想到包装精美的礼物(也许是蛋糕!).礼物在一个盒子里,可能被一些保护空间或衬垫包围着。除非它接触到其他盒子,否则盒子周围可能还有一些空白。CSS 盒模型盒是类似的,基于元素的内容,加上它的padding
、border
和margin
属性。你已经熟悉了这本书前半部分的内容,所以让我们回顾一下padding
、border
和margin
,因为这三个属性影响一个元素在页面中可以占据多少空间。
padding
向元素内容的一侧或多侧添加空格。它是透明的,所以它揭示了元素的背景颜色和/或背景图像。border
控制元素每一侧的边框外观,包围内容和padding
。这通常是一条由border
属性定义宽度、样式和颜色的彩色或半透明线条,但它可以有圆角,甚至可能使用边框图像(见第十一章)。边框被添加到元素的padding
和margin
之间,默认情况下,它覆盖元素的背景。margin
也影响一个元素的一个或多个边上的空间,并且是透明的,但是与padding
不同,它也可以接受负值和值auto
。这些选项允许您将元素从其初始位置移开,或者更改它与周围元素的交互方式。它也可以作为 CSS 布局的一部分,你会在本章后面的“用负边距改变列顺序”一节中看到。正如你在第七章的“CSS 速记”一节中所记得的,这三个速记属性也有不同的种类(比如margin-top
),在border
的情况下,还有一系列单独的属性(比如border-bottom-color
)。
这里我们还应该提到outline
,它类似于border
,但是并没有改变盒子所占的空间。它被添加到元素的border
之外,与任何margin
重叠,并堆叠在元素内容之上。与border
不同,单个outline
样式应用于元素盒子的所有侧面。您将主要在浏览器默认样式表(浏览器默认应用于每个页面的 CSS 规则)中看到outline
,用于在链接和表单字段上指示:focus
以实现可访问性。一般来说,你会希望不使用outline
,而是使用更灵活的border
。
这些属性占用的空间量以长度单位定义。这些是:
%:
包含块宽度的百分比,作为一个数字后跟%
,如33.3%
字体-相对长度单位,如:
em:
字体的高度(嗯,元素的font-size
的计算值)。ex:
字体的 x 高度,一般是字符“x”的高度(约 0.5em)ch
:字符单位,定义为字符“0”的前进宽度(一个排印术语)。这对于指定与等宽字体(包括中文、日文和韩文字体)中的字符数相等的值非常有用。(【http://j.mp/defining-ch】6)rem
:根单元的字号,<html>
。这避免了与em
的继承问题。视口-相对长度单位如:
vw
:视口宽度的百分比。视区是页面的可见部分,由浏览器窗口限定。这与正常的百分比不同,因为它是初始包含块的百分比,可以比元素的当前包含块更宽。vh
:视口高度的百分比。vm
:vw
和vh.
的较小值绝对长度单位,如
px
: CSS 像素;出于分辨率的目的,1px 等于 1in 的 1/96,给出 96dpi 的固定 CSS 分辨率。cm
:厘米mm
:毫米in
:英寸pt
:分;1 磅等于 1 英寸的 1/72。pc
:Picas;1pc 等于 12pt。6
(注意长度为0
时,单位为相对和绝对单位可选。)
由于浏览器支持,我们目前仅限于屏幕 CSS 的%
、em
和px
,尽管在现代浏览器中对rem
有广泛的浏览器支持,但现在可以使用em
或px
单元回退(更多细节请参见第十章)。绝对单位(除了px
)应该只在打印样式表中使用。
CSS 中的像素也值得进一步解释。这些像素可能与显示像素不同,并被定义为视角,因此无论距离远近,它们的大小都大致相同。移动电话和投影仪上的 CSS 像素的相对大小对观众来说应该是相同的,尽管绝对大小是非常不同的。这也意味着高分辨率显示器可能会使用多个设备像素来显示一个 CSS 像素,而双分辨率显示器的每个 CSS 像素会使用四个设备像素。
非零宽度填充、边框、边距和/或轮廓的显示顺序是从元素的边距和背景色开始,然后是背景图像、填充、边框、实际内容,最后是顶部的轮廓。这在图 9-1 块级盒子的 CSS 盒子模型的分解 3D 图中进行了说明。
**图 9-1。**一个 CSS 盒子(包括轮廓),有一个分解图显示块级盒子的各个部分是如何堆叠的
这个图展示了盒子模型如何为块级盒子工作,一个使用样式display: block;
的盒子。属性有一系列不同的值,但是两个基本的值是block
和inline
。通常,块级框包含内容块,如包含文本的<p>
元素,而内联框被添加到内容中,如围绕一些文本的<strong>
元素。它们在 CSS Box 模型中的工作方式也有所不同,所以让我们从display: block;
开始,一次看一个。但首先,简短地跑题一下国际化和定位词。
HTML 和 CSS 的奇妙之处之一是在国际化和可访问性方面做了大量的工作。“同一个网站”是国际化和多语言的,在本章中记住这一点很重要。
虽然英语和许多欧洲语言是从左到右、从上到下书写的,但其他语言不是这样,例如阿拉伯语和希伯来语(从右到左),以及传统风格的汉语和日语(从上到下、从右到左)。为了简单起见,我们将使用基于英语的示例,其中文本从左到右,内容从上到下阅读。如果你使用的是不同规范的语言,请记住这一点。
块级盒子是你的结构构建块。默认情况下,带有display: block;
的元素与它们包含的元素一样宽,并且在页面中垂直排列。块级框的默认高度是包含框中内容所需的高度。这些是元素的内在尺寸——在应用 CSS 之前的宽度和高度。虽然如果文本大小或包含元素的宽度改变,段落的高度也会改变,但默认情况下,替换的内容(如图像)将使用其固有的宽度和高度,即使它被视口裁剪。参见图 9-2 。
图 9-2 。块级段落和图像。请注意,当视窗较窄时,顶部段落的高度会调整以包含文本,但默认情况下,图像会被裁剪。
包含元素的概念将在本章后面的“块格式化上下文”部分详细介绍。
对于块级的盒子,你可以使用属性width
和height
来改变这些固有的尺寸。使用百分比值时,它们分别基于包含元素的宽度和高度。一般来说,隐藏内容是一个坏主意,所以我们建议不要在包含文本或任何使用字体相关单位大小的元素上设置height
——这是自找麻烦。如果浏览器的字体变大或者浏览器窗口变小,你很容易在元素上隐藏内容和滚动条。虽然您可以使用overflow
属性来控制这种行为,但是最好不要隐藏任何内容。(如果无法避免为文本块设置height
,使用ems
来适应文本大小调整,并彻底测试。)
还有max-width
和min-width
的相关属性,加上较少使用的max-height
和min-height
,它们对元素的维度设置了上限和下限。如果你没有指定一个固定的宽度,但又不想让你的行在一个很宽的浏览器窗口中变得过长,这是非常方便的。它们在 Internet Explorer 6 中不起作用,所以最好为该浏览器添加一个针对 IE 6 的固定width
。
默认情况下,CSS 盒子的width
和height
是其内容的大小——由content
和padding
之间的边缘定义。然而,盒子占据的空间是内容框加上任何填充、边框和边距。默认计算是
margin-left
+border-left-width
+padding-left
+width
+padding-right
+border-right-width
+margin-right
margin-top
+border-top-width
+padding-top
+height
+padding-bottom
+border-bottom-width
+margin-bottom
图 9-3 显示了一个示例 div,它有固定的宽度和高度,加上边距、边框和填充来演示这一点。
.box { width: 240px; height: 160px; margin: 24px 48px; /* = 24px 48px 24px 48px */ border: 1px solid #ddd; padding: 12px 18px 6px; /* = 12px 18px 6px 18px */
`}
It’s boxes all the way down…
图 9-3 。带有填充、边框和页边空白的框,以及 Safari 的 Web 检查器的“外观”标签中的相同元素
您最初可能希望 div 占用 240x160px,但默认情况下,它将占用以下空间:
当试图并排浮动两个 50%宽的元素时,通常会第一次遇到这种情况(我们稍后将讨论浮动)。如果您添加任何水平边距、边框或填充,两个框合起来会变得比 100%宽,第二个框会下降到下面。这也使得很难在margin
、border
、padding
和width
上使用不同的单位,因为em
的大小和百分比单位分别随着浏览器的字体大小和浏览器宽度而变化。
这可能与你的期望相矛盾,因为当你邮寄礼物时,你要为盒子的尺寸付款*,包括*包装,而不仅仅是里面的东西。雪上加霜的是,6 版之前的 Internet Explorer 曲解了 CSS Box 模型,将 border
和padding
包含为width
的一部分。如果你忘记用一个 doctype 开始你的 HTML,它仍然会这样做,这就是所谓的怪癖模式。不要忘记文档类型!
然而,一切旧的都是新的,使用box-sizing
属性你现在可以选择width
和height
是指默认的content-box
还是更直观的border-box
(在边距和边框之间,称为边框边缘),这对于布局来说更容易。使用border-box
意味着边框和填充值不会像使用content-box
那样增加元素的宽度和高度。
content-box
: width
=内容宽度border-box
: width
= border-left-width
+ padding-left
+内容的宽度+ padding-right
+ border-right-width
回到图 9-3 中的前一个例子,让我们看看border-box
是如何改变数学的。
margin-left
+width
+margin-right
= 48px+240 px+48px = 336 pxmargin-top
+height
+margin-bottom
= 24px+160 px+24px = 208 px图 9-4 清楚地显示了这种差异——content-box
内容宽度与border-box
边框边缘宽度相同。
图 9-4 。比较box-sizing
属性的content-box
和border-box
值
请注意,默认情况下,元素的背景对于边框边缘是可见的,并且左上角是背景图像开始的地方。如果你改变了box-sizing
,你可能会想要改变background-clip
和/或background-origin
,我们会在第十一章中介绍。默认情况下,当鼠标悬停在某个元素上时,浏览器的检查器工具中显示的尺寸是到边框边缘的尺寸,因此不包括margin
。您可以使用我们在图 9-3 中看到的检查员工具的方框模型图来检查页边距。(Opera 的开发者工具和 Firefox 的 Firebug 也包含其他方便的信息,包括元素的box-sizing
值。)
正如你在表 9-1 中看到的,浏览器对此的支持出奇的好,尽管 Firefox 13 及以下版本在结合min-/max-height
、min-/max-width
、SVG 和表格单元格时可能会有问题。
然而,如果您的受众包括 Internet Explorer 7 和更低版本,使用box-sizing
将需要为这些浏览器定制变通办法,以避免破坏您的布局。虽然 Modernizr 可以检测到这一点,并且有 polyfills,但除非你支持很多传统浏览器,否则只添加面向 IE 的样式可能是最简单的。
现在还有很多旧版的 ie 浏览器在用。原因包括 Windows XP(不运行 IE9,但仍被广泛使用),公司政策,以及 IE 是最后一个转向自动更新的主要浏览器(从 2012 年开始)。我们提倡在创建网站时偶尔测试不同版本的 IE,因为你通常可以通过良好的编码和渐进增强来避免问题。然而,虽然 IE10 最终加入了“现代浏览器”的行列,但有时你会在早期版本(在 IE6-7 中更常见)中遇到一个怪癖或错误,需要给它们一点小小的推动。
*历史上,这是通过使用 CSS 过滤器([
j.mp/css-filter](http://j.mp/css-filter)
7 )(如下划线和星号)或通过使用 IE 的条件注释([
j.mp/ies-cc](http://j.mp/ies-cc) 8 ). Instead, we recommend using Paul Irish’s conditional classes on
(
j.mp/html-cc
<sup>9</sup>
):*加载特定于 IE 的样式表来完成的
*<!--[if lt IE 7 ]> <html class="ie6"> <![endif]-->* *<!--[if IE 7 ]> <html class="ie7"> <![endif]-->* *<!--[if IE 8 ]> <html class="ie8"> <![endif]-->* *<!--[if IE 9 ]> <html class="ie9"> <![endif]-->* *<!--[if(gtIE9)|!(IE)]><!--> <html> <!--<![endif]-->*
然后,你可以通过在相关的类前加上前缀来定位任何特定于 IE 的样式,就像这样:
*img {max-width: 100%;}* *.ie6 img {width: 100%;}*
7 en.wikipedia.org/wiki/CSS_filter
8
9
块级框上的正边距值将增加框周围的空间。但是,负边距值的工作方式略有不同。对于块级元素,负的上边距将向上移动该元素(以及后面的元素),可能会覆盖前面的内容,负的下边距将向上拉后面的内容,可能会覆盖该元素,如图 9-5 所示。
图 9-5 。应用于块级框的负垂直边距:左边的示例用于参考(没有负边距),中间的示例有一个负的margin-top
向上移动元素(和后面的内容),右边的示例显示了一个负的margin-bottom
“向上拉”后面的内容。
根据width
是否为auto
,负左右边距的工作方式不同。对于具有相关宽度或高度auto
的块级元素,负的左边距或右边距将拉出框的边缘,加宽元素。对于具有设定宽度的块级元素(包括替换的内容,如图像),负的左边距将使元素向左移动,负的右边距将把内容拉到元素的右边,可能会与元素重叠(尽管只有当块旁边有内容时,例如当应用于两个浮点中的第一个时,您才会看到这一点)。这在图 9-6 中显示。
图 9-6 。负水平边距应用于左侧带有width: auto;
的块级框。中间的例子有一个固定的宽度和负的左边距和上边距。右边的例子在图像 1 上有一个负的margin-right
,它将内容“拉”到右边。
如果元素的宽度没有父元素宽,使用auto
作为左边距或右边距将会吸收所有未使用的空间。如图图 9-7 所示,默认情况下,一个图像会与其父元素的左边缘对齐,但是如果该元素有margin-left: auto;
和margin-right: 0;
,则该元素会接触到父元素的右侧。如果左边距和右边距都是auto
,元素将在父元素的宽度上居中,如最右边的示例所示。
图 9-7 。对于比其父元素窄的块级框,添加设置为auto
的水平边距将吸收任何额外的空间,允许您在它们的父元素内右对齐或居中元素。
具有块级盒子的盒子模型的另一个有趣的方面是如果两个垂直边距接触,只有最大的边距被使用。这听起来很奇怪,但实际上这是大多数时候你希望发生的事情。例如,在没有折叠页边距的情况下,CSS p {margin: 1.5em 0;}
意味着段落之间的页边距是第一个段落顶部和最后一个段落底部的的两倍,正如你在图 9-6 的左边看到的那样。我们可以对此进行编码,例如只设置margin-top
。然而,通过折叠垂直边距,我们不需要这样做——段落前和段落间的边距最终是相同的,如右图所示。
图 9-8 。两段,带p {margin: 1.5em 0;}
。左边的例子演示了累积垂直边距是如何工作的。右边的例子显示了折叠垂直边距如何阻止段落之间的空间变得更大。
这看起来是一个小问题,但是当几个嵌套元素都有接触的顶部或底部边界时,就变得很重要了,比如一个列表(见图 9-9 )。
`ul {margin: 1.5em 0 1.5em 1.5em;}
li {margin: 0.75em;}
…
…
图 9-9 。如果多页边空白相互接触,它们会折叠成最大的一页。如果没有边距折叠,元素的嵌套将导致这两段之间有 5.25em 的间距。随着边距的缩小,该值变为 1.5em,这是最大的单个值。
没有边框、填充、内容或空白来分隔它们的元素的顶部和底部边距也是接触的,并且也折叠在一起。这就是为什么添加空段落来增加垂直空间这种直观但糟糕的想法行不通。然而,一旦边距被填充、边框(即使是透明的)或内容分开,垂直边距折叠就会被阻止,如图图 9-10 所示。元素还必须是流入(非浮动等),并且在相同的块格式化上下文,这些概念我们将很快介绍。
`p {margin: 1.5em 0;}
…
…
` ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Fvkdoc-html-css-zh%2Fraw%2Fmaster%2Fdocs%2Fbegin-h5c3-web-evo%2Fimg%2F9781430228745_Fig09-10.jpg&pos_id=img-DeWFjWdI-1723652054541)图 9-10 。在第一个段落的下边距和最后一个段落的上边距之间,所有的垂直边距都相互接触,并且会被折叠成一个 1.5em 的边距。然而,在右边添加p {border-top: 1px solid #000;}
意味着这个边框现在防止了一些页边空白接触(和折叠),空段落变得可见。
现在我们已经讨论了块级盒子——带有display: block;
的元素——让我们来看看内联盒子,另一种常见的盒子类型。
内联框元素通常包含文本内容的单词或短语,HTML5 的内容元素默认为display: inline;
。与块级的盒子不同,它们和它们的内容一样长,而不是创建一个矩形,它们的盒子把每行的文本*(像荧光笔一样),如果需要的话可以换行,如图 9-11 中的所示。内嵌框不能包含块级框。*
*
图 9-11 。一个包含一个内嵌框的参数图,该框有一个环绕(拆分)两行的边框。
替换的内容包括链接和嵌入的元素,如图像和视频。未替换的内容是其他所有内容,即 HTML 文件中的内容。内联替换和非替换内容的行为略有不同,所以让我们一次看一个。
默认情况下,内嵌替换的内容(如内嵌图像)使用其固有尺寸。它也使用与块级内容相同的盒子模型,填充和边距影响元素的所有边,正如你在图 9-12 中看到的。
图 9-12 。内联替换内容的示例。填充、边框和边距会影响此图像在各个方向占用的空间。
内联非替换内容(通常指文本)从font-size
和line-height
获得其高度。与图 9-12 中的内联图像不同,内联非替换内容上的填充和边距被应用,但只影响文本流向的元素和周围内容——在图 9-13 中,这是在左边和右边。负的左边距会将元素向左移动,负的右边距会拉近后面的内容,可能会与元素重叠。
图 9-13 。内联非替换内容的填充和边距(包括负边距)只影响文本流向周围的内容,在本例中是左右方向。
浏览器在行框中一次显示一行内联内容(文本和内联元素)。默认情况下,行框的高度足以容纳行中每个行内元素的框。对于替换的内容(内嵌图像),这来自内容的尺寸加上垂直边距、边框和填充。这就是为什么图 9-12 的右图中的图像增加了线条之间的距离。对于非替换内容(文本),这是内容的line-height
。默认情况下,行内内容在基线上垂直对齐,即使字体大小有很大不同。这可以用vertical-align
属性来改变,它也会影响内嵌框的高度。图 9-14 显示了添加line-height: 0;
如何改变大文本和不同垂直对齐元素的行内框,改变包含该内容的行框的高度。
图 9-14 :默认情况下,行框会扩展到包含其内容的行内框。对于非替换内容,您可以在比默认行框大的行内元素上使用line-height: 0;
来防止这种情况。
参考 Eric Meyer 的内联格式模型文章(发表于 2000 年!)以获得关于内联框如何布局的详细信息([
j.mp/inline-modelmeyerweb.com/eric/css/inline-format.html](http://j.mp/inline-modelmeyerweb.com/eric/css/inline-format.html)
)。
最后,如果您正在内联使用图像,vertical-align
是您想要尝试的东西(vertical-align: middle;
通常是您想要的)。我们将在第十章中更详细地介绍vertical-align
的财产。
虽然display: block;
和display: inline;
是最常见的值,display
也有一些其他值。其中最有用的是inline-block
,它使一个元素的行为与内联替换的内容相同,因此它被“收缩包装”到其内容中,并被视为内联框,但我们仍然可以使用width
、height
、margin
和padding
。然而,对于它包含的任何元素,它表现为一个块级容器,你可以在图 9-15 的中看到inline
和inline-block
之间的比较。
图 9-15 。宽度、填充、边框和边距都为display: inline;
和display: inline-block;
的元素。对于display: inline-block;
,宽度(和高度)、垂直填充和边距影响元素的框和周围的元素,与替换的行内内容相同。
注意 IE 6-7 只接受默认为display: inline;
的元素上的inline-block
(j.mp/ppk-display
[www.quirksmode.org/css/display.html](http://www.quirksmode.org/css/display.html)
)。你可以通过只针对 IE6-7 的样式同时应用display: inline;
和zoom: 1;
来欺骗他们装病(j.mp/ie-inline-block
10)。注意display: inline-block;
也可以用于页面布局,尽管有一些注意事项,比如源代码中的空白,这是我们将在本章后面讨论的内容。
有一大组与表格相关的自定义样式表,尽管您不需要为普通的数据表指定它们,因为它们已经在浏览器的默认样式表中了。但是,如果您将 CSS 表格模型用于非<table>
元素上的布局,您可能会使用它们,这一点我们将在后面介绍。
还有一些特殊用途的样式表,您可能只会在浏览器的默认样式表中看到,比如list-item
和ruby
。最后还有none
,它阻止元素(和所有子元素)产生一个盒子。
块级框可以包含块级框或行内框。这听起来可能有点奇怪,因为在下面的代码中,<div>
包含文本和块级元素,并且完全有效:
`
An important block-level paragraph
10
在这种情况下,浏览器会添加匿名框(块级或内联)来匹配可视化格式模型的规则,并使内容的布局更加容易。每当元素的display
属性与视觉格式化模型相矛盾时,也会发生这种情况。图 9-16 在左边显示了由元素生成的盒子,在右边是一个浏览器会使用的匿名盒子的代表。
图 9-16 。“一些内联内容”将成为块级匿名框,因为它的兄弟<p>
是块级的。元素两边的内联内容将成为内联匿名框。
重要的是要注意,你不能使用 CSS 来设计匿名框本身的样式——它们从它们的父对象那里获得可继承的样式,并为其他所有东西采用默认值。然而,了解匿名框是有好处的,因为有时这种行为会导致意外的渲染。
不知道元素的默认显示值或它们的 HTML5 内容模型可能会导致意外的呈现,因此我们建议您熟悉这些内容,以便知道什么可以放在哪里。随着时间的推移,你会学到这方面的知识,但是当你有疑问时,使用验证器,并检查规范:
[
validator.nu/](http://validator.nu/)
)j.mp/html5-elements-index
11)j.mp/html5-element-categories
12)[
j.mp/css-2010-properties](http://j.mp/css-2010-properties)
14 )display
和其他属性的计算值。这会告诉你浏览器实际使用的是什么;如果和你预期的不一样,可能是这样的原因。11
12
13
前面我们已经了解到,块级别的盒子和它们包含的元素一样宽,并且被添加到前一个块级别的元素下面。这被称为正常流程(默认情况下框在那里),实际上是由于默认的定位方案position: static;
。CSS 2.1 中还有三种其他的定位方案:相对、绝对和固定定位。这三个定位方案允许您使用属性top
、right
、bottom
和left
将元素从方案的默认位置移开,这些属性接受长度值。如果您同时设置了top
和bottom
,或者left
和right
,这些也会分别设置元素的height
和width
,
position: relative;
的盒子所占空间与其在正常流程中所占空间相同(如果是position: static;
)。但是您可以使用top
、right
、bottom
和left
将相对于移动到这个位置。如果移动元素,它所占用的原始空间将被保留(内容不会上移),并且移动的元素可以与其他内容重叠。position: relative;
对于为绝对定位的元素建立一个包含块也很有用。top
、right
、bottom
和left
来移动(和调整大小)。然而,与相对定位的元素不同,如果没有设置width
,它会“收缩”到内容的宽度,并且在正常流中不会占用任何空间。一个绝对定位的元素最初将出现在它的静态位置,但是如果使用top
、right
、bottom
或left
移动,它将相对于它的包含块(它将是没有position: static;
的最近的祖先元素)或根元素<html>
定位。position: fixed;
的元素最初也将出现在其静态位置,top
、right
、bottom
或left
将相对于视窗(或打印样式表的每一页)对其进行定位。当页面滚动时,带有position: fixed;
的元素不移动。像绝对定位的元素一样,它们仍然可以覆盖其他内容,如果没有设置width
,它们也会“收缩包装”。你可以在图 9-17 中对比这些定位方案。
图 9-17 。positioning
属性的四个值的比较。每一对中右边例子中的定位框也有样式top: -1em; left: -1em;
,并且稍微透明,以便更容易看到发生了什么。
虽然定位是一个有用的工具,但被定位的元素很容易重叠或隐藏内容,使它们变得不可原谅。即使字体大小和视窗宽度发生变化,也要检查是否留有空间。
当发生重叠时,CSS 中的默认分层是 HTML 源代码中后面的元素将覆盖前面的元素。使用z-index
属性可以改变这一点。它接受整数值,按照从负到正的顺序堆叠元素,此外还有默认的auto
值。具有整数值的定位框(包括position: relative;
)建立一个堆栈上下文,子元素基于它们的z-index
值进行堆栈。元素将需要有透明或半透明的背景(如opacity: 0.5;
、HSLa
或RGBa
颜色,或不透明的图像),以显示它们重叠的元素。
通常,重叠或隐藏的内容不是您想要的,您可能想要为定位的元素腾出空间,例如通过在另一个元素上使用边距,而不是使用z-index
。然而,有时候只是门票的问题。最后,z-index
整数是相对的,所以如果你没有得到你想要的效果,使用一个巨大的z-index
数字是无济于事的——而是寻找原因。
属性最初被指定为允许文本环绕图像。它取值为left
、right
、none
和inherit
。使用默认的width: auto;
将float: left;
应用到一个图像,使其成为一个块级的盒子*,其内容的尺寸为*(“收缩包装”)。因此,除非内容有一个固有的宽度(比如一个图像),否则您通常也会想要添加一个特定的width
。float: left;
向左移动元素,直到它接触到包含框或另一个浮动的边缘,而float: right;
向右做同样的动作。浮动元素也会将其从文档流中移除,因此它不会占用任何空间。这意味着后续未被浮动的块级元素会忽略被浮动的元素,并向上移动以填充间隙。然而,行内元素和行框仍然为浮动元素腾出空间。例如,参见图 9-18 。
图 9-18 。后面跟有段落的块级图像。应用float: left;
或float: right;
意味着图像不再占用正常流程中的空间(允许段落上移),但段落的行框会为图像腾出空间。
如果不止一个连续的元素被浮动,只要还有空间,它们就会堆叠在一起。带有float: right;
的元素从右到左排列,如图 9-19 中的右图所示。
图 9-19 。如果有空间的话,浮动的元素会在彼此旁边浮动。带有float:right;
的元素从右到左排列。
一旦没有足够的空间,浮动将“下降”到第一个可用的空间。如果浮动的高度不同(如果涉及文本,这种可能性很大),这可能不是你所希望的空间,如图 9-20 所示。
图 9-20 。一个掉落的浮子将会到达第一个有空间的地方。除非每个浮动元素都是相同的高度,否则这不会是您想要的位置。
如果您的网格只包含图像,您可以控制它们的大小,或者使用包装元素使每个图像具有相同的高度来防止这种情况。虽然你可以在 ems 中设置足够大的高度来包含任何内容,但是如果艺术总监的简报中的对象包含文本,那么使用不同的布局技术可能会更容易。
因为浮动元素在正常流中不再占用任何空间,所以只包含浮动的元素将表现得好像没有内容一样。如果浮动容器是为了给浮动提供背景,这是不好的。此外,默认情况下,比容器高的浮动会伸出底部,因此它可以与后续内容进行交互。这对于图片周围的文字来说可能没问题,但是对于下一个部分的标题来说就不太好了。为了控制这一点,你需要学习如何清除浮动。
有几种方法可以将一个元素推到前面的浮动元素之下,或者使一个带有浮动子元素的元素展开以包含它。它们各有优缺点,我们一个一个来看。
clear
属性:对于值为left
、right
或both
的元素,应用该属性可以防止它出现在前面任何分别具有float: left;
、float: right;
或 float 值的元素旁边,而是将其移动到被浮动元素的下面。虽然您可以将它添加到一个或多个 float 后面的元素中,为 float“腾出空间”,但有时没有元素可以添加它。历史上,人们在浮动元素后添加<br style="clear:both;" />
来使浮动容器扩展以包含它,但是现在有更好的方法。clearfix
):最初由托尼·阿斯莱特开发的 clearfix 方法(j.mp/easy-clearing
14)通过使用生成的内容和:after
,给出了使用clear: both;
而不添加额外元素的好处。虽然这是一种流行的技术,但实际上它在 IE < 8 中的效果略有不同,正如 Thierry Koblentz 在“你所知道的关于 Clearfix 的一切都是错误的”([
j.mp/clearfix-details](http://j.mp/clearfix-details)
15 )中所详述的那样。* 浮动容器:一个浮动自动包含任何被浮动的元素。单独使用,这已被称为浮动几乎一切(FNE)方法清除浮动 ( [
j.mp/fne-method](http://j.mp/fne-method)
16 )。一般来说,我们建议采用以下浮动结算方法,而不是专门为 FNE 结算而浮动。然而,知道浮动将包含浮动的子对象意味着你不需要清除一个浮动容器,它本身就是浮动的。* overflow
属性:控制当一个块级元素的内容对于它来说太大时会发生什么,比如一个长单词或者一个<pre>
块。默认情况下,块级元素将垂直扩展,但是如果元素具有太小的固定高度或宽度,它将显示垂直或水平滚动条以提供对内容的访问。一般来说,除了浏览器的垂直滚动条,任何东西都应该避免——人们尤其讨厌水平滚动。对一个元素应用除了visible
之外的任何值也会“清除”它旁边或里面的浮动。将overflow: auto;
添加到一个包含浮动的元素中通常是一个很好的方法,可以使它扩展到包含一个浮动,尽管您需要注意滚动条上比容器更宽或更高的内容。对于图像,你可以使用max-width: 100%; height: auto;
(CSS,我们将在讨论响应式网页设计时再次讨论),对于文本,你可以使用word-wrap
,我们将在第十章中介绍。注意overflow: hidden;
也是有用的,尽管应该小心使用。最后,请记住这在 IE6 中不起作用,在 IE6 中您需要使用不同的技术,比如 Micro Clearfix 方法或zoom: 1;
。** 微 Clearfix 方法:尼古拉斯·加拉格尔广泛研究了传统 clearfix 方法的问题,并开发了一种新的微 clearfix 方法([
j.mp/micro-clearfixnicolasgallagher.com/micro-clearfix-hack/](http://j.mp/micro-clearfixnicolasgallagher.com/micro-clearfix-hack/)
),这种方法在不同浏览器之间保持一致,并且代码更少。当你需要清除浮动并且不能使用overflow
时,我们推荐使用这个。
**__________
14
15
16
/* For modern browsers */ .group:before, .group:after { content: " "; display: table; } .group:after { clear: both; } /* For IE 6/7 (trigger hasLayout) */ .group {
*zoom: 1; }
你可以在图 9-21 的中看到浮动清算的不同之处
图 9-21 。非浮动的容器元素不会扩展到包含浮动的子元素。一个后来被清除的非浮动兄弟元素,或者对容器应用一个“clearfix ”(比如overflow: auto;
或者微 clearfix ),将扩展容器以包含浮动的子元素。
我们发现我们通常使用 micro clearfix 和overflow
方法,但是只针对需要它的元素。然而,简单清除方法的跨浏览器问题给了我们一个很好的机会来研究为什么,并顺便提及 CSS 布局的基础之一。
您知道块级别的框是垂直布局的,它们的左边缘与包含它们的块元素的左边缘相接触(对于从左到右的语言)。但是浏览器怎么知道包含的元素是什么呢?建立块格式化上下文的元素成为其子元素的包含元素。默认情况下,这包括
static
或relative
之外的任意position
值的元素(例如absolute
或fixed
inline-block
、table-cell
和table-caption
的display
值)visible
之外的任意值overflow
的块级盒建立块格式化上下文可能非常方便。例如,一个浮动旁的未浮动元素将为浮动腾出空间,如果它成为一个块格式化上下文,如图 9-22 所示。
图 9-22 。使用overflow: auto;
在段落上建立块格式上下文
您会注意到,这个列表包括了我们前面提到的几种清除浮动的方法——清除浮动是块格式化上下文的属性之一。除了清除浮动外,请记住:
块格式上下文是浏览器如何进行布局的一个重要部分,花时间去理解它会让你对布局如何工作有更多的了解。这里有一些关于这个高级主题的进一步阅读材料:
[
j.mp/overflow-benefit](http://j.mp/overflow-benefit)
17
[
j.mp/css-bfc](http://j.mp/css-bfc)
18 )17 www.stubbornella.org/content/209/07/23/overflow-a-secret-benefit/
18
回到 IE 6-7 中轻松清除方法的结果略有不同的原因,这是因为这些浏览器不支持:after
,而 IE 专有的zoom
属性被用来清除它们。请注意,zoom: 1;
使用 IE 的内部布局属性hasLayout: true;
对元素进行样式化。其中,这会导致元素生成一个新的块格式上下文并包含浮动。然而,容易清除,非 IE CSS 规则不这样做,导致潜在的显示差异。micro clearfix 方法会在所有浏览器中产生新的块格式化上下文。
随着 Internet Explorer 8 和更高版本支持生成内容,这些版本在遵循规范方面做得越来越好,了解hasLayout
的特性不再像过去那样重要。不过,在支持 IE6-7 的时候了解一下还是有好处的,所以这里有一些背景:
【Internet Explorer has layout 属性】by SitePoint ( [
j.mp/ie-haslayoutreference.sitepoint.com/css/haslayout](http://j.mp/ie-haslayoutreference.sitepoint.com/css/haslayout)
`《论拥有的布局》作者:霍利·伯格文、英戈·曹、布鲁诺·法西诺、约翰·格兰特、格奥尔格·索尔顿、菲利普·维滕贝格(【http://j.mp/having-layoutl】19)
当我们谈到老 IE 怪癖的话题时,如果你遇到 IE6 的双边距错误(j.mp/doubled-margin
20),你可以通过为该浏览器应用display: inline;
来修复它。浮点的计算类型总是display: block;
,所以这不会有任何负面影响。请注意,如果浮动包含比浮动的width
更宽的内容,IE6 也会扩展浮动,而不是让内容突出来。如果没有预期的那么多空间,你可以使用针对 IE6 的overflow: hidden;
来防止这导致浮点下降。
###### 布局浮动
浮动布局只是使用浮动的能力与浮动或未浮动的内容并排排列而不重叠,将这种能力应用于布局各部分的容器元素。虽然它们最初不是为布局而设计的,但它们已经成为当前的布局主力,是 CSS 2.1 中不太好的布局选项中的佼佼者。
那么现在你已经知道了基本的浮动和清除浮动,你实际上是如何使用浮动来设计一个网页的呢?当内容垂直扩展时,常见的网页设计布局模式是有一个全幅页眉,接着是 1-3 列内容,最后是一个全幅页脚,出现在最高的一列之后,如图 9-23 所示。
19
20 www.positioniseverything.net/explorer/doubled-margin.html
图 9-23 。常见的设计模式包括页眉、页脚和一至三列内容。一栏布局是纵向模式下手机的默认布局。灰色背景表示列,但是请注意,当使用浮动时,每个浮动将只和它的内容一样高。
一列布局很容易,全角的页眉和页脚也一样——块级元素默认是全角的。您可以使用浮动将块级元素放在一起,例如两列或更多列。但是,您需要注意所有列的总宽度变得大于包含元素宽度的 100%,好像没有足够的水平空间让浮动适应,这意味着最后一列将“下降”到下面。如前所述,混合水平单位(width
以百分比表示,border
以像素表示,等等。)使这成为可能,除非你使用box-sizing: border-edge;
。我们的老朋友 IE 6 可以增加元素宽度几个像素(除了不支持box-sizing
),所以让列的组合宽度比包含元素的宽度小一点是个好主意,这样可以防止意外的列丢失。
让我们看看一些选择。
您可以使用上述方法的修改版本来对齐两个以上的列。
我们建议启动你的文本浏览器(或使用 Dabblet.com 或 CodePen.io 等在线工具),重新创建其中一些布局,为每个列元素分配不同的背景颜色。通过应用不同的 CSS 规则并查看结果,您将开始了解如何使用浮动构建一个简单的布局。
<style scoped>
` div {
border: 1px solid #666;
padding: 0.5em;
background-color: #ddd;
}
.main {…}
.secondary {…}
.tertiary {…}
记得给每个 div 添加一些文本,或者指定一个宽度和高度,这样你就可以看到它们。
如果你的列有背景色,你可以看到浮动框只延伸到它们的内容。但是,您可能希望列背景色延伸到页脚,即使对于较短的列也是如此。要获得高度相等的列,您可以使用几种技术之一来伪造它。不幸的是,除非你使用基于像素的列宽(丹·塞德霍尔姆的假列宽技术是完美的(j.mp/faux-columns
21),否则没有基本的和广泛支持的方法,然而,克里斯·科伊尔已经汇编了一个 CSS 技巧的选项列表来帮助你(j.mp/equal-height-cols
CSS-Tricks . com/fluid-width-equal-height-Columns/),到你完成这本书时,尼古拉斯·加拉格尔的聪明的伪
21
在尝试这些布局模式时,您会注意到列元素的 HTML 源顺序决定了它们的位置。当这是你想要的顺序时,这是好的,但有时不是。例如,在你的 HTML 中按照重要性排列你的内容是最理想的(基于用户想要首先看到的),所以如果你的 CSS 没有加载,主要内容将会在顶部附近。理想情况下,你应该从一个简单的、单栏的、移动友好的布局开始(当我们在本章后面讨论响应式网页设计的时候会有更多的介绍),然后在编写 CSS 的最后为更宽的显示器上的栏添加 CSS。如果是这样的话,你的内容来源可能已经按重要性排序了。即使你是从桌面布局开始的,当线性化你的设计——移除列上的浮动以使一列布局更适合移动设备时,把这想成一个好的源顺序是有用的。
虽然没有属性可以改变同级浮动的顺序,但是当你的列使用相同的width
单位时,你可以在源中按照重要性顺序保存你的内容,然后通过使用负边距重新排列你的列。例如,您可以在图 9-24 的中看到以下代码的结果。
`
div {
float: left;
/* box-sizing for easy testing /
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
border: 1px solid #666;
padding: 0.5em;
background-color: #ddd;
}
.content content {width: 50%;}
.nav secondary {width: 30%;}
.sidebar {width: 20%;}
/ nav - content - sidebar /
.content {margin-left: 30%;} / space for nav /
.nav {margin-left: -80%;} / 50% + 30% /
/ sidebar - content - nav /
.content {margin-left: 20%;} / space for sidebar /
.sidebar {margin-left: -100%;} / (50% + 20%) + 30% */
/* content - nav - sidebar /
/ This is easy as it’s source order. Floating alone is enough! */
/* nav - sidebar - content
not necessarily a good layout, but to show how it’s done /
.content {margin-left: 50%;} / space for nav + sidebar /
.nav {margin-left: -100%;} / (50% + 50%) /
.sidebar {margin-left: -70%;} / 50% + 20% */`
图 9-24 。使用负边距和数学重新排列浮动元素
要了解更多关于灵活布局的信息,我们推荐 Zoe Mickley Gillenwater 的书灵活的网页设计。还推荐以下文章:
[
j.mp/ala-holy-grail](http://j.mp/ala-holy-grail)
22 )[
j.mp/meyerweb-columnsmeyerweb.com/eric/thoughts/2005/11/09/multi-unit-any-order-columns/](http://j.mp/meyerweb-columnsmeyerweb.com/eric/thoughts/2005/11/09/multi-unit-any-order-columns/)
)的“多单元任意顺序列”当用于布局尺寸时,三种受支持的长度单位(像素、百分比和 ems)具有不同的属性。当然,您可以将这些布局技术用于页面的某些部分以及页面布局。您还可以根据需要将各种布局技术混合在一起。让我们依次简单看一下每一个。
基于使用不灵活的基于像素的布局,把网页设计和印刷设计同等对待是一个悠久而光荣的传统。基于像素的布局只是在容器元素上使用像素尺寸,比如<body>
或<div class="wrapper">
。图 9-25 显示了一个基于像素的页面布局的例子。
22
*Remember that setting a fixed height on anything containing text (or content sized using ems) is generally asking for trouble*
图 9-25 。基于像素的布局在预期的视口宽度下工作良好,但是如果没有额外的工作,在较小的尺寸下将变得非常不可用。这里我们放大了右图中的主要内容,因此部分导航不再可见。在狭窄的视窗中,这将导致水平滚动。([
html5doctor.com/)](http://html5doctor.com/)
当您的内容主要是固定宽度,尤其是替换的内容(如图像或视频)时,使用像素尺寸进行布局是有意义的。在每个像素都至关重要的情况下,例如移动网站或密集 web 应用的界面,它也很有用。另一个需要考虑基于像素的布局的时候是当你的设计依赖于文本与背景图像的关系时(尽管我们会警告不要使用这种设计),或者当你需要合并大的固定宽度的横幅广告时。
旁白:视窗是用户浏览网页的窗口。如果网页比视窗大,默认情况下会出现滚动条。
基于像素的布局不能适应字体大小或视口大小的变化。虽然这被认为是像素布局的优势之一,但事实上,这种不灵活性使它们仅适用于理想环境。此外,随着屏幕尺寸不是 320x480px 的移动设备激增,基于像素的手机布局的有用窗口也很有限。因此,我们发现我们不使用基于像素的布局,除非是在测试或原型制作时。
那么像图片这样宽度固定的内容呢?嗯,图像宽度是固定的只是你的想法,你很快就会看到。
*###### 灵活的布局
灵活布局基于使布局适应浏览器环境的单元。虽然它们可能需要更多一点的远见(特别是如果你习惯于基于像素的设计),但它们的回报是更防弹,或更不容易在压力下破裂。
液体布局(也称为液体布局)使用百分比定义水平尺寸,适应浏览器的宽度,并帮助防止可怕的水平滚动。块级元素的默认样式相当于全宽、单列液体布局。百分比的主要缺点是,如果不小心的话,很容易在大显示器上产生不合理的长行,这会损害可读性。因此,液体布局通常应使用 ems 或像素中的min-width
和max-width
值。图 9-26 显示了一个流动页面布局的例子。
图 9-26 。一种液体布局,其中元素的宽度会改变以适应可用的空间。它使用max-width
来防止宽视窗中的线变得过长。(oli.jp/
但是,它们最适合灵活的内容。宽或固定宽度的内容(如图像、表格和代码块)需要特别小心。对于替换的内容,比如图像,解决这个问题的一种方法是使用max-width
属性。
<style> img { max-width: 100%; height: auto; /* so images with a height attribute don’t scale in one dimension */ } </style> <img src="img/earth.jpg" width="695" height="695" alt="The blue marble of earth, as seen from space">
默认情况下,图像的大小是width
和height
属性的大小(或者图像的固有宽度和高度,如果没有设置这些属性的话),让浏览器分配空间并防止桌面浏览器中的重排。但是,如果图像的包含块变得比图像的宽度窄,max-width
和height
属性将缩放它。这可以防止固有的图像宽度破坏布局,浏览器通常也会合理地缩小图像。图 9-27 显示了结果。
图 9-27 。太大的柔性图像(带有相对单位中的max-width
)将被浏览器缩放。左边的图像有max-width: 100%;,
,当比包含的元素或视口更宽时将被缩放。如右图所示,默认图像(使用固有尺寸)不会被缩放,默认情况下会触发水平滚动条。
创建液体布局时,可以通过多种方式获得宽度值。除了使用基于网格的值,或看起来合适的值(如 50%、33%、66%等。),您还可以为目标屏幕宽度创建一个基于像素的网格(可能基于实体模型),然后使用公式size ÷ context = result
进行转换,将结果处理为百分比。例如,对于 960 px 宽的设计,360 px 宽的列将得到 360 ÷ 960 = .375,即 37.5%。顺便提一下,这个“期望的size ÷ context = result”
公式也被用于计算第十章中ems
的排版。如果这样做,我们建议在值旁边的注释中“显示您的数学”,例如:
.content { width: 37.7083333%; /* 362px/960px */ … }
虽然这看起来比仅仅使用像素要多得多,但基于百分比的布局将优雅地适应更大和更小的视口大小,这是一个巨大的好处。你将需要一些额外的技术来优化你的液体布局,以适应非常窄和非常宽的屏幕,因为它只能适应到此为止。这是我们将在本章后面的媒体询问中涉及的内容。
虽然我们通常喜欢流畅的布局,但是有一个重要的注意事项要记住。与所有以像素以外的形式指定的长度值一样,浏览器必须将百分比值转换为像素进行显示。正如 John Resig 在“CSS 中的子像素问题”中所描述的那样,不同的浏览器在这方面的方法略有不同(见表 9-2 ),这可能会导致浏览器之间的细微差异。
这可能会导致一些问题,如向下舍入时元素过窄几个像素,向上舍入和向下舍入时元素之间偶尔会有 1 px 的间隙,以及向上舍入时浮动元素会落在其他内容的下方。前两个通常是小问题,但是 Internet Explorer 的舍入可以打破基于浮动的布局。避免这种情况的一个方法是确保你的宽度值略小于 100%,给一点回旋的空间。浏览器正在转向使用亚像素定位(截至 2012 年年中的 Firefox、IE 10、WebKit),因此未来将更经常地做你期望的事情。
最后,还有一些 Internet Explorer 问题需要解决。如上所述,IE6 不支持min-width
、max-width
、min-height
或max-height
。对于内容图片,通常可以通过专门针对 IE6 的样式将max-width: 100%;
替换为width: 100%;
来保持流畅性。注意max-width: 100%;
只影响比包含块更宽的图像。然而,使用width: 100%;
意味着图像将始终是包含块的宽度。这是完全不同的,会导致问题,所以要彻底测试。如果绝对需要,还有基于 JavaScript 的 polyfills,如狄恩·爱德华兹的 IE7.js ( [
j.mp/ie7-js](http://j.mp/ie7-js)
code.google.com/p/ie7-js/
)。
另一个问题是,与现代浏览器不同,IE6 缩放图像的能力非常差。如果这是一个问题,你可以用 CSS -ms-interpolation-mode: bicubic;
或者使用微软专有的 CSS 过滤器 AlphaImageLoader 来解决。关于 AlphaImageLoader 技术的细节和自动化该过程的便捷脚本,请阅读 Ethan Marcotte 的“流体图像”([
j.mp/fluid-images](http://j.mp/fluid-images)
23 )。这是他的书响应式网页设计第三章的一部分,我们强烈推荐阅读。
弹性布局使用ems
进行水平测量,这是基于浏览器的字体大小。默认情况下,1em = 16px。这意味着如果用户增加或减少字体大小,基于em
的布局将相应地调整,保持行的长度。图 9-28 显示了一个弹性页面布局的例子。
图 9-28 。伯里亚街 456 号(www.456bereastreet.com/
),罗杰·约翰逊的网站,展示了基于 em 的布局。通过关闭 Roger 的max-width
声明,我们可以在第二个图像中看到水平滚动,其中浏览器的字体设置已经增加。
从历史上看,在浏览器中增加或减小尺寸只会改变文本大小,而不会影响其他内容或页面布局。通过在ems
中设置水平尺寸,你可以改变文本尺寸,也可以缩放页面布局,甚至是图片等内容(如果它们是在ems
中调整的)。所有浏览器的最新版本现在默认缩放页面,减少了基于 ?? 布局的好处,但是为了向后兼容,记住这一点是很好的。
此外,如果用户设置了非常大的文本大小,这会严重影响布局,因为内容对于视窗来说变得太宽了,所以会出现水平滚动条。与流动布局一样,您应该选择一个支持的文本大小范围,并使用不同单位(如百分比或像素)的max-width
来防止水平滚动超过这个范围。虽然并不常见,但这仍然是您工具箱中的一个很好的技术,因为您可以在混合布局中组合布局技术。
23
混合布局结合多种布局方法来创建布局。通常,这用于将固定宽度的内容(以像素为单位声明的宽度)与流动内容相结合。当你在侧边栏中有固定宽度的内容(比如广告)时,这是一个很好的选择,它结合了一个流动的主内容栏。图 9-29 显示了一个使用浮动的网站,元素宽度以 ems 表示,最大宽度以像素表示,加上一些绝对定位和使用display: inline-block;
。
图 9-29 。Lea Verou 的语法高亮器 Prism(prismjs.com/
)的网站是一个混合页面布局的例子,结合了各种布局方法。
混合布局的一个好处是你可以混合你的布局技术来利用每种技术的优势。例如,您可以在 ems 中设置页面的宽度,然后按百分比设置列宽,以使弹性设计更加可靠。然而,最近我们发现自己倾向于使用页面布局,所有列以百分比表示,加上以 ems 或像素表示的min-width
和max-width
值,而不是基于像素的混合布局。
总的来说,如果你开始使用 CSS 布局,我们最好的建议是制作一些试用页面,使用浏览器的开发工具查看它们,然后进行实验。尝试编辑应用的 CSS 规则,看看这如何改变元素的位置、计算的布局样式以及与其他元素的交互。之后,尝试看看不同的浏览器如何显示相同的页面,您将很快熟悉使用 CSS 的布局、浏览器差异和基于浏览器的工具。
CSS 布局通常围绕着一个全幅的页眉和页脚,中间有一列或多列。为此,您需要的最基本的东西如下:
如果包含元素收缩包装它们的内容也很好,这样您就不需要显式地设置宽度和/或高度,并且列适应它们的周围环境(换句话说,它们不会相互覆盖)。虽然我们已经详细介绍了浮动,但是还有另外两个基于 CSS 2.1 的方法可以满足这些需求,并且可以用于布局。不幸的是,这两者都…对 Internet Explorer 6-7 具有挑战性。让我们快速浏览一下。
带有display: inline-block;
的元素并排排列,并收缩其内容。更好的是,您可以使用类似于text-align: justify;
的属性来等间距放置子元素,text-align: center;
来轻松地居中放置元素,vertical-align: top;
来制作一个将成行排列的方框网格。您还可以使用负边距技术,可能与容器元素上的填充相结合,来重新排列列,就像您对浮动所做的那样。图 9-30 显示了图 9-24 使用显示重新制作的布局:内嵌块;
图 9-30 。使用负边距对display: inline-block;
列重新排序。与图 9-24 中的进行比较。
这看起来很棒,但是有两个浏览器支持问题需要解决。IE6 和 7 不支持inline-block
,尽管如前所述,你可以通过同时应用display: inline;
和zoom: 1;
来欺骗它们,只使用针对 IE6-7 的样式。
第二个问题可能更困难——由于 CSS 折叠 HTML 中元素间空白(HTML 代码中的空格、制表符和换行符)的方式,使用 inline-block 的元素之间自然会有一个小空格。这大约是 4 px,但是根据容器元素的字体和字体大小以及浏览器的不同而不同。只要您的设计不依赖于精确对齐,或者知道一行内联块元素的确切宽度,这就不是问题。如果你的设计依赖于此,比如导航标签应该接触,有几种方法可以解决这个问题。可惜都不理想。
最简单的方法是删除 HTML 中元素之间的空白。您可以通过以下任何一种方式来实现这一点:
<li>
元素时,可以省略结束标记,因为这些元素在 HTML5 中是自结束的。这对<div>
、<section>
等元素不起作用。虽然我们更喜欢显式的结束标记,但这是完全有效的 HTML5。有关示例,请参见以下代码示例:
`
解决这一问题的其他方法更加脆弱。您可以尝试以下方法之一:
font-size: 0;
,然后在列元素上重置font-size
。这停止了字体大小的继承,尽管您可以在现代浏览器中使用rem
来重置它,或者甚至在容器元素上使用font-size: 1%;
,在子元素上使用font-size: 10000%;
。-0.3em
的右边距。这在 IE6-7 中可能会失败,您需要针对您正在使用的字体进行调整并彻底测试。您还可以将font-family
设置为 Courier New,确切地说应该是margin-right: -0.6em
,尽管您还必须在列元素的子元素上重置font-family
。CSS4 中提出了一种使用text-space-collapse: discard;
来解决这个问题的方法,但是,好吧,它是 CSS4,在编写本文时没有任何支持。这些选项都不是特别好,但是只要你的设计不依赖于相邻的元素接触或者知道确切的宽度,这就不是问题。这在 HTML5 样板网站(html5boilerplate.com/
)的图 9-31 中有演示,它使用内嵌块来布局导航、按钮和内容栏。
图 9-31 。HTML5 样板网站大量使用display: inline-block;
进行布局。
如果你的设计依赖于精确的尺寸,考虑一个“去除 HTML 空白”的变通方法,或者一个不同的布局方法。
在 web 标准运动花费了 10 年的时间来阻止使用嵌套的<table>
元素进行布局之后,建议使用表格进行布局可能看起来很奇怪。然而,与表相关的display
值是基于 CSS 的表示,当应用于像<div>
或<section>
这样的元素时,不会滥用<table>
元素的语义。通过在列元素上指定display: table-cell;
,这些列将并排排列,并允许您指定宽度。将width
值应用到容器和列中可以得到一个布局。
这也给了你同样的好处,使得基于<table>
的布局如此吸引人。例如,border-collapse
和border-spacing
让您控制单元格之间的边框和间距,同一行的单元格将是最高单元格的高度,因此您不需要人造列。你甚至不需要将display: table;
或display: table-row;
分配给容器元素——对于单个行,浏览器会将它们添加为匿名框,以容纳带有display: table-cell;
的元素。您还可以用其他一些与表格相关的显示值做一些有趣的事情。例如,您可以将display: table-caption;
与caption-side
一起使用来重新排列元素的顺序,正如 Jeremy Keith 在“重新制表”([
j.mp/re-tabulate](http://j.mp/re-tabulate)
adactio.com/journal/4780/
)中所介绍的那样。
坏消息是 IE 6-7 不支持display: table;
,除了为这些浏览器创建一个单独的后备布局之外,没有别的解决方法。也没有与 HTML 属性colspan
和rowspan
等价的 CSS,复制它们通常需要带有display: table;
或display: table-row;
的复杂嵌套元素。请记住,表格单元格会扩展以包含它们的内容,如果替换了图像等内容,这可能会破坏基于display: table;
的布局。您可以将table-layout: fixed;
添加到带有display: table;
的元素中,以强制遵守单元格宽度。最后,表布局附带了所有使基于表的布局如此脆弱的源顺序依赖性。在撰写本文时,我们认为除了渐进式增强风格的改进之外,这些都是重要的问题。
使用display: inline-block;
和display: table;
的主要区别如下:
inline-block
元素将会下拉到下一行(像浮动),宽度为的inline-block
元素中的内容将会突出,display: table
将会触发水平滚动。
text-align: center;
代表display: inline-block;
,用border-collapse
和border-spacing
代表display: table;
,这给了每种技术不同的优缺点。display: table;
的支持,需要替代布局。虽然display: inline-block;
和display: table;
都是潜在有用的布局选项,但它们都有潜在的严重缺陷。然而,我们认为它们值得尝试并牢记在心,因为偶尔它们会是你想要的。
总之,这些明显不足的基于 CSS 2.1 的布局工具,加上旧浏览器中不稳定的支持,使得复杂布局成为 CSS 中一个明显的痛点。幸运的是,CSS 中的布局终于得到了万维网联盟(W3C)和浏览器制造商的喜爱和关注。然而,在我们看到即将发生的事情之前,让我们先来看看一些相关的有用的(也是必要的)东西:媒体查询,响应性网页设计,以及处理高分辨率显示的技术。
我们之前在描述液体或流体布局时提到了响应式网页设计——使用百分比表示水平宽度的布局。在《论“响应式”(j.mp/being-responsive
24)一书中,开创了“响应式网页设计”的伊桑·马科特(Ethan Marcotte)将它的三个主要要求定义为:
24
从根本上来说,这是约翰·奥尔索普的“网页设计之道”一文中观点的优雅、现代的继承者,即“放开控制,变得灵活”通过以灵活性或适应性为基本理念进行设计,然后使用媒体查询来根据设备的属性进一步调整设计,你可以做出在各种设备上都能优雅响应的设计。我们已经介绍了灵活的网格(基于百分比和em
的布局)和图像(max-width: 100%; height: auto;
),所以让我们看看媒体查询如何帮助我们。
媒体查询(25)最初是一种根据媒体提供不同 CSS 的方式,比如打印样式表:
`
`它们还允许您测试媒体特性,如浏览器宽度、屏幕宽度、设备分辨率等。这允许您基于这些特性定制您的 CSS,例如:
@media screen and (min-width: 24em) { body {CSS for everything except small devices…} … } @media screen and (min-width: 42em) { body {CSS for tablets and larger screens…}
… }
除了作为样式表<link>
元素上的属性和样式表中的@media
块之外,还可以在@import
规则上使用媒体查询(与@media
的方式相同)。然而,出于性能原因,我们建议不要使用@import
,因为以这种方式包含的样式表只会在第一个样式表下载后才开始下载。
在撰写本文时,媒体类型包括all
(默认)、braille
、embossed
、handheld
、print
、projection
、screen
、speech
、tty
和tv
。然而,在大多数情况下,你只需要all
、screen
和print
。
25 dev.w3.org/csswg/css3-mediaqueries/
媒体特征的列表更长,并且被添加到括号中的媒体查询中:
width
:浏览器视窗的宽度,最常用的查询height
:浏览器视窗的高度device-width
:设备屏幕的宽度device-height
:设备屏幕的高度resolution
:输出设备中的像素密度orientation
:不是portrait
就是landscape
aspect-ratio
:width
与height
的比率(例如,对于宽屏电视画面为 16/9)device-aspect-ratio
:device-width
与device-height
的比值color
:输出设备的每个颜色分量的位数color-index
:输出设备的颜色查找表中的条目数monochrome
:单色帧缓冲器中每个像素的位数scan
:电视输出设备的扫描过程grid
:查询输出设备是网格还是位图其中大多数也有min-
和max-
两种变体,但您通常会使用以下几种:
min-width
或max-width
min-height
或max-height
min-resolution
(与-wekbit-min-device-pixel-ratio
一起)resolution
属性用于具有自定义 CSS 的不同像素密度的目标设备(例如 Apple Retina 显示屏),并在dpi
(每 CSS 英寸点数)和最近添加的dppx
(每 CSS 像素点数)中取值。然而,WebKit 实现了相关的专有属性device-pixel-ratio
,它接受一个数字值。你最有可能看到的是-wekbit-min-device-pixel-ratio
,普通显示器是1
,视网膜显示器(分辨率加倍)是2
。其他浏览器也将此实现为-moz-min-device-pixel-ratio
和-o-min-device-pixel-ratio
(注意 Opera 变体采用小数值)。不过这些浏览器也实现了resolution
,你可以通过乘以 96 从device-pixel-ratio
转换成dpi
。这意味着目前的目标是双密度显示(每个 CSS 像素 4 个设备像素),你可以使用
@media screen and (-webkit-min-device-pixel-ratio: 2), screen and (min-resolution: 192dpi) {…}
dppx
支持变得广泛时,你将能够使用@media screen and (-webkit-min-device-pixel-ratio: 2), screen and (min-resolution: 2dppx) {…}
正如您刚才看到的,您可以使用基本的逻辑运算符“and”、“or”(作为逗号)和“not”来组合媒体查询选择器以下是一些例子:
screen and (min-width: 534px)
:将以下样式应用于所有基于屏幕的设备(例如,非打印设备),其显示屏为 534 px 或更宽。screen and (max-width: 960px), screen and (max-height: 960px)
:将样式应用于宽度在任一维度上高达 960 px 的设备。screen and (min-width: 20em) and (max-width: 32em)
:基于根font-size
,将以下样式应用于所有显示器宽度在 20em 和 32em 之间的设备。screen
和(max-width: 480px)
和(-webkit-min-device-pixel-ratio: 2), screen and (max-width: 480px)
和(min-resolution: 192dpi)
:将样式应用到 480 px 宽的双分辨率显示器设备,如 Retina 显示屏 iPhone(任一方向)。移动设备兴起之前建立的网站是按照特定的屏幕宽度建立的。虽然这并不被认为是建立一个“桌面优先”的网站,但事后看来,很容易看出这种偏见。虽然仍然可以首先为桌面浏览器设计,然后在移动电话的媒体查询中覆盖其中的一些样式,我们发现通过最初为移动浏览器设计,然后为更大的屏幕添加具有额外样式的媒体查询,工作流程更容易(并且 CSS 更简单)。另一个好处是,移动布局至少可以在任何不支持媒体查询的浏览器上使用,但宽布局可能不适用于小手机。Luke Wrobluski 在他的演讲“移动优先”(j.mp/mobile-first-preso
)中详细介绍了这种方法的好处。 26
然而,从哲学上来说,我们发现杰里米·基思在《内容第一》(【http://j.mp/content-first】adactio . com/journal/4523/)中阐述的内容第一设计更适合。在你开始考虑一个布局之前,你应该考虑什么内容是合适的,以及浏览网页的人想要达到什么目的。这样做可以防止“桌面优先”方法的一个常见问题:仅仅因为有空间就添加不必要的内容。从内容和功能入手,将有助于你了解网站(或应用)的架构,并使移动设计和桌面设计更容易。这也意味着在开始设计之前,你应该有很多内容,虽然这对于一些客户来说很棘手,但我们发现,如果可能的话,通过让你的设计立足于现实,最终结果会有很大的不同。
26 www.lukew.com/presos/preso.asp?26
虽然您可以通过查阅浏览器屏幕尺寸图表来选择媒体查询的目标宽度,但我们建议您也采用内容优先的方法。取而代之的是,拉伸内容,看看它在哪里断掉(或许可以使用 Remy Sharp 有用的 Responsive px 工具([
responsivepx.com/](http://responsivepx.com/)
),然后以此为基础设置断点。也没有什么要求你使用像素作为你的媒体查询长度单位——检查min-width
等等。在 ems 也很好用。
最后,请记住,您可以通过为每个查询仅设置一个min-
或max-
特性来进行媒体查询包含,或者通过设置两个特性来进行排除。例如,
@media all and (min-width: 534px) {…} @media all and (min-width: 961px) {…}
与非常不同
@media all and (min-width: 534px) and (max-width: 960px) {…} @media all and (min-width: 961px) {…}
这将影响应用哪些样式以及哪些样式可能需要替代。这是你在每个项目开始时需要做出的决定之一。关于你的各种与媒体查询相关的选择及其后果的更多信息,我们推荐阅读佐伊·米克利·吉伦沃特的详细文章《制作高质量媒体查询的基本考虑》(j.mp/quality-mq
27)。
有几种方法可以实现媒体查询。您可以将所有的 CSS 放在一个样式表中,适当地使用@media
媒体查询规则。在另一个极端,您可以将您的 CSS 分成几个样式表,每个媒体查询一个,然后通过<link>
添加它们。这两种技术各有利弊。例如,单个文件是好的,因为由于开始下载的开销,一个 20KB 的下载比两个 10KB 的下载快。对每个查询的样式表使用<link>
也有好处,因为不理解媒体查询的旧浏览器会忽略那些<link>
元素,避免下载不必要的样式。
不幸的是,还有比这更大的问题。与许多低端手机一样,Internet Explorer 版本 8 及以下支持基本的媒体查询(如screen
和print
),但不支持包含媒体功能的查询。哎哟。这意味着如果你从基本的移动风格开始,然后使用媒体查询来补充和覆盖桌面浏览器,IE 6-8 将只应用移动风格。有几种方法可以解决这个问题。
27 zomigi.com/blog/essential-considerations-for-crafting-quality-media-queries/
<body>
或包装元素来补充基本的移动样式(如果网站默认使用移动样式)。取决于你补充了多少,这可能导致你的代码“分叉”,本质上维持两种设计——如果可能的话,这是应该避免的。j.mp/respond-js
[
github.com/scottjehl/Respond](https://github.com/scottjehl/Respond)
)poly fill。然而,这意味着如果脚本没有加载或者 JavaScript 被关闭,您将回到“什么都不做”的方法。j.mp/windows-mq
adactio.com/journal/4494/
)详细介绍了如何操作,但代码如下:`
`这里有趣的条件注释为低于 IE9 的 Internet Explorer 版本加载了wide.css
样式表,但为 Internet Explorer Mobile 7 加载了而不是,后者不能解析基于功能的媒体查询,但应该获得移动样式。如果你使用 CSS 预处理器或类似的东西,按照你喜欢的方式安排你的 CSS 应该没有问题——你甚至可以创建两个版本的wide.css
,一个为现代浏览器的@media
块中的中间设备定制,另一个没有为旧的 Internet Explorer 定制。这是一个你可以通过“桌面优先”的方法避免的问题,但是如果你这样做了,你将面临处理移动问题的更大挑战。
说到这里,许多智能手机在小屏幕上处理以桌面为中心的设计的一种方式是假装 960 px 宽。然后在视窗中放大和缩小以阅读和移动页面进行导航。但是,您可以告诉移动设备使用它们实际的 CSS 像素宽度,方法是将这个 meta 标签添加到文档的<head>
:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
是的,width=device-width
和initial-scale=1.0
就是你所想象的:将视窗的宽度设置为设备的宽度(以 CSS 像素为单位),并且不缩放显示。您还可以将其他逗号分隔的值添加到content
,例如minimum-scale
、maximum-scale
和user-scalable
。注意minimum-scale=1.0
可能有用,但是应用maximum-scale=1.0
或user-scalable=no
通常会对用户不利,我们建议不要这样做。在 CSS 中设置这些东西也有可能通过 CSS 设备适配规范的@viewport
规则(j.mp/css-device-adapt
28)来实现,尽管在撰写本文时只有 Opera 支持。
您已经了解了如何制作流畅的图像,以及如何使用媒体查询来基于设备分辨率应用样式,但是这些基于像素的图像在响应式设计中仍然是一个棘手的问题。您希望将合适的图像发送到不同的设备——将高度压缩的小图像发送到小屏幕设备,将较大的图像发送到更大的屏幕。高分辨率显示器使这变得更加困难;双分辨率图像的像素是 ?? 的四倍,这让它们明显变大了。你肯定不想把大的、高分辨率的图像发送给外出走动的人的手机。说到这里,虽然有一个带宽检测的规范(网络信息 API 规范j.mp/netinfo-api
29),但在撰写本文时,只有一小部分当前移动设备支持它,因此我们目前被迫通过将带宽与屏幕大小相关联来猜测带宽,甚至求助于服务器端浏览器嗅探。所有这些都使得高分辨率图像成为一个主要问题。
浏览器的默认行为往往是“下载所有的东西!”理解高级媒体查询的浏览器将下载所有<link>
ed 样式表,即使媒体查询不适用。最新的浏览器不会预加载当前不适用的媒体查询中的图像。但是,在应用 CSS 和 JavaScript 规则之前,它们将开始预取页面上的所有图像。如果一个元素通过background-image
应用了一个图像,而这个图像随后在层叠中被覆盖,那么许多 Android 和 iOS 移动设备中的旧版本 Mobile WebKit 将会下载这两个图像。所有的浏览器也会下载隐藏在display: none;
元素中的图片。在撰写本文时,还没有官方的、实现的方法来解决这个图像问题(尽管它正在积极地工作)。总的来说,这意味着目前没有简单的方法来发送合适的图像,而有些人不得不下载同一图像的两个版本。
28 dev.w3.org/csswg/css-device-adapt/#the-viewport-rule
29 www.w3.org/TR/netinfo-api/
暂时忽略这些问题,让我们来看一个给你的页面添加高分辨率图像的基本方法:使用一个合适的大图像,然后使用<img>
元素属性或者使用 CSS 中的width
和height
来声明想要的尺寸。例如,如果您想将双分辨率 HiDPI 图像添加为 320x240 CSS 像素,并在双分辨率设备上以 640x480 设备像素显示,您可以创建 640x480 px 的图像,然后使用 CSS 或图像元素属性将其调整到所需的大小,如下:
<!-- resizing a 640x480px image using the HTML width and height attributes --> <img src="miss-baker.jpg" width="320" height="240" alt="Monkey Baker with a model Jupiter vehicle (NIX collection, NASA)"> /* resizing a 640x480px image using the CSS width and height properties */ .hidpi { width: 320px; height: 240px; } <img class="hidpi" src="miss-baker.jpg" alt=" Monkey Baker with a model Jupiter vehicle (NIX collection, NASA)">
或者,使图像流畅(max-width: 100%
;)并将其放入一个容器中,该容器不会变得比图像所需的宽度更大。虽然在普通分辨率的设备上你不会注意到差别,但是在高分辨率的设备上差别会很明显,如图图 9-32 所示:
图 9-32 :太空猴子贝克小姐的正常分辨率图像,以及使用上述技术之一的高分辨率图像。
那么,该怎么办呢?幸运的是,有创造力的人已经想出了巧妙的方法来解决这个问题。虽然没有一个是完美的,但至少有一些选择。其中包括:
[
adaptive-images.com/](http://adaptive-images.com/)
)data-*
和一个<noscript>
回退(当 JavaScript 被禁用时)。它是非常可配置的,也可选地提供延迟加载和带宽测试。(【http://j.mp/riloadr】30)另一种选择是只创建一个 HiDPI 图像,并使用 JPEG 压缩值 30 左右的文件对其进行大量压缩。当以正常尺寸观看时,这会产生可见的伪像,但是这些伪像被正常分辨率屏幕的浏览器大小调整和 HiDPI 屏幕的微小像素所掩盖。唯一的缺点是,你需要在 HiDPI 屏幕上创建图像,以获得最佳压缩效果。这极大地简化了事情,并且不需要 JavaScript,但是它不适用于必须使用 PNG 或 GIF 的图像,或者在压缩后图像对于移动设备来说仍然太大的情况。
在撰写本文时,这是一个正在积极发展的领域,所以像 Matt Wilcox 的综合概述“响应图像:问题是什么,我们如何解决它?”([
j.mp/responsive-img-problem](http://j.mp/responsive-img-problem)
31 )以及克里斯·科伊尔的《你应该使用哪种响应式图像解决方案([
j.mp/responsive-img-solution](http://j.mp/responsive-img-solution)
32 )可能很快就过时了。关注新闻的一个好地方是 Responsive Images 社区小组([www.w3.org/community/respimg/](http://www.w3.org/community/respimg/)
),这是 Responsive(j.mp/this-is-responsive
33),由布拉德·弗罗斯特(Brad Frost)提供的关于 responsive web 设计的精选模式、资源和新闻。
总之,虽然在撰写本文时,我们还不能对适应性和高分辨率图像提出可靠的建议,但学习如何压缩图像是永远不会过时的事情。
imageoptim.com
)trimage.org
)[www.ardfry.com/pngoutwin/](http://www.ardfry.com/pngoutwin/)
)或 Benjamin Hollis 的 PNGGauntlet ( [www.pnggauntlet.com](http://www.pnggauntlet.com)
)[www.smushit.com](http://www.smushit.com)
)、TinyPNG (tinypng.org)、JPEGMini ( jpegmini.com
)在线。pngmini.com
)或 Adobe Fireworks ( [www.adobe.com/products/fireworks.html](http://www.adobe.com/products/fireworks.html)
)等工具,将 PNG-24 图像转换为具有 alpha 透明度的 PNG-8 图像,该图像可在 IE6 中工作。30 [github.com/tubalmartin/riloadr](https://github.com/tubalmartin/riloadr)
31 dev.opera.com/articles/view/responsive-images-problem/
32
33
将高分辨率图像添加到设计中的另一种方法是使用基于矢量的图像,如可缩放矢量图形(SVG)和图标字体。这些将顺利缩放,比多张图像轻得多。Reda Lemeden 的“走向视网膜网络”很好地概述了这些和其他 HiDPI 技术(j.mp/sm-retina-web
coding . smashingmagazine . com/2012/08/20/forward-Retina-Web/)。
公平地说,我们用于布局的 CSS 2.1 工具并不是为我们正在做的布局而设计的。源顺序会限制我们的布局选项,水平对齐和垂直居中很困难,一般来说,创建健壮的布局比应该的要困难得多。然而,我们希望这将在不久的将来改变,因为几个布局模块目前正在开发中,大多数最初在一个或多个浏览器中实现。让我们来认识一下我们未来的布局霸主:
position
属性的附加值,包括长期以来一直追求的轻松垂直居中。break-*
及相关属性,被多个布局规范使用。我们将只简要介绍这些规范中的大部分,但我们希望您会对其潜力感到兴奋,并开始考虑如何使用它们。好了,我们走吧!
本规范涵盖了基于您的老朋友position
属性的定位方案。CSS3 版本引入了两个新的值:position: center;
最终提供了简单的水平和垂直居中,属性top
、right
、bottom
和left
作为对此的偏移量,而position: page;
创建了一个绝对定位的框,它相对于初始包含块定位,并且可以在分页媒体中分页。还有一组属性offset
,其作用类似于定位属性top
、right
等。,但依赖于语言—对多语言网站有用。遗憾的是,在撰写本文时,浏览器还不支持这些新功能。参见[
j.mp/css3-positioning](http://j.mp/css3-positioning)
34 的 CSS 定位布局模块三级规范。
这个“助手”规范定义了属性和规则,用于中断,或者当元素由于 CSS 布局而被一分为二时,元素的内容如何表现。这些属性用于设置或控制多栏布局中的栏间分隔符、CSS 区域中的区域以及 CSS 灵活框布局中的 flex 容器。它们与page-break-*
属性密切相关,我们将在 CSS 页面媒体模块级别 3 中提及。这些属性如下:
break-before
、break-after
、break-inside
:通过以下方式添加和控制分栏符:
break-before
和break-after
:写入时的值为auto
、always
、left
、right
、page
、column
、region
、avoid
、avoid-page
、avoid-column
和avoid-region
。break-inside
:写入时的值为auto
、avoid
、avoid-page
、avoid-column
和avoid-region
。orphans
和widows
:分别控制元素内容在元素中间断点前后必须出现的最少行数。默认是2
线。34
主要是您想要在一个内容块之前或之后触发一个中断,或者防止一个元素内部的中断,就像这样:
article {break-after: always;} h3 {break-before: always;} table {break-inside: avoid;} p { widows: 4; orphans: 3; }
在撰写本文时,浏览器对break-*
的支持是与使用它的布局模块绑定在一起的,并且作为多栏布局的一部分,有不同级别的支持,我们将在接下来讨论。目前 IE 8+和 Opera 9.2+支持widows
和orphans
。详见 http://j.mp/css3-break(dev.w3.org/csswg/css3-break/
)CSS 碎片模块三级。
多列布局模块允许您轻松地将报纸样式的列添加到元素中。column-width
和column-count
(带有简写属性columns
)的主要属性为元素的内容创建大小相等的列框。因为是 CSS,所以可以使用媒体查询来更改列数。
以下是多栏属性:
column-width
:每列的理想宽度。例如,{column-width: 15em;}
添加元素宽度(减去column-gap
宽度)允许的 15em 宽的列,然后相等地增加列宽以填充元素的宽度。百分比值不能用 ( 自动,长度)。
column-count
:列数。例如,{column-width: 4;}
在元素 ( auto ,integer)中创建四个大小相等的列。
columns
:设置column-width
和/或column-count
。当两个值都给定时,如果元素的宽度小于所需的宽度,则结果将如同使用了column-width
,如果宽度大于所需的宽度,则如同使用了column-count
…如果只有一个值,另一个被设置为默认值auto
。column-gap
:控制列间距。每列之间应用相同的间隙。默认的normal
一般是 1em ( 正常,长度)。
column-rule
:在列间增加一条线,取值与border
和outline
相同。您也可以使用属性column-rule-width
、column-rule-style
和column-rule-color
分别设置这三个值。嵌线宽度不影响列框的宽度。column-span
:允许一个块级元素跨越值为all
的所有列,这也作为一个列分隔符 ( none ,all)。
break-before
、break-after
、break-inside
:添加和控制分栏符。虽然在撰写本文时,这些属性是用多列布局模块规范中的下列值定义的,但我们预计它们将在不久的将来被 CSS 碎片模块定义所取代:break-before
和break-after
:可能的值有auto
、always
、avoid
、left
、right
、page
、column
、avoid-page
、avoid-column
。break-inside
:可能的值有auto
、avoid
、avoid-page
和avoid-column
。column-fill
:当height
大于auto
时,控制内容如何跨列分布。默认的balance
试图使所有列高度相同,而auto
一次完全填充一列 ( 平衡,自动)。
下面是一些使用多栏布局的基本示例。首先,column-width
建议每一列的期望列宽。如果一列有足够的空间,这将作为最小列宽。的列数和的列宽都随着元素的宽度而变化,以确保最后一列的边缘接触到元素的右边缘。列的可用宽度是元素的宽度减去column-gap
宽度。
例如,让我们将column-width: 10em;
应用于一个 42em 宽的段落,如图 9-33 中的。虽然这是我们可以愉快地留给浏览器的事情,但是我们可以使用这个伪算法来计算列数:
max(1, floor((available-width + column-gap) / (column-width + column-gap)))
默认为column-gap: 1em;
,即max(1, floor((42em + 1em) / (10em + 1em)))
,计算到max(1, floor(3.90909))
,即三列。然后,我们可以使用伪算法计算出列宽:
((available-width + column-gap) / number-of-columns) - column-gap
在本例中是((42em + 1em) / 3) - 1em
,这给了我们三个 13.333em 宽的列。
图 9-33 将column-width: 10em;
应用于 42em 宽的段落,前后。列的宽度最终为 13.333em,以填充元素的宽度。
目前column-width
(和column-gap
)不允许百分比。如果不想用带column-width
的长度单位,可以用column-count
代替,如图图 9-34 。这相当于百分比,因为column-count
给了我们固定的列数,而的列宽随着元素的宽度而变化。
图 9-34**。**当元素的宽度只有 20em 时column-width: 10em;
和column-count: 3;
的比较(这对于两个 10em 的列加上一个列间隙来说不够宽)。当column-width
适应时,column-count
保持列框的数量,即使它们变得非常窄。
速记属性columns
可以设置列宽和列数中的一个或两个。当只给出一个值时,另一个就是默认的auto
。当两个值都给定时,如果元素的宽度小于要求的宽度,结果就像使用了column-width
,如果宽度大于要求的宽度,结果就像使用了column-count
。值的顺序并不重要。我们倾向于使用column-width
或column-count
,我们发现column-width
更安全、更灵活。
另外两个重要的属性是column-gap
和column-rule
,允许您指定列之间的间隙(或装订线),以及在该间隙的中心绘制的标尺。column-gap
占用空间,column-rule
不占用空间,它们适用于所有列,如图图 9-35 所示。
**图 9-35。**具有大column-gap
和column-rule
的多列元素。与图 9-33 中的相比,由于column-gap
更窄,图 9-33 只有七行高。
表 9-3 显示了 Mozilla、Safari 和 Chrome 对多栏布局属性的基本支持已经有一段时间了。最近,Opera 11.10 和 Internet Explorer 10 中增加了全面支持。
1 在写的时候,Opera 把两个值都和column-width
一样的columns
。
2 WebKit 浏览器(Safari 和 Chrome)和 IE 不显示比column-gap
宽的column-rule
。Firefox 和 Opera 在内容下面显示规则。
3 WebKit 初步支持break-before
、break-after
、break-inside
,拥有专有属性-webkit-column-break-before
、-webkit-column-break-after
、-webkit-column-break-inside
。-webkit-column-break-before
和-webkit-column-break-after
支持值always
、left
、right
、、auto
,-webkit-column-break-inside
支持值avoid
、auto
。不幸的是,在撰写本文时-webkit-column-break-inside: avoid;
还没有进入 Safari 一个解决方法是使用display: inline-block;
。
除了上面提到的几点,还有三个重要的问题:
column-rule
)。然而,Firefox 在下一列的内容后面显示这个溢出的内容。通过使用流体图像来避免这种情况(例如img {max-width: 100%;}
)。在撰写本文时,Safari 6 改为在column-gap
的边缘裁剪(虽然我们认为这样看起来更好,但这不符合规范)。column-count
时)。必须向上滚动才能到达下一列的顶部,这几乎与水平滚动阅读每一行一样令人讨厌。小心在移动设备上测试,避免在大块内容上使用多栏布局。如您所料,对于不支持这些属性的浏览器,元素的内容正常显示在一列中。虽然这可能会导致很长的线路长度(小心!),内容仍然可读和可访问,使得多栏布局在更广泛的浏览器支持之前具有潜在的可用性。如果你已经为每一列的内容准备了包装器(比如你想分成三列的三个段落),那么在 Modernizr 的帮助下使用.csscolumns/.no-csscolumns
添加回退样式真的很容易。虽然对更高级属性的不稳定支持意味着它还不能胜任繁重的布局任务,但可以考虑对小型渐进式增强任务使用多列布局——只要记住避免垂直滚动并进行彻底的测试!
最后一个警告——虽然我们将多栏布局描述为一种“添加报纸风格的栏目”的方式,但是请记住网络是而不是新闻纸。确保你的使用适合你的内容,而不仅仅是模仿报纸的风格。
[
dev.w3.org/csswg/css3-multicol/](http://dev.w3.org/csswg/css3-multicol/)
)[
webdesign.tutsplus.com/tutorials/htmlcss-tutorials/an-introduction-to-the-css3-multiple-column-layout-module/](http://webdesign.tutsplus.com/tutorials/htmlcss-tutorials/an-introduction-to-the-css3-multiple-column-layout-module/)
)[
developer.mozilla.org/en/CSS/Using_CSS_multi-column_layouts](https://developer.mozilla.org/en/CSS/Using_CSS_multi-column_layouts)
)[
zomigi.com/blog/deal-breaker-problems-with-css3-multi-columns/](http://zomigi.com/blog/deal-breaker-problems-with-css3-multi-columns/)
)中遇到它[
ie.microsoft.com/testdrive/Graphics/hands-on-css3/hands-on_multi-column.htm](http://ie.microsoft.com/testdrive/Graphics/hands-on-css3/hands-on_multi-column.htm)
)大多数桌面出版(DTP)程序允许您将一系列文本框链接在一起,因此它们可以作为一个单独的内容框。如果第一个框中显示的内容太多,内容将自动按顺序溢出到后续的框中(参见图 9-36 )。
图 9-36 。桌面出版程序中用连接线链接的两个文本框。文本从一个框流向下一个框。
CSS 区域做同样的事情——使用flow-into
属性将一个元素分配给一个名为 flow 的*。然后,这个元素的内容将被注入一个区域列表(一个区域链)中,该列表被定义为具有相同名称的flow-from
属性的选择器,按照选择器被列出的顺序。*
article { flow-into: article-chain; } /* IDs of regions in flow order: either existing elements or pseudo-elements to be created */ #lede, #part1, #part2, #part3 { flow-from: article-chain;
}
/* styles for positioning these elements */ …
CSS 区域仅定义命名流的内容如何流经区域链。然后可以使用其他布局模块来定位这些区域,包括作为多栏布局、灵活框布局或网格布局的一部分。区域可以是空元素的支架,例如网格布局的子元素,但不是必须如此——伪元素,例如::before
和::after
或任何其他可以被样式化的元素都可以成为区域。非官方的 CSS 分页模板模块 Level 3 规范提出了一种为基于页面的布局定义 DTP 风格的“主模板”的方法,其@slot
规则也可以定义区域,而不需要空元素的框架。
您可以使用以下属性控制区域中内容的显示:
break-before
、break-after
和break-inside
:设置或避免区域链中区域之间的中断,如 CSS 分段模块级别 3 中所定义。region-overflow
:与overflow
属性一起控制如何处理最后一个区域的溢出内容。@region
规则:对特定区域的内容应用框模型、排版和颜色样式。伪元素::before
和::after
也可以用在每个区域上,并且每个区域创建新的块格式化上下文和新的堆叠上下文。
在撰写本文时,Chrome 19+,Safari 5.2 和 IE 10 中有部分供应商前缀支持。WebKit 使用-webkit-flow
而不是flow-into
,使用-webkit-from-flow
而不是flow-from
,并且在编写时 Chrome 需要启动一个启用标志(或者在 Canary 的chrome://flags/
中启用“实验 WebKit 特性”标志)。CSS 区域也可以用 Modernizr 2.6+ ( .css-regions
)检测。最后,CSS 分页模板模块级别 3 在 WebKit nightlies 中也有初始的、厂商前缀的支持。
[
dev.w3.org/csswg/css3-regions/](http://dev.w3.org/csswg/css3-regions/)
)[
dev.w3.org/csswg/css3-page-template/](http://dev.w3.org/csswg/css3-page-template/)
)[
caniuse.com/#feat=css-regions](http://caniuse.com/#feat=css-regions)
)[
html.adobe.com/webstandards/cssregions/](http://html.adobe.com/webstandards/cssregions/)
)的 CSS 区域信息,包括:[
adobe.github.com/web-platform/samples/css-regions/](http://adobe.github.com/web-platform/samples/css-regions/)
)[
adobe.github.com/web-platform/utilities/css-pagination-template/](http://adobe.github.com/web-platform/utilities/css-pagination-template/)
)浮动的一个有趣的方面是非浮动的块级框忽略它们的方式,但是那些框的行框环绕它们。该规范的 CSS 排除部分将影响内联内容的能力扩展到任何元素,使用任何定位方案。您可以使文本在形状内部或周围流动(CSS 形状部分),并在单个元素的内部和外部使用不同的形状。这使得杂志技术像围绕图像或内部形状流动的文本很容易实现,如图图 9-37 所示。最后,从矩形的暴政中获得自由!
图 9-37 。文本环绕左侧的图像,并位于右侧匹配的半圆形状内。
您可以使用wrap-flow
属性控制块级元素对内联内容的影响。数值为auto
(默认)both``start``end``minimum``maximum``clear
,提供多种包裹效果。具有非auto
值的元素影响同一包含块中的内联内容,并建立新的块格式化上下文。您可以使用属性wrap-margin
、wrap-padding
、简写wrap
(包含前面的三个属性)和wrap-through
来控制排除。
CSS 形状使用shape-outside
和shape-inside
来声明。虽然内部形状可以应用于任何块级元素,但外部形状只有在应用于排除或浮动时才起作用。形状可以通过基本的 SVG 语法(rectangle()
、circle()
、ellipse()
和polygon()
)直接在 CSS 中定义,通过引用<svg>
块中的 SVG 形状,通过具有透明度的图像(包含不透明度大于shape-image-threshold
值的像素的路径,默认为 0.5),或者通过使用outside-shape
(与为shape-outside
定义的形状相同)为shape-inside
定义。
通过结合排除和形状,各种令人兴奋的布局的可能性打开。然而,如果你的印刷灵感被冲昏了头脑,请记住杂志读者不能调整杂志版面的大小——确保你的使用是“网络的”,并将优雅地适应。
在撰写本文时,IE 10 中有初始的供应商前缀支持(最初称之为“定位浮动”),WebKit 中有初步支持(在 Canary 中启用chrome://flags/
中的“实验 WebKit 特性”标志),Adobe 也发布了一个基于 WebKit 的演示,尽管这使用了比当前规范更早的语法。由于一些浏览器返回误报,Modernizr 在编写时无法检测排除。
[
dev.w3.org/csswg/css3-exclusions/](http://dev.w3.org/csswg/css3-exclusions/)
)galjot.si/css-exclusions
)撰写的介绍性文章《CSS 排除》[
html.adobe.com/webstandards/cssexclusions/](http://html.adobe.com/webstandards/cssexclusions/)
)的 CSS 排除和形状信息,包括:
[
adobe.github.com/web-platform/samples/css-exclusions/](http://adobe.github.com/web-platform/samples/css-exclusions/)
):示例图像信息丰富,但是在撰写本文时,WebKit 演示和代码已经过时[
msdn.microsoft.com/en-us/library/ie/hh673558(v=vs.85).aspx](http://msdn.microsoft.com/en-us/library/ie/hh673558(v=vs.85).aspx)
)该规范详细说明了分页媒体格式化模型,即打印网页时使用的基于页面框的模型。这可以使用@page
规则(以及页面周围区域的相关规则,如@top-center
和@bottom-right-corner
)以及:left
、:right
和:first
伪类来设计。这些可以在@media
规则中使用,规范还定义了与页面相关的属性,包括:
page-break-*
:这些是 CSS 片段模块中break-*
属性的前身(用于多栏布局、CSS 区域、CSS Flexbox 等。),并以同样的方式工作。size
:指定页面尺寸(普通纸张尺寸,或先宽后高),如有必要,指定方向,如size: A4 portrait;
或size: 6in 4in;
。page
:创建命名的@page
规则,然后使用page
属性来控制元素理想出现在什么样的页面上。例如,下面的 CSS 指定纸张大小和方向,以及左右页的页边距:
@page { size: A5 portrait; } /* channeling Müller-Brockmann */ @page :left { margin: 15mm 10mm 30mm 20mm; } @page :right { margin: 15mm 20mm 30mm 10mm; }
这些规则也可以嵌套在@media 规则中,例如:
@media print and (width: 210mm) and (height: 297mm) { @page { /* rules for A4 paper */ } } @media print and (width: 8.5in) and (height: 11in) { @page { /* rules for US Letter paper */ } }
CSS 片段模块中的orphans
和widows
有助于控制在带有行框的元素中间出现分页符时出现的印刷杂散行。此外,CSS 图像值和替换内容模块级别 3 规范中的几个相关属性object-fit
和object-position
控制替换内容(如<img>
、<video>
、<object>
和<svg>
)如何在其框中显示和定位:
object-fit
:如果元素的尺寸或长宽比不同,您可以调整元素框内替换内容的大小。例如,这可让您选择对宽屏影片进行裁剪或信箱操作,非常适合处理各种内容的模板。object-position
:这和background-position
一样,允许你在元素框的框架中偏移元素的内容。在撰写本文时,这些属性中的浏览器支持差别很大。比如page-break-before
在 Firefox 中被普遍支持而page-break-inside
不被支持,在 IE 8+和 Opera 9.2+中支持widows
和orphans
,只有 Opera 12 的一个定制版支持object-fit
和object-position
。
[
dev.w3.org/csswg/css3-page/](http://dev.w3.org/csswg/css3-page/)
)[
dev.w3.org/csswg/css3-img/#sizing](http://dev.w3.org/csswg/css3-img/#sizing)
)[
caniuse.com/#feat=object-fit](http://caniuse.com/#feat=object-fit)
)[
dev.opera.com/articles/view/css3-object-fit-object-position/](http://dev.opera.com/articles/view/css3-object-fit-object-position/)
)该规范为生成的内容提供了样式,如标题、脚注和交叉引用。它还包括属性的四个新值:overflow-style
、paged-x
、paged-y
、paged-x-controls
和paged-y-controls
。这些给出了一个基于页面的界面,有或没有相关的导航控件。这些样式非常适合与 CSS 分页媒体和多栏布局规范搭配使用。
如果你想要一个章节号和基于标题的运行标题,你可以先把章节的<h1>
内容分配给一个名为字符串的*,并把它绑定到一个计数器😗
h1 { string-set: chapter-title content-element; counter-increment: chapter; }
在这个例子中,我们将<h1>
的content-element
内容(元素的内容,不包括任何:before
或:after
内容)添加到字符串“chapter-title”中。我们还在每次遇到<h1>
时增加一个名为“章节”的计数器。使用 CSS 分页媒体模块中的样式,如@page
规则,您可以调用使用string()
设置的命名值和使用counter()
设置的当前计数器,使用content
属性显示它们,并使用:left
和:right
伪类为左右页面适当地定位它们。继续上面的代码:
title { string-set: book-title contents; } @page :left { @top-center { content: string(book-title); } } @page :right { @top-center { content: "Chapter " counter(chapter) ": " string(chapter-title); } }
要为电子书使用分页用户界面,您可以使用以下 CSS:
@media paged { html { height: 100%; overflow: paged-x-controls; } }
height: 100%;
限制了视窗的高度,额外的内容溢出到右边,可以通过默认的浏览器页面导航部件访问。该规范还涵盖了通过@navigation
的基于页面的导航,基于页面和基于行的伪元素,以及电子书风格的翻页过渡。
在撰写本文时,Opera 12(j.mp/opera-gcpm
people.opera.com/howcome/2011/reader/
)有一个定制版本,支持初始版本和厂商前缀。
[
dev.w3.org/csswg/css3-gcpm/](http://dev.w3.org/csswg/css3-gcpm/)
)[
people.opera.com/howcome/2011/reader/](http://people.opera.com/howcome/2011/reader/)
),演示了该模块的属性。它包括 Opera 12 定制版本的链接。灵活盒子模型(或“Flexbox”)起源于 Firefox 用户界面的布局方式。该规范的早期版本(使用display: box;
)在 Firefox 和 WebKit 浏览器上获得了尚可的支持,但各种问题导致它被“送回公式”在一个尴尬的中间阶段(使用display: flexbox;
)之后,它重新出现,成为大大改进的新 Flexbox(使用display: flex;
)。Flexbox 规范定义了“为界面设计优化的 CSS 盒子模型”,具有水平或垂直布局和排序盒子的属性,以及对盒子如何对齐以及它们如何相对于可用空间扩展和收缩(“flex”)的深度控制。
要使用 Flexbox,首先使用display: flex;
(或display: inline-flex;
用于内联变体)将一个元素制作成一个 flex 容器。然后,该元素建立一个新的 flex 格式上下文(类似于块格式上下文,但使用 flex 布局),它形成一个包含块,并防止边距折叠和浮动元素重叠。flex 容器的子元素成为 flex 项目。flex 容器不能使用多栏布局,属性float
、clear
和vertical-align
不影响 flex 项目。
图 9-38 显示了用于水平和垂直语言的示例单线柔性盒。请注意,描述 flexbox 各个方面的术语是独立于语言的,并且适用于该语言的书写模式。
图 9-38 。带有 flex 项目的单行 flex 容器,显示英语和繁体日语的主轴和横轴如何根据它们不同的writing-mode
值而变化。
以图 9-38 为指导,让我们来看看应用于 flex 容器的属性:
flex-direction
:控制伸缩项的排列方向,取值row
(默认)row-reverse``column``column-reverse
,row
表示主轴与inline
同向,column
与block
同向。这些都是基于当前语言的书写方向,所以默认的row
在英语中的意思是从左到右,在传统的日语示例中图 9-38 row
是从上到下。flex-wrap
: Flex 容器可以有单行的 Flex 项目(默认为nowrap
),或者使用wrap
或wrap-reverse
包含多行。多条线以wrap
自始至终叠加,或反方向叠加wrap-reverse
。flex-flow
速记属性:它接受flex-direction
和/或flex-wrap
值,如果没有声明,则使用默认值。justify-content
:控制伸缩项目如何在主轴方向排成一行。它可能会让你想起第十章中提到的text-align
内联块元素。这些值是默认的flex-start
加上flex-end
、center
、space-between
和space-around
。align-items
:控制 flex 行中的 flex 项如何在横轴方向对齐,可能会提醒您vertical-align
属性,也在第十章中介绍。这些值是flex-start
、flex-end
、center
、baseline
和默认的stretch
,这使得所有 flex 项目具有相同的高度(对于基于行的 Flexbox)。align-content
:控制多行柔性容器中各行在横轴方向的对齐。数值为flex-start
、flex-end
、center
、space-between
、space-around
,默认为stretch
。应用于弹性项目的属性如下:
order
:该属性允许您对弹性项目重新排序,并接受数值。项目从负到正排序,没有显式顺序声明的项目使用默认值 0。具有相同值的弹性项目按来源顺序显示。该属性只应用于可视(非逻辑)重新排序,不会改变语音阅读器中的顺序。flex-grow
和flex-shrink
:这两个属性分别控制在有额外空间的情况下是否允许伸缩项增长,或者在没有足够空间的情况下允许伸缩项收缩。对于同一 flex 线上的 flex 项目,它们共同决定了 flex 增长比率和 flex 收缩比率,它们决定了每个 flex 项目增长或收缩的比例。这些属性采用 0 和正数,初始值为flex-grow: 1;
和flex-shrink: 1;.
,这意味着 flex 项目将默认为相同的宽度(对于水平流轴),如果没有足够的空间,则扩展或收缩。flex-basis
:这指定了在flex-grow
或flex-shrink
调整其大小以适应容器之前,伸缩项的初始大小。取值与width
相同(如长度和百分比),默认为auto
,视情况使用项目的width
或height
(主轴方向的尺寸)。当与 flex 一起使用时,这提供了“相对 flex”。除了auto
之外的值意味着该项目的width
或height
将被忽略。设置flex-basis: 0%;
或flex-basis: 0;
会将伸缩项目的主轴尺寸设置为 0,这意味着其大小将取决于flex-grow
或flex-shrink
,从而给出“绝对伸缩”。如果使用值auto
,或接近(或等于)0
的值,确保您设置了适当的width
或height
。flex-grow
、flex-shrink
和/或flex-basis
。如果没有定义任何值,其初始值就是各个属性值。如果仅设置flex-grow
和/或flex-shrink
值,flex-basis
将为 0,给出“绝对弹性”如果你只设置了flex-basis
,你会得到“相对弹性”,而flex-grow
和flex-shrink
使用默认的 1。注意,flex
属性中flex-basis
的零值需要一个单位,例如 0px,以避免与增长和收缩值混淆。flex
也有一些有用的简写值:
flex: initial;
或flex: 0 auto;
:伸缩项将使用其width
和height
属性,不会扩展,但会在必要时收缩。这与flex: 0 1 auto;
的初始值相同,在使用 Flexbox 的对齐属性或结合自动边距时非常有用。flex: none;
:类似于initial
,这将阻止伸缩项伸缩,即使它们的width
或height
导致它们溢出(相当于flex: 0 0 auto;
)。flex: auto;
:从其声明的维度(或内容维度,如果使用例如width: auto;
)开始,flex 项目将增长或收缩以填充空间。如果一个 flex 行中的所有 flex 项都使用auto
,任何多余的空间将使用“相对 flex”(相当于flex: 1 1 auto;
)平均分配。flex: <positive-number>
:这使得一个 flex 项具有灵活性,同时将flex-basis
设置为 0px(等于flex: <positive-number> 1 0px;
)。这使用“绝对伸缩”,所以如果一行中的所有伸缩项都使用这种风格的伸缩(或使用flex-basis: 0%;
或flex-basis: 0;
)。那么它们的尺寸将与它们的挠曲比成比例,不受它们固有尺寸的影响。align-self
:这在横轴方向上对齐一个 flex 项目,并且是 flex 容器的align-items
属性的 flex 项目等价物。它采用相同的值(flex-start
、flex-end
、center
、baseline
和stretch
),加上默认的auto
,后者继承了align-items
的值。为了解释相对和绝对伸缩之间的区别,让我们通过将flex
预设值应用到图 9-39 中的简单导航栏来比较它们。我们忽略了 flex:initial;因为它看起来与 flex: none 相同;有多余空间的时候。
<style> .nav { display: flex; /* Establish a flex container */ list-style-type: none; } /* First image: Flexbox with no flex */ .nav li { flex: none; /* equivalent to flex: 0 0 auto; */ } /* Second image: Relative flex */ .nav li { flex: auto; /* equivalent to flex: 1 1 auto; */ } /* Third image: Absolute flex */ .nav li { flex: 1; /* equivalent to flex: 1 1 0px; */ }
`/* Fourth image: Differing flex values /
.nav li {
flex: 1;
}
.nav li:nth-child(2) {
flex: 2; / equivalent to flex: 2 1 0px; /
}
/ Increase click target area */
.nav a {
display: block;
width: 100%;
height: 100%;
}
…
图 9-39 。一个简单的导航栏,显示如何使用相对伸缩(将空间添加到内容的宽度)和绝对伸缩(忽略内容的初始宽度添加空间)来分配额外的空间。
如果没有足够的空间,伸缩值(特别是flex-shrink
)将控制每个伸缩项如何(或是否)收缩以适应。正如你在第一张图中所看到的,仅仅使用没有 flex 的 Flexbox 就使得块级元素相互堆叠,就好像它们是inline-block
。
也许 Flexbox 最好的能力是它给我们的对 flex 项目的对齐和排序的深度控制。首先,如果 flex 项目的容器有额外的空间,您可以通过使用auto
边距来对齐没有 flex 的 flex 项目(特别是那些带有flex-grow: 0;
的项目)——任何额外的空间都将平均分配给轴方向上具有值auto
的边距。注意,这阻止了与 Flexbox 属性justify-content
的对齐,因为在 flex 被计算之后,但在 Flexbox 对齐发生之前,自动边距吸收了任何空闲空间。
让我们使用图 9-39 的第一幅图像中的相同导航按钮(flex:无;)演示自动边缘对齐,在图 9-40 中。
图 9-40 。在伸缩项目上,任何额外的空间都会与主轴方向上的任何自动边距平均分割。
让我们将其与 Flexbox 的justify-content
属性进行比较,该属性允许我们通过将其每个值应用到图 9-41 中的相同示例导航按钮,来快速应用几个常见对齐中的一个。
图 9-41 。将justify-content
值应用到 flex 容器。
除了在主轴方向对齐内容,Flexbox 还为我们提供了在横轴方向对齐的强大工具。属性align-items
和align-self
取相同的值,并允许我们分别对齐所有 flex 项(通过应用到 flex 容器)或单个 flex 项。让我们比较一下图 9-42 中align-items
的可能值。
图 9-42**。将align-items
值应用到 flex 容器。请注意,对于水平行,默认的stretch
会自动创建高度相等的伸缩项,center
让我们可以轻松地垂直居中,baseline
会对齐行中每个伸缩项的第一条基线。**
**结合align-content
在横轴方向上对齐多线 flexbox 的 flex 行,Flexbox 真正覆盖了您对 flex 项目对齐和分配的精细控制。
这一切听起来很完美,但我们建议在考虑 Flexbox 的页面布局时要谨慎。虽然您可以使用order
属性对一行中的 flex 项目进行重新排序,但是复杂的页面布局需要额外的包装器元素,并且布局重排通常需要更改 HTML。Flexbox 的优势在于它对对齐和分配界面或页面的部分的惊人控制,它并不理想地适合页面布局本身。不幸的是,虽然 CSS Grid Layout 完美地补充了这一点,CSS Grid Layout 专门用于整个页面布局,这也是我们接下来将讨论的内容,但我们可能会首先提供可用的 Flexbox 支持,因此尽管如此,您可能会发现自己正在努力处理基于 Flexbox 的页面布局。
在撰写本文时,Chrome 21 和 Firefox 18 已经对当前灵活的框布局模块提供了初始的、供应商前缀的支持,而 Opera 12.10 则提供了无前缀的支持。然而,在撰写本文时,该规范还是一个候选推荐标准(W3C 称之为“基本完成”),所有浏览器都支持某种版本的 Flexbox,因此我们预计对新 Flexbox 的支持以及非修复将会相对较快地出现。虽然 Firefox 和 WebKit 也支持该规范的第一个版本(即中间的第二个版本),但使用这些早期规范有几个重大问题(参考:j.mp/old-flexbox
奥利. jp/2011/css3-flexbox/),我们建议坚持使用display: flex;
。Modernizr 检测 Flexbox 的当前版本(display: flex;
)和原始版本(display: box;
)。
[
dev.w3.org/csswg/css3-flexbox/](http://dev.w3.org/csswg/css3-flexbox/)
)[
developer.mozilla.org/en-US/docs/CSS/Using_CSS_flexible_boxes](https://developer.mozilla.org/en-US/docs/CSS/Using_CSS_flexible_boxes)
)[
demo.agektmr.com/flexbox/](http://demo.agektmr.com/flexbox/)
)[
caniuse.com/#feat=flexbox](http://caniuse.com/#feat=flexbox)
)网格布局正在形成我们一直在等待的“一个真正的布局”方法,一个值得真爱的方法。它基于一个网格(呜!),并且与源顺序没有联系,允许使用表格布局或其他 CSS 2.1 布局方案无法实现的布局。
网格由水平和垂直的网格线组成,包围网格域。我们可以通过创建网格线(可以分配角色)、网格字段或两者来设置网格,任何未定义但需要的线或字段都将被自动添加。网格的块级、替换和内嵌块子元素是网格框,可以基于命名网格字段、网格线或命名网格线角色进行定位。您可以将网格框跨越多行,将内容与网格线对齐,重叠网格框,甚至将它们分配到同一位置,并控制它们的堆叠顺序。这些术语如图 9-43 所示。
图 9-43 。一个图表显示了写作时的网格布局概念。
您可以用几种方式定义网格:
grid-lines-horizontal
和grid-lines-vertical
属性grid-fields
属性制作一个 ASCII 艺术表示网格线的位置可以使用
width
表示行,height
表示列)fr
单位)max-content
)或最小大小(min-content
)minmax
函数(minmax (*min*, *max*)
),可以使用任何前述值类型的最小值和最大值auto
,相当于minmax(min-content, max-content)
请注意,如果minmax
函数的“最小含量”值使用分数单位,它将被视为 0 px。
分数(fr)是一个新的单位,表示从容器的宽度或高度中减去显式长度后剩余空间的比例。然后,任何额外的空间在具有与每个小数值成比例的小数值的字段之间分割,类似于flex-grow
值如何控制灵活框模块中额外空间的相对比例。当未定义可用空间时,使用小数单位计算每个字段的最大内容大小,最大的内容大小用作 1fr 的基础,因此保持相对比例。确保在网格元素上使用宽度(比如 100%),以避免水平滚动
在警告了你 Flexbox 的页面布局,并赞美了网格布局的页面布局能力之后,我们不得不遗憾地回到现实。根据在 Internet Explorer 10 中最初实现的反馈,在编写本书时,网格布局规范正在进行全面检查,以使其更适合使用网格线的图形设计影响的布局。虽然 Grid Layout 正在变得非常灵活和强大——非常适合创建一个整体页面布局,然后通过媒体查询重新安排它——但在撰写本文时,它的当前状态意味着我们在几年内也不会使用它。从好的方面来看,这个规范是几个早期布局规范的最佳想法的结合,正在积极地工作,所有的浏览器都计划在它稳定后实现它。
我们急切地等待着这个规范(或未来的变体)最终被广泛传播的那一天。我们也希望最终能看到体面的基于图形用户界面的网页设计工具。与此同时,CSS 2.1 布局技术(在 Flexbox 的帮助下逐步增强,直到它足够广泛地独立存在)将不得不做。
[
dev.w3.org/csswg/css3-grid-layout/](http://dev.w3.org/csswg/css3-grid-layout/)
)[
caniuse.com/#feat=css-grid](http://caniuse.com/#feat=css-grid)
)让我们再次强调,除了多栏布局之外,这些规范中没有一个能在几年内支持浏览器在生产中使用。其实很多还在编辑中。然而,这意味着这是一个很好的时间来使用它们,思考它们在未来如何有用,当然也可以向 CSS 工作组提供反馈。
显然,这些规范中的一些不能在同一个元素上使用,例如灵活的盒子布局和网格布局。但是,您可以将网格框转换为 flex 容器,将 flex 项目转换为网格容器。
在本章中,我们已经讨论了的很多内容,从盒子模型和各种盒子的基础开始,然后继续讨论基于 CSS 2.1 的position
属性、display: inline;
、display: inline-block;
和display: table;
布局的可能性。我们讨论了媒体查询以及如何将它们与适应性布局一起使用来实现响应性 web 设计,还讨论了如何处理高分辨率显示。最后,我们谈到了一些即将到来的 CSS3 布局规范,令人沮丧的是,在撰写本文时,几乎所有的规范都遥不可及,但却有望实现简单的 CSS 布局。
事情的当前状态令人沮丧——实际上有浏览器支持的 CSS 对于页面布局来说动力不足,并且经常有重大缺陷。提供真正布局工具的规范仍在编写中,这意味着它们可能还需要几年才能得到广泛的浏览器支持。考虑到布局的重要性(这不是我们可以轻易增加的渐进式改进),广泛的浏览器支持是在除了例外情况之外的所有情况下使用的先决条件。我们可能会很幸运,得到 polyfills 或其他工具,使维护两种布局成为可能,但在短期内,看起来我们将不得不忍受我们现有的 CSS 2.1 布局方法。
然而,这里有一缕阳光:随着 2012 年 Internet Explorer 10 的推出,所有主流浏览器现在都可以自动更新了。这意味着不再等待 IE6 消失的 10 多年,新的规范将在大约 3-4 年的时间内被广泛采用(并成为可用的)。现在这算不上什么安慰,但它将改变游戏规则。
我们将通过回到网页设计的基本哲学来结束这一章:适应。为变化做准备,优雅地处理它,设计成防弹的。通过对未来友好,你的布局(和你的网站)将避免被新的设备和技术弄得措手不及。记住,网络不是印刷品,这是它的优势之一。
www.flexiblewebbook.com/
)的一本书smacss.com/
)的书《CSS 的可扩展和模块化架构》www.abookapart.com/products/responsive-web-design
)写的一本书《响应式网页设计》retinafy.me/
)的书《Retinafy 你的网站和应用》futurefriend.ly/
[
html5please.com/](http://html5please.com/)
)[
paulirish.com/2012/box-sizing-border-box-ftw/](http://paulirish.com/2012/box-sizing-border-box-ftw/)
)oocss.org/
)[www.sitepoint.com/give-floats-the-flick-in-css-layouts/](http://www.sitepoint.com/give-floats-the-flick-in-css-layouts/)
)display: inline-block;
和text-align: justify;
创建一个健壮的网格。([www.jonathantneal.com/blog/simple-stacks-and-panels/](http://www.jonathantneal.com/blog/simple-stacks-and-panels/)
)[www.digital-web.com/articles/everything_you_know_about_CSS_Is_wrong/](http://www.digital-web.com/articles/everything_you_know_about_CSS_Is_wrong/)
)[
zomigi.com/blog/examples-of-flexible-layouts-with-css3-media-queries/](http://zomigi.com/blog/examples-of-flexible-layouts-with-css3-media-queries/)
)的“CSS3 媒体查询的灵活布局示例”[
bradfrost.github.com/this-is-responsive/resources.html](http://bradfrost.github.com/this-is-responsive/resources.html)
)撰写的关于响应式网页设计的资源集合[
docs.google.com/spreadsheet/ccc?key=0Al0lI17fOl9DdDgxTFVoRzFpV3VCdHk2NTBmdVI2OXc#gid=0](https://docs.google.com/spreadsheet/ccc?key=0Al0lI17fOl9DdDgxTFVoRzFpV3VCdHk2NTBmdVI2OXc#gid=0)
)编辑的反应图像图表[
dev.opera.com/articles/view/love-your-devices-adaptive-web-design-with-media-queries-viewport-and-more/](http://dev.opera.com/articles/view/love-your-devices-adaptive-web-design-with-media-queries-viewport-and-more/)
)target-densitydpi
的危险。([
sunpig.com/martin/archives/2012/03/18/goldilocks-and-the-three-device-pixel-ratios.html](http://sunpig.com/martin/archives/2012/03/18/goldilocks-and-the-three-device-pixel-ratios.html)
)html5boilerplate.com/
)[
dev.w3.org/csswg/css3-values/](http://dev.w3.org/csswg/css3-values/)
,[
dev.w3.org/csswg/css3-values/#absolute-lengths](http://dev.w3.org/csswg/css3-values/#absolute-lengths)
)[www.w3.org/TR/CSS2/box.html](http://www.w3.org/TR/CSS2/box.html)
)更新版本,CSS 3 基本盒模型更加详细,但在撰写本文时仍在进行中。([
dev.w3.org/csswg/css3-box/](http://dev.w3.org/csswg/css3-box/)
)[
dev.w3.org/csswg/css3-ui/](http://dev.w3.org/csswg/css3-ui/)
)position
属性的规范,包括有用的新值center
和page
、offset
组属性以及详细的定位算法。([
dev.w3.org/csswg/css3-positioning](http://dev.w3.org/csswg/css3-positioning)
)[
dev.w3.org/csswg/css3-mediaqueries/](http://dev.w3.org/csswg/css3-mediaqueries/)
)[www.w3.org/TR/CSS2/tables.html](http://www.w3.org/TR/CSS2/tables.html)
)<meta viewport="…">
元素实现为@viewport
。([
dev.w3.org/csswg/css-device-adapt/](http://dev.w3.org/csswg/css-device-adapt/)
)[
dev.w3.org/csswg/css3-break/](http://dev.w3.org/csswg/css3-break/)
)[
dev.w3.org/csswg/css3-multicol/](http://dev.w3.org/csswg/css3-multicol/)
)[
dev.w3.org/csswg/css3-regions/](http://dev.w3.org/csswg/css3-regions/)
)[
dev.w3.org/csswg/css3-page-template/](http://dev.w3.org/csswg/css3-page-template/)
)[
dev.w3.org/csswg/css3-exclusions/](http://dev.w3.org/csswg/css3-exclusions/)
)[
dev.w3.org/csswg/css3-page/](http://dev.w3.org/csswg/css3-page/)
)[
dev.w3.org/csswg/css3-img/](http://dev.w3.org/csswg/css3-img/)
)[
dev.w3.org/csswg/css3-gcpm/](http://dev.w3.org/csswg/css3-gcpm/)
)[
dev.w3.org/csswg/css3-flexbox/](http://dev.w3.org/csswg/css3-flexbox/)
)[
dev.w3.org/csswg/css3-grid-layout/)](http://dev.w3.org/csswg/css3-grid-layout/))
我们希望您已经尝试了 CSS 2.1 布局的每个新方面,编写了一些小测试,然后在浏览器检查器中检查结果,并进行调整,看看会发生什么。有了这些,是时候回到你的作业页面,练习制作布局的工作流程了。你已经有了你的内容,所以现在你可以考虑如何最好地呈现它。从可能的设计的铅笔和纸草图开始,从移动版本开始,然后考虑桌面版本。首先构建移动版本,然后返回到你的草图,找出如何通过媒体查询将其转换为桌面版本。对于额外的标记,在几个不同的设备中测试您的断点,如果需要,添加一个或两个额外的中间媒体查询来平滑粗略的断点。``