CSS3-布局技巧高级教程-全-

CSS3 布局技巧高级教程(全)

原文:Pro CSS3 layout techniques

协议:CC BY-NC-SA 4.0

一、克服网页布局的挑战

Electronic supplementary material The online version of this chapter (doi:10.​1007/​978-1-4302-6503-0_​1) contains supplementary material, which is available to authorized users.

欢迎使用 Pro CSS3 布局技术!

虽然说风格比内容更重要是不公平的,但我们都希望网站看起来不错,对我们的设备做出反应,并在参与度上与其他媒体竞争,这确实是事实。这意味着,作为网页设计者,我们被寄予了很大的期望,去生成更加直观的布局、用户友好的展示和与设备无关的代码。虽然我们已经准备好迎接挑战,但是我们所拥有的一些核心工具要么从来就不是为版面设计设计的,要么已经用了十多年了。网络在发展,但是布局工具却没有——直到 CSS3 的出现和实现。

这本书将涵盖以下主题:

  • 利用 CSS3 布局模块
  • 决定今天什么是可行的
  • 发现即将在真实环境中使用的内容
  • 在 CSS3 不可用的情况下,学习使用 CSS Level 2.1 规范进行布局的最佳实践方法

在我们对新玩具过于兴奋之前,首先很有必要理解为什么我们会处于这种境地。为了正确理解,我们需要回顾 HTML(超文本标记语言)和 CSS(层叠样式表)的发展。不要担心:这篇评论不会是一次详尽的记忆之旅,但是当您下一次使用 CSS 来设计布局时,它会很好地为您服务。

HTML 属性和标签

当网络发展到非常早期的时候,HTML 被用于标记和样式。HTML 属性和标签定义了页面的外观。关于如何标记内容的决定很可能来自标签的默认视觉特征,也可能来自任何语义层次的感觉。考虑以下示例及其用途:

  • 标签用于大而粗的文本,同时也表示页面上最重要的信息。
  • <p>对于小文本,还可以显示段落文本,即标题的骨架。
  • <center>标签来对齐段落和表格。最初,它们只是用来显示表格数据的。这些标记开始被用于创建复杂的多栏布局,这对于语言中有限的标记和格式属性来说是不可能的。

尽管这种方法非常足智多谋且富有创造性,但它导致了一些既难以阅读又难以维护的可怕代码。随着布局需求变得越来越复杂,表格开始相互嵌套,通常有几层之深。视觉上多余的透明间隔 gif 越来越多地用于确保元素的正确定位。一个简单的页面包含成百上千行难以理解的代码变得很常见,如清单 1-1 所示。

<FONT FACE=TIMES COLOR=#FF0000 SIZE=3>
<H2><I>WELCOME TO MY WEBSITE</I></H2>
  <CENTER>
    <TABLE WIDTH=720 HEIGHT=480 BORDER=2 BGCOLOR=BLACK>
     <TR>
       <TD BACKGROUND=texture.gif>
         <TABLE WIDTH=360 HEIGHT=480 BORDER=0>
           <TR>
             <TD>
                <IMG SRC=spacer.gif WIDTH=360 HEIGHT=10><BR>
                 <H1>ABOUT MY SITE</H1>
                 <P>...</P>
             </TD>
            </TR>
           </TABLE>
         </TD>
         <TD BACKGROUND=texture2.gif>
          <TABLE WIDTH=360 HEIGHT=480 BORDER=0>
           <TR>
             <TD>
                <IMG SRC=spacer.gif WIDTH=360 HEIGHT=10><BR>
                 <H1>ABOUT ME</H1>
                 <P>...</P>
             </TD>
           </TR>
         </TABLE>
       </TD>
     </TR>
    </TABLE>
  </CENTER>
</FONT>

Listing 1-1.Example of a Vast Listing to Create a Basic 

Two-Column Layout

这种编码和维护网站的方法提出了一些问题,这些问题对于使用 HTML 的每个人来说都是显而易见的。Web 需要一种将内容和样式分开的方法,因此万维网联盟(W3C)承担了这项任务,开发了 CSS Level 1 规范。

CSS 的到来

随着 Web 开始超越简单的基于文本的媒体,成为更加视觉化、杂志式的体验,很快就发现 HTML 样式带来的限制将成为一个问题。负责定义网络标准的 W3C 认为将风格与内容分开更明智,并开始研究一种新的语言,这种语言将控制内容的美学处理,而不考虑内容的语义。解决方案是层叠样式表(CSS),它是现代网页上所有设计和布局的基础。

CSS 级别 1

CSS Level 1 (CSS1)并不打算作为实现布局的解决方案。相反,这个想法是替换所有基本的视觉特征,比如颜色、字体、边距和边框,这些都是用 HTML 标签和属性指定的。结果是以下有限的属性集:

  • 块级元素的宽度和高度
  • 漂浮,清除漂浮元素
  • 边距和填充
  • 背景颜色和图像
  • 边界
  • 字体和字体样式
  • 列表样式
  • 一些基本的排列

CSS1 允许设计采用 HTML 代码本身之外的单个元素的基本样式。第一次,一个网站的外观可以通过一个外部文件来控制。这对页面设计的维护和一致性有很大的好处,因为一行 CSS 代码现在可以影响整个网站。以前,简单的标题颜色改变意味着单独编辑网站中的每个页面。

由于浏览器市场缺乏竞争以及设计者的需求相对缓慢,网络浏览器花了一些时间来采用新的 CSS 规范。直到 20 世纪 90 年代末,设计人员才能够依靠常用的浏览器,如 Netscape Navigator 和 Microsoft Internet Explorer,以近乎精确的方式解析和呈现 CSS 代码。巧合的是,微软和网景正在争夺霸权。如图 1-1 所示,Internet Explorer 是最终的胜利者。

A320135_1_En_1_Fig1_HTML.jpg

图 1-1。

Internet Explorer on the Mac was the first CSS-compliant browser

也许你熟悉使用浮动元素作为创建布局的系统。然而,CSS1 中引入的floatclear属性从来不是为了这个目的。它们旨在提供以前属于 HTML 的ALIGN=LEFTALIGN=RIGHT属性的 CSS 传真。计划是在图像上使用它们,让文本自动围绕元素流动。第二章讨论了如何有效地使用浮动元素。

您可能已经注意到了规范中的宽度和高度属性,它们可以用来定义元素的尺寸。但是它们的目的仅仅是复制以前在 HTML 中作为图像、表格和其他块级元素的属性使用的相同属性。

CSS1 显然是网络的一个里程碑。随着它在 20 世纪 90 年代后期被浏览器实现,W3C 开始致力于级联样式表语言的下一个迭代:CSS Level 2。

CSS 级别 2

CSS Level 2 设计的一个目的是在样式表中实现一些布局控制。将布局从 HTML 转移到 CSS 的第一次尝试是基于网页设计者已经习惯的表格模型。引入的一个关键的新属性是display,规范的一部分提供了要应用的值table-cell。(见图 1-2 。)该值在正确呈现后,可以让您创建一个类似于使用表格的布局,并包含等高的列。

A320135_1_En_1_Fig2_HTML.jpg

图 1-2。

CSS2 introduced the display : table-cell property to mimic the existing tabular layout solution being used by designers

可悲的是,并不是每个浏览器都支持 CSS2 标准,所以它实际上在网络上是不可用的。虽然很多浏览器支持display: table-cell,但是 Internet Explorer 6 不支持。因此,可靠的布局仍然牢牢地留在 HTML 表格的领域中。此外,浏览器供应商对松散编写的 CSS2 规范的解释略有不同。因此,浏览器呈现的同一页面不一致,让设计者和消费者都很沮丧。

W3C 已经开始着手 CSS 的下一个版本——level 3。然而,认识到 CSS2 规范中的缺陷,该组织搁置了 CSS3,转而花了很长时间致力于解决 CSS2 产生的互操作性问题,最终开发了 CSS Level 2.1 形式的后继版本。

因为 Internet Explorer 实际上享有垄断地位,所以大多数网站的设计都考虑到了它的呈现方式。最终,设计师采用了风格和内容的分离,但他们被迫使用浮动和绝对定位来设计布局。正如您已经看到的,这些属性从来就不是用来作为布局工具的。但是足智多谋的网页设计社区找到了劫持它们的方法,并且在不使用表格的情况下生成巧妙的布局。

浏览器

图 1-3 显示了权力的天平向谷歌的 Chrome 浏览器倾斜。然而,很大一部分用户依赖于 Internet Explorer。

A320135_1_En_1_Fig3_HTML.jpg

图 1-3。

Market share statistics from 2013 show browser usage. Image from StatCounter.com

让我们来看看下面的例子:

  • 火狐浏览器
  • 微软公司出品的 web 浏览器

火狐浏览器

1999 年美国在线(AOL)收购网景浏览器后,源代码被开源,允许开发者社区为其做出贡献。这一令人钦佩的行动导致了一种全新的浏览器功能的形成。其结果是 Mozilla 基金会和 2004 年新的网络浏览器 Firefox 的出现。

Firefox 单枪匹马引发了一场新的浏览器大战。微软仍然是占主导地位的浏览器,市场份额在 90%左右,但 Firefox 慢慢削弱了它的主导地位。这最终迫使微软在中断六年后更新了老化的 ie 浏览器。

微软公司出品的 web 浏览器

Internet Explorer 7 于 2007 年发布。它给用户带来了选项卡式浏览,但在标准采用或对设计者 CSS 的额外支持方面很少。

2000 年代末,Internet Explorer 8 引入了对display: table-cell的支持,最终实现了一定程度的互操作性。令人沮丧的是,仍有超过一半的网络用户使用 Internet Explorer 6 的问题。

Note

即使在今天,Internet Explorer 6 也只有大约 1%的市场份额。大多数网页设计者现在选择忽略这部分市场,因为提供支持所花费的时间与回报的递减不成比例。

当微软继续拖后腿的时候,Firefox 开始流行,一个新的竞争者被引入市场。搜索引擎巨头谷歌基于开源 WebKit 项目开发了自己的品牌浏览器,并于 2008 年底发布。Chrome(见图 1-4 )很快取代 Firefox 成为网络上第二受欢迎的浏览器,并朝着完全符合 CSS2.1 迈出了一大步。

A320135_1_En_1_Fig4_HTML.jpg

图 1-4。

Google’s Chrome is now the world’s most widely used browser

CSS 盒子模型

在 2000 年至 2009 年期间,网页设计师不得不应对非常头痛的问题,即差异巨大的渲染引擎以完全不同的方式显示他们的代码。最大的问题是 CSS box-model(见图 1-5 ),它用于从指定的宽度、高度、边距和填充的组合中确定元素的宽度。由于编写松散的 CSS2 规范,微软对 box 模型的解释与其他浏览器供应商社区不同,导致了竞争浏览器之间文档呈现的不一致;在 Internet Explorer 6 以外的浏览器中,页面无法按预期呈现。因此,采用了变通方法、shivs 和 hacks 来创建布局,这些布局基于符合 CSS2.1 规范的代码,但也适用于不符合标准的 IE6 渲染引擎。

A320135_1_En_1_Fig5_HTML.jpg

图 1-5。

An illustration of the different box-model rendering across browsers

微软目前正在邀请用户放弃 Internet Explorer 6,并认为它只不过是一个糟糕的记忆。然而,由于 Internet Explorer 7 和 8 的兼容模式,很大一部分浏览器市场份额仍然使用 Internet Explorer 6 渲染方法。因此,常见到针对微软浏览器的专家样式表。此外,整个 JavaScript 库都包含在一个页面中,以便符合 polyfill 的布局呈现。

为了应对不同浏览器之间实现互操作性的困难,开发了一系列测试来帮助衡量不同浏览器相对于 CSS 规范的性能。这些酸性测试被标准支持者用来向包括微软在内的浏览器供应商施压,要求他们改进软件。

最后,在 21 世纪中后期,微软开始开发符合标准的 IE 浏览器版本:IE8 于 2008 年发布,IE9 于 2011 年发布。与此同时,随着 iPhone 等设备的发布,移动领域正在发生一场革命。这些新的支持互联网的智能手机支持新开发的 CSS3 规范的元素,以及 HTML5,并进一步增加了现有市场领导者采用标准的压力。

CSS 级别 3

CSS Level 3 不同于之前的迭代,因为它是模块化的。这允许 CSS 工作组在规范成熟时发布不同的部分,并且浏览器供应商能够快速采用功能。CSS 级模块化方法大致分为四个部分:

  • 选择器和逻辑
  • 装饰效果
  • 排版(包括对国际化的支持)
  • 布局

最有趣的是,布局方面封装了一系列新模块,这些模块在页面布局方面提供了灵活性和标准化,这在 Web 上是前所未有的。令人沮丧的是,即使有了这个新规范,我们仍在旧浏览器和不完整实现的阴影下挣扎。

CSS 布局模块

CSS Level 3 为设计者的武库中增加了一系列新的布局工具。这些模块中的每一个都提供了一种令人兴奋的方法,只使用 CSS 来制作布局。这些模块将改变你创作风格的方式,更重要的是,改变你的 HTML 标记。

四个主要模块正在开发中,而不是一个单独的方法来制作布局。每一个都有自己的概念、规则,以及最重要的浏览器支持。以下章节深入探讨了每个模块:

  • CSS 多列布局模块
  • CSS 灵活盒子布局(Flexbox)模块
  • CSS 网格布局模块
  • CSS 区域布局模块

在第 4–7 章节深入每个模块的全部细节之前,您将在第二章中对每个模块进行适当的概述。与此同时,您可以通过快速查看每个模块在布局方面可以实现的功能来激起您的兴趣。

CSS 多列布局

CSS 多列布局是新布局模块中最容易掌握和实现的。它也是对浏览器支持最成熟的模块,尽管它可能是对高级布局最没用的模块。

多栏布局(见图 1-6 )确实如你所料:它使内容很容易自动流入多栏,这可以适应可用空间,以便较小的屏幕比较大的屏幕呈现较少的栏。第四章考查本模块。

A320135_1_En_1_Fig6_HTML.jpg

图 1-6。

CSS Multi-column Layout rendering content into a column-based layout

CSS 灵活的盒子布局

CSS 柔性盒布局(或 Flexbox)已经经历了几次不同的修订。多亏了一些早期的浏览器实现,网络上有许多现在已经不存在的例子。这导致了网页设计社区的混乱;但是现在规范已经稳定了,对模块有了相当好的跨浏览器支持。

Flexbox 的设计并不是为网站提供一个完整的布局解决方案,但是它确实可以让你创建一些元素,比如工具栏和标签区域,这些元素可以响应用来查看它们的设备(见图 1-7 )。第五章深入探讨了 Flexbox 模块。

A320135_1_En_1_Fig7_HTML.jpg

图 1-7。

Flexbox helps solve some common user interface design problems

CSS 网格布局

CSS 网格布局是最令人兴奋的布局模块之一,因为它第一次允许设计真正与表现分离。元素可以使用 CSS 网格布局重新排序,因此标记到达的顺序与布局无关。对于努力创建有意义的语义标记的设计师来说,这是一个极好的消息,更不用说该模块允许在定义的网格内进行布局控制,并完成垂直对齐(见图 1-8 )。第六章研究了所有的细节和浏览器支持。

A320135_1_En_1_Fig8_HTML.jpg

图 1-8。

The CSS Grid layout brings a flexible and reliable grid layout option to the Web for perhaps the first time

CSS 区域布局

CSS 区域布局允许内容在杂志风格的布局中从一个区域到另一个区域的复杂流动。这种复杂的布局超出了其他布局模块。它可用于创建响应不同设备的动态、流畅布局(参见图 1-9 )。CSS 区域布局还不是一个完全成熟的模块,但是第七章会检查所有的细节,包括当前的浏览器支持。

A320135_1_En_1_Fig9_HTML.jpg

图 1-9。

CSS Regions Layout offers an exciting way to position content in and around elements without affecting document flow Note

还有一些新兴的布局模块,虽然还不是 CSS 规范的一部分,但提供了更多的布局选项。在这本书的结尾你会看到一些。

正如您所料,目前使用 CSS3 模块存在许多潜在的问题:一些仍在开发中,而另一些已经相当成熟。一些浏览器几乎已经完全实现了单个模块的标准,但是其他浏览器还在继续努力合并或者在某些情况下定义它们。这可能是一个雷区,但这本书引导你安全地通过陷阱!

这本书将如何帮助你

现在你知道你面对的是什么了,让我们快速看看你能从阅读这本书中得到什么。我的目的是帮助你理解在你的网站设计方法中可以使用的关键 CSS 布局技术。

CSS3 提供了大量令人兴奋的可能性,这本书着眼于每个关键的布局模块。给你一个警告:作为阅读这本书的结果,你将改变你构建网站布局的方式!但话虽如此,你也会看到一些限制——标准本身的限制,或者人们用来访问网络的浏览器软件带来的限制。

到这本书结束时,你会对你今天能做什么有一个现实的看法,以及对未来一两年可能发生的事情有一个好的想法。您还将看到一系列有用的多填充技术示例,它们可以为您的布局提供一个优雅的后备。

当然,如果忽略了大部分继续使用旧浏览器软件的用户,任何 CSS 布局书籍都没有用。因此,您还将看到仅使用 CSS2.1 进行布局的最新最佳实践方法,并在此过程中学习概念。尽管我假设你熟悉 CSS2.1,下一章还是从这个主题开始。

摘要

CSS3 仍在发展中,但它的大部分现在都可以安全地使用。像 Flexbox 这样的布局模块为网页设计者面临的一些现实挑战提供了一个可靠的解决方案。自网络出现以来,CSS 已经走过了漫长的道路,在过去的几年中,这种语言的发展速度大大加快。这本书将让你快速掌握开发中每个主要布局模块背后的核心原理,并向你展示如何在现实世界中使用这些模块。我们开始吧!

二、CSS 中的布局模块:旧与新

本章将帮助你在与 CSS 相关的核心布局概念上站稳脚跟。如果你熟悉 CSS2.1,你已经对它了如指掌,但是可能有一些你没有意识到 CSS 支持的概念(因为浏览器支持一直很差)。

本章快速浏览了 CSS 提供的所有不同的布局范例,从 CSS 的原始版本:level 1 开始。请注意,CSS 提供的每个布局解决方案都是作为一个模块实现的。在 CSS3 之前,每一层的整个 CSS 规范都包含在一个无所不包的模块中,而现在每一层都被分割成自己独立的模块;但是为了简单起见,我把每种方法都当作一个单独的模块来讨论。

正如我在第一章中提到的,在 CSS 出现之前,HTML 并没有提供多少布局控制。设计者找到了一种巧妙的方法来制作复杂的布局:通过使用表格在页面上精确定位元素来破解 HTML 规范。表格是一个非常有用的布局工具,因为它们为单个内容的定位提供了一个可控的解决方案。然而,HTML 表格从来就不是用来布局的;所以,从语义上来说,这次黑客攻击是一场灾难。因为整个方法是一种变通方法,所以还存在内容的可维护性和可读性问题。发现六七层深度的嵌套表并不少见。

随着 CSS1 的出现,焦点开始从使用 HTML 呈现一切(包括内容和表示)转移开来。取而代之的是,将内容从审美呈现中分离出来的思想得以确立。

Note

本章讨论了不同的 CSS 级别:1、2 和 3。需要注意的是,在设计网站时,你不能选择使用哪个级别;浏览器支持不同的级别,每个级别都建立在现有级别之上或旁边。虽然这本书是关于 CSS3 的,但是在屏幕上看到的结果取决于你使用的浏览器——或者更重要的是,浏览你网站的人使用的浏览器。

布局概念

在引入 CSS3 之前,CSS 提供了四种(官方)不同的布局模式。正如已经建立的那样,除了用户代理应用的默认行为之外,HTML 本身不包含任何布局特定的功能。对于网页设计者来说,这是一个发现的旅程,从基于表格的布局作为实现对定位的精细控制的方法开始,到本世纪最初几年 CSS 的采用,最终达到今天的成熟程度,表现和可用性的问题是内在相关的。

那么什么是 CSS 呢?当设计者试图创建一个更加视觉化的网站时,HTML 语言的局限性很快就显现出来了。作为一个主要基于文本的系统,HTML 是一个交流信息的好方法,但是它不是一个很好的美化信息的工具。负责开发 HTML 语言的机构做了各种尝试来解决基本的样式需求,但是从根本上说,HTML 的最初目的正在被侵蚀。级联样式表(CSS)的引入是实现可视化 Web 的第一步。一旦建立起来,CSS 就被迅速采用并不断迭代,直到 21 世纪初达到 2.1 版本,当时它陷入了政治和缓慢的浏览器开发的泥潭,陷入了停顿。尽管如此,设计师们继续试验 CSS 的可能性,通过 CSS Zen Garden 这样的工具来推广它,如图 2-1 所示。

A320135_1_En_2_Fig1_HTML.jpg

图 2-1。

CSS Zen Garden spearheaded the CSS revolution in the early years of the 21st century

网络在发展,但是我们可以使用的工具却没有——直到 CSS3 的出现和实现!CSS 处理 HTML 文档的外观和样式,包括以下内容的表示方面:

  • 文本,包括字体选择、字体大小、粗细、间距、方向和装饰
  • 不同元素的颜色和背景,包括图像和渐变
  • 边框和边框效果,包括线条样式、大小和弯角,以及投影等特殊效果
  • 不同元素在页面上的定位,可以在文档流内,也可以在文档流外
  • 页面上不同元素的边距和填充
  • 跨不同结构元素(包括列和区域)分布和对齐内容
  • 过渡和动画,包括用户交互控制
  • 2D 和三维空间中的变换

值得快速强调的是,CSS 的最新版本仍然处于不断变化的状态。而在以前的版本(CSS2.1)中,整个规范包含在一个模块中,而在 CSS3 中,各个组件都被模块化了。这意味着 CSS 工作组(CSSWG)可以更快更有效地迭代单个模块,浏览器供应商可以实现标准,而不必等待每个单个模块都达到推荐状态。不利的一面是,规范被分割在许多不同的模块和项目中。这使得跟踪哪个浏览器支持某个特定功能以及全球范围内的最新发展变得很棘手。

自从 W3C 在 2005 年宣布 CSS3 的开发以来,web 设计社区一直带着兴奋和期待的混合情绪关注着,等待浏览器实现这些标准并为设计开辟一系列新的可能性。从 CSS3 开发开始到现在已经将近十年了,但是直到最近一两年才有了对 CSS2.1 的普遍支持!

尽管如此,随着浏览器供应商迅速实现对新功能的支持,CSS3 正在 web 设计界掀起巨大的波澜。所有主流浏览器都已经支持大量新的 CSS3 属性、创新的 CSS3 布局方法、基于 CSS 的动画和特殊的视觉效果。今天,甚至可以在一些浏览器中直接渲染 3D 场景,而不需要插件或特殊的阅读器软件。

历史上,web 采用新技术的速度一直很慢,因为 Web 用户需要在这些技术得到支持之前主动更新他们的浏览器软件。自然,用户有比更新软件更有趣的事情要做,结果整代用户(和计算机)都被购买时安装的原始浏览器所困扰。随着新一代笔记本电脑和台式电脑的出现,更不用说基于 Android 和 iOS 操作系统的智能手机的广泛采用,浏览器软件也在发展,现在许多流行的浏览器在有新版本时会自动更新。

直到几年前,如果不借助 Photoshop、Adobe Flash 或一些非常复杂的 JavaScript,在网页上渲染阴影是不可能的。现在呢?CSS3 使得渲染阴影像设置一个属性一样简单!更好的是,由于这个 CSS3 属性在今天的浏览器中被广泛采用,这是一个非常安全的渲染效果的方法。

CSS3 规范提供了一套强大的新工具,远远超出了简单的投影渲染。这本书关注的是布局选项,但是不要忘记 CSS3 提供的不仅仅是布局控制;CSS3 将你的网页和应用程序的样式提升到了一个全新的水平,远远超越了过去的可能性。当然,它不是一个完美的工具;在本章中,我们来看看 CSS3 没有解决的问题以及它擅长的事情。

不同类型的布局

关于现代 web 开发,需要理解的一个关键问题是内容的结构独立于表现形式。CSS 是专门设计来让你定义视觉或听觉的表现,而不需要以特定的方式构造 HTML,至少是为了如何向用户显示页面。

这并不是说这两件事没有明确的联系!CSS 依赖于它所应用的 HTML 中明确的结构;但是,页面的布局越来越不受 HTML 中内容的顺序或特定标记的支配。

这是非常有益的,因为它允许在稍后阶段更容易地重新调整内容的用途,无论是到新的平台还是作为设计改进的一部分。这也意味着您可以根据设备或访问设备的用户的配置文件,以不同的方式呈现完全相同的内容。在实践中,这就是响应式设计(在不同设备上适当呈现工程内容的过程)。另一个好处是,内容可以按照语义顺序进行组织和交付,而不是依赖于网站的视觉设计。

随着 CSS 语言的发展,可用的布局选项也发生了变化。CSS 的每个新级别都建立在以前级别的基础上,增加了功能和能力。因此,有许多潜在的方法可以用看似相同的布局来设计页面的样式,但是每种方法都有不同的行为和特征。让我们快速看一下在引入新的 CSS 布局模块之前 CSS 提供了什么,这些模块是 CSS3 规范的一部分。

CSS1 中的布局

当网络发展到非常早期的时候,HTML 被用于标记和样式。HTML 属性和标签定义了页面的外观。关于如何标记内容的决定很可能来自标签的默认视觉特征,也可能来自任何语义层次的感觉。<h1>标签用于需要大而粗的文本的地方,<p>用于小文本,<center>标签用于对齐段落和表格——仅作为一种呈现表格数据的方式——以创建复杂的多栏布局,这在语言中可用的标签和格式属性的有限集合中是不可能的。

尽管这种方法非常足智多谋且富有创造性,但它导致了一些可怕的代码,这些代码既难以阅读又难以维护。随着布局需求变得越来越复杂,表格开始相互嵌套,通常有几层之深。视觉上冗余的透明间隔 gif 越来越多地被用来确保元素的正确定位,一个简单的页面包含数百或数千行意大利面条汤(难以理解的代码)变得很常见。清单 2-1 显示了与第一章中相同的代码示例:实践中一个典型页面的 HTML 代码,包括大量可视化渲染指令。

<FONT FACE=TIMES COLOR=#FF0000 SIZE=3>
 <H2><I>WELCOME TO MY WEBSITE</I></H2>
  <CENTER>
    <TABLE WIDTH=720 HEIGHT=480 BORDER=2 BGCOLOR=BLACK>
      <TR>
        <TD BACKGROUND=texture.gif>
          <TABLE WIDTH=360 HEIGHT=480 BORDER=0>
            <TR>
              <TD>
                <IMG SRC=spacer.gif WIDTH=360 HEIGHT=10><BR>
                  <H1>ABOUT MY SITE</H1>
                  <P>...</P>
              </TD>
            </TR>
          </TABLE>
        </TD>
        <TD BACKGROUND=texture2.gif>
          <TABLE WIDTH=360 HEIGHT=480 BORDER=0>
            <TR>
              <TD>
                <IMG SRC=spacer.gif WIDTH=360 HEIGHT=10><BR>
                  <H1>ABOUT ME</H1>
                  <P>...</P>
              </TD>
            </TR>
          </TABLE>
        </TD>
      </TR>
    </TABLE>
  </CENTER>
</FONT>

Listing 2-1.Typical HTML Code Before CSS and Modern Web Standards Were Widely Adopted

这种编码和维护网站的方法所带来的问题对于每个使用 HTML 的人来说都是显而易见的。Web 需要一种方法来将内容与风格分开,因此 W3C 接手了这一工作,开发了 CSS Level 1 规范。

第一章谈到了 CSS 旨在解决的不同视觉特征。回想一下,CSS Level 1 并不打算作为布局的解决方案。取而代之的是,用 HTML 标签和属性取代所有基本的视觉特征。如第一章所述,结果是一组非常有限的属性,包括以下内容:

  • 块级元素的宽度和高度
  • 漂浮,清除漂浮元素
  • 边距和填充
  • 背景颜色和图像
  • 边界
  • 字体和字体样式
  • 列表样式
  • 一些基本的排列

CSS1 允许设计者在 HTML 代码之外获取单个元素的基本样式。第一次,一个网站的外观可以由一个单独的外部文件来控制。这对页面设计的维护和一致性有很大的好处,因为一行 CSS 代码现在可以影响整个网站。以前,简单的标题颜色改变意味着单独编辑网站的每个页面。

web 浏览器花了一些时间来采用新的 CSS 规范,直到 20 世纪 90 年代末,设计人员才能够依靠常用的浏览器来理解和准确地呈现他们的 CSS 代码。对于历史爱好者来说,这也是微软和网景争夺霸权的时期,Internet Explorer 是最终的胜利者。

值得注意的是,虽然您可能熟悉使用浮动元素作为创建布局的系统的想法,但 CSS1 中引入的floatclear属性从来不是为了这个目的。引入它们是为了提供以前属于 HTML 一部分的ALIGN=LEFTALIGN=RIGHT属性的 CSS 传真,旨在用于图像,允许文本自动围绕元素流动。

CSS2 和 CSS2.1 中的布局

CSS2.1 引入并定义了四种不同的布局模式来呈现网页。这些是浏览器在解析 CSS 规则时使用的系统,用于根据元素的兄弟元素、文档中的流和父元素来确定元素的大小和位置。这四种模式如下:

  • 块布局:用于布局或组织文档中的元素
  • 嵌入式布局:用于布局文本
  • 表格布局:用于在二维网格中显示和布局表格数据
  • 定位布局:用于在页面上明确定位元素,将它们从文档流中移除

块布局

W3C 的 CSS2.1 规范提供了对块布局的解释:

In the context of block formatting, starting from the top of the containing block, vertically place the boxes one after the other. The vertical distance between two sibling boxes is determined by the margin property. Vertical margin folding between adjacent block-level boxes in block format context.

块布局在元素周围创建矩形框,描述该元素占用的空间量。许多 HTML 元素自动采用块布局,包括像<p><h1><div><ul>这样的元素。块级盒子垂直堆叠,每个盒子紧接着前一个占据垂直空间。块级盒子不会水平堆叠。每个新块出现在新的垂直位置。

有一些与块级框的布局相关联的特殊规则,以及用于确定每个块级框占用多少空间的规则。简言之,这些规则如下:

  • 块级元素的background完全延伸到border的外边缘。这意味着背景填充了内容区域以及paddingborder区域的组合。如果边框使用任何透明度(例如,如果它使用虚线),则在虚线之间的空间中可以看到background
  • 块级元素的width默认设置为auto(填充可用的水平空间)。唯一可以设置为auto的其他属性是marginheight属性。
  • 负值可以应用于margin属性,但是其他属性不能有负值。
  • widthheight属性仅定义内容区域。paddingbordermargin都是为了布局的目的而增加盒子的宽度。

这最好用图表来说明,如图 2-2 所示。marginpaddingborder都增加了块级元素的位移大小。从历史的角度来看,Internet Explorer 最初实现的盒子模型包括元素的定义宽度(和高度)内的填充,导致了多年的变通方法和特定于浏览器的样式表破解。幸运的是,那些日子已经过去了!

A320135_1_En_2_Fig2_HTML.jpg

图 2-2。

The block-level box model. The width property affects only the content area, with padding, border, and margin adding to the overall displacement width and height

内嵌布局

内联级元素是源文档中不构成新内容块的那些元素;内容按行分布(例如,段落中强调的文本片段、内联图像等)。内联级元素生成内联级框,它们是参与内联格式上下文的框。这意味着它们在相同的读取流中替换相邻的内容,但是它们不会干扰块级呈现。

内联框是内联级别的,其内容参与其包含的内联格式上下文。一个display值为inline的非替换元素生成一个内嵌框。默认采用内联行为的元素的常见例子包括<span><em>

表格布局

使用display属性进行访问,表格布局允许元素像构成表格的一部分一样工作——承担表格单元格的角色,并占据表格布局中的行和/或列。这种布局模式非常强大,原因和早期的 web 设计者劫持表格一样,但是糟糕的浏览器支持在历史上意味着它从来没有作为一种可靠的布局解决方案出现过。

现代浏览器支持非常好。因此,表格布局是一种可行且有效的布局方法。

定位布局

定位布局允许您使用坐标精确地放置单个元素,相对于页面或另一个具有定义位置的包含元素。这使您可以将元素放在浏览器窗口的右上角,或者让单个元素在视口内的任意位置相互重叠,并假定在文档流中有一个位置是默认行为。

CSS2.1 规范中提供了几种不同的定位属性值:

  • 静态:应用正常的流程规则,并且topbottomleftright属性不起作用。
  • 相对:框的位置根据它在文档流中的位置来确定。属性然后相对于它的“正常”位置偏移盒子的位置。受框在文档流中的位置影响的后续元素的行为就像框上没有偏移一样。
  • 绝对:盒子的位置(可能还有大小)由topleftbottomright属性指定。这些属性指定从包含框(可能是页面本身)的偏移量。
  • Fixed:长方体按照绝对位置定位,但它固定在相对于某个参考的位置。在大多数情况下,位置相对于视口是固定的,不会相对于用户滚动页面而移动。

CSS3 中的布局

正如已经讨论过的,CSS3 以一种新的方式处理布局。各个组件被分解成独立的模块,而不是单一的整体规格。因此,CSS3 有几个不同的布局模块,每个模块都是单独开发和维护的。

浏览器已经很好地支持了几个模块;其他的仍在开发和定义中。这本书检查了所有主要的布局模块,并指出哪些模块你可以直接使用,哪些是即将推出的,哪些是未来要关注的。第一章简要地讨论了每一个模块,所以与其再详细讨论每一个模块,不如在这里提醒一下本书所关注的模块:

  • CSS 多列布局
  • CSS 灵活盒子布局(Flexbox)
  • CSS 网格布局
  • CSS 区域布局

然而,这个列表并不是 CSS3 中布局的限制。正如你在这本书的结尾所看到的,一些令人兴奋的想法正在被讨论和提出,它们可能会改变你默认的页面布局方式!

理解 CSS3 不会以任何方式取代 CSS2.1 或 CSS1 是很重要的。接下来的章节中涉及的新模块建立在现有规范的基础上。因此,您将继续使用 CSS2.1 引入的四种布局类型——块、内联、表格和绝对——作为最常见的默认布局解决方案。您可以将这些原始布局范例与新模块结合使用,并对其进行补充。

模块化的重要性

您可能想知道为什么 CSS3 以模块化的方式构建很重要,以及这与现有 CSS 规范的工作方式有何不同。简单的回答是,通过采用模块化方法,组成 CSS3 的每个独立模块都可以被浏览器供应商测试、评估和采用,而无需采用整个规范。这也意味着 CCSWG 可以在其生命周期的不同阶段关注规范的不同领域。

这为什么有用?嗯,仍在开发中的新布局模块(例如,CSS 区域布局和 CSS Flexbox)可以与已完成的模块共存。功能可以在持续的基础上发布,而不需要完成每个模块,从而提高了实现和采用的速度。这对大家都好!

我提到过 CSS3 规范的不同部分由不同的模块覆盖,并且每个模块都处于开发生命周期的不同阶段。这听起来像是理想的解决方案,但这并不意味着开发新规范的所有令人沮丧的部分都会被自动删除。仍然有一个固有的缓慢的开发周期,这可能会让热衷于推动 web 前进的 Web 设计人员和开发人员感到沮丧。

然而,您可以从中获得的是,整个规范的不同元素现在都可以使用。相比之下,CSS2.1 过了十年才得到完全支持——而且是在 W3C 的 CSS 团队完成了所有开发工作之后!

一个额外的好处是,因为每个模块都是独立于其他模块的,当一个模块成熟时,浏览器供应商(如微软、苹果、谷歌和 Opera)能够在其浏览器中集成对它的支持。这为新的模块和属性提供了早期支持,但这往往是有代价的;因为当工程师在浏览器中创建支持时,每个新模块都是不完整的,所以新属性在声明之前通常需要一个特定于供应商的前缀。这使得浏览器能够创建早期的支持,而不会导致后来的向后兼容性问题:当最终规范达成一致时,供应商前缀被删除,只留下完整的规范属性名称和行为。

总的来说,CSS3 仍然处于不断变化的状态(我会在整本书中提醒你这一点!).在 CSS2.1 中,整个规范包含在一个模块中,而在 CSS3 中,各个组件都被模块化了。这意味着 CSSWG 可以更快更有效地迭代单个模块,浏览器供应商可以实现标准,而不必等待每个单个模块都达到推荐状态。

CSS 布局的限制

如您所见,CSS2.1 提供了相当多非常有用的布局选项,CSS3 为工具箱带来了大量新选项。这对网页设计师来说是个好消息,随着新技术的发展,你将开始一段激动人心的发现之旅,充分利用新模块提供的机会。

然而,这并不完全是一片美好的前景。光靠 CSS 还是有很多事情做不到的。对于这些任务中的大多数,脚本化的工作区提供了一个解决方案;但是完整的布局涅槃还是有一段路要走。本书的最后几章对一些即将到来的提案进行了短暂的浏览。

正如您所看到的,CSS 主要关注页面的美学表现,无论是通过屏幕上内容的视觉表现,还是在办公室激光打印机上打印页面的方式,或者屏幕阅读器如何强调内容。对于这项任务来说,CSS 是网页设计者可用的最佳解决方案,在可预见的未来也是如此。如果你想做的只是创建静态网页,并把它们漂亮地呈现出来,CSS 将会是最合适的工具。

你可能已经猜到了,有一个“但是”来了!在今天的网站中,很难找到不需要某种文档对象模型(DOM)操作(移动、添加或删除树中的元素)或过程化生成标记的页面。有时,您创建完全通过服务器端脚本语言(如 ASP.NET 或 PHP)呈现的页面,使用处理逻辑生成按需呈现和样式化的页面。

CSS 可以很好地处理这种情况,提供了处理不同数量或排列的标记的灵活性。然而,它不是为设计者试图减少或消除回发到服务器进行数据处理的需要而设计的。

让我们以一个带有搜索表单的页面为例,当用户开始输入时,搜索表单会返回结果。现在,您不必依赖于页面首次加载时呈现的所有内容,而必须考虑到内容可能会随时发生变化,以响应动态加载的新内容。

Note

在继续之前,我应该指出,这种交互式数据反应用户界面解决方案与传统的页面加载/页面呈现模型一样频繁地向服务器回发数据。是生成和呈现内容的方法发生了变化。

内容通常使用 JSON 或 XML 通过 JavaScript 以这种方式加载。该脚本调用一个服务器方法,该方法或者为正在读取的页面生成附加标记,或者以脚本可以解释并用于操作页面内容的格式输出数据。

无论以何种方式加载内容,页面上显示的数据量和数据类型都会随着事件的发生而改变。当然,在创建样式表时,您可以考虑所有可能的场景,但是仅仅使用 CSS 是无法实现表示的细微差别以及向用户展示新内容已经加载到页面中的。

对于这些情况,JavaScript 是操纵页面外观的最佳方式。通常情况下,JavaScript 用于更新应用于特定元素的 CSS,但是程序性地生成值和属性的能力将脚本化解决方案与纯 CSS 方法区分开来。

如果单独使用 CSS 无法实现特定的布局,那么现在使用 JavaScript 为缺失的行为提供多种填充是完全可以接受的。我将在每个模块章节的末尾介绍这些场景。

Note

只是提醒一下:本书中的一些模块处于不断变化的状态。请经常查看 W3C 网站上的最新规范,以确保您使用的是最新的语法。

总结:为未来做好准备!

本章研究了不同层次的 CSS 提供的布局选项。CSS1 主要为内容提供了样式选项,忽略了控制这些元素位置的需要。第 2 级带来了四种不同的布局方法,用于相对于页面以及元素之间的定位。CSS3 远远超越了这四个工具。

现在,让我们继续学习新的模块,以及如何使用它们来创建新的布局,这在以前单独使用 CSS 是不可能的。下一章将向你展示 CSS3 之前的布局模块的概要,之后就是 CSS3 了。让我们开始吧!

三、我们去过的地方:定位、浮动和显示

本章介绍 CSS2.1 和 CSS1 布局模块。它既是现有布局选项的总结,也是基于 CSS 布局的“老式”方法的最佳实践指南/参考指南。有经验的网页设计师可能会选择跳过这一章,但是你可能会错过一些有用的技术和方法,即使是最老练的网页设计师也可能不知道。本章包括以下内容:

  • CSS 布局介绍
  • CSS2.1 布局模块
  • 如何使用它们
  • 真实世界的例子

您将快速浏览 CSS 提供的所有布局范例,从 CSS 的原始版本:Level 1 开始。请注意,CSS 提供的每个布局解决方案都是作为一个模块实现的。在 CSS3 之前,每个层次的整个 CSS 规范都包含在一个无所不包的模块中,而现在每个层次都被分割成自己独立的模块;为了简单起见,我把每种方法都当作一个单独的模块来讨论。

正如在第一章提到的,CSS 之前,HTML 在布局控制方面没有提供太多。设计者找到了一种巧妙的方法来制作复杂的布局:通过使用表格在页面上精确定位元素来破解 HTML 规范。表格是一个非常有用的布局工具,因为它们为单个内容的定位提供了一个可控的解决方案。然而,HTML 表格从来就不是用来布局的;所以,从语义上来说,这次黑客攻击是一场灾难。由于整个方法是一种变通方法,所以还存在内容的可维护性和可读性问题。发现六七层深度的嵌套表并不少见。

随着 CSS1 的到来,焦点开始从使用 HTML 渲染一切转移开来。取而代之的是,将内容从审美呈现中分离出来的思想得以确立。

Note

如果你已经是 CSS2 布局的专家,这一章不会给你提供任何新的见解,所以可以直接跳到第四章。如果你是网页设计新手,请继续阅读 CSS2 和 CSS1 提供的布局选项。

CSS3 之前的布局

正如在第二章中提到的,除了根据语义层次标记内容的能力之外,HTML 不是为布局而设计的。网络的第一个版本仅仅是为了方便访问和检索而互相链接的科学文献的集合。HTML 语言确实发展到以对齐的形式加入了一些有限的布局选项,但在早期,布局主要是通过误用<table>标签实现的。

想象一下这样一个场景:您想要为 Web 创建一个布局,其特征不仅仅是像 Word 文档一样的一系列内容。你的设计需要两栏(现代的说法是侧栏)。使用直接的 HTML 这实际上是不可能的,直到有人注意到<table>标签提供了这种程度的布局控制。图 3-1 显示了一个没有任何“布局”的布局,旁边是一个使用表格创建“布局”的布局很容易看出哪一个在视觉上更有吸引力——难怪设计师们想尽一切办法来美化和拓展网页设计的边界。

A320135_1_En_3_Fig1_HTML.jpg

图 3-1。

A linear layout versus a table-based layout , demonstrating the attraction of using tables when there were no other options available to designers

通过使用表格来排列不同的内容,设计者能够精确地控制元素在页面上的位置。尽管表格是为表示表格数据集而设计的。这种方法曾一度奏效,但随着设计师开始寻求更具进步性的设计,布局革命变得不顺利。使用表格可以实现极其复杂的布局,但是设计越复杂,就越有可能需要表格中的表格和跨越多列或多行的单元格;这导致了一种可怕的意大利面条式代码,难以破译,维护起来也很糟糕。

然而,难以理解的代码并不是表格独有的问题。作为将风格与内容分离的更广泛策略的一部分,W3C 致力于设计 CSS。直到 CSS2 才出现了任何特定于布局的特性;本章介绍了这些功能。

第二章列出了布局范例。本章从实际应用的角度讨论了所有的选项,所以让我们把浮动布局添加到列表中。在 CSS3 到来之前,可用的 CSS 布局选项如下:

  • 块布局:用于在布局文档时控制框
  • 嵌入式布局:用于布局文本
  • 表格布局:用于在二维网格中显示和布局表格数据
  • 相对和定位布局:允许在页面上显式定位元素,或者对文档流做出反应并影响后续元素,或者将它们从文档流中移除并使它们对页面上的周围元素没有影响
  • 浮动布局:允许元素在出现时从文档流中移除,但仍会影响页面上相对定位的元素

如果您对表格布局感到困惑,这是可以理解的。使用表格进行布局的想法从来没有问题,但是 HTML 表格实现并不是为适应布局而设计的。所以 CSS 2.1 规范引入了表格布局作为布局范式。让我们来看看实现布局的每一个选项,包括一些基本的例子,如果你是网页布局的新手,这些例子可以帮助你迅速进入角色。

相对和绝对定位

默认情况下,页面上的 HTML 元素采用相对定位。这意味着它们会将其他元素挤出来,为它们在文档中占据的位置腾出空间。如果您选择为某个元素分配绝对定位,您将从普通文档流中删除该元素,并且它不再与页面上的其他元素争夺位置。此外,相对定位的元素作为页面上的在先元素的结果被放置在页面上,而绝对定位的元素可以被分配坐标来占据。看看清单 3-1 中的代码,看看这两个选项是如何工作的。

<style>
.relative {
 position: relative;
 width: 100px;
 height: 100px;
 background: red;
 margin: 10px;
}
.absolute {
 position: absolute;
 top: 100px;
 left: 200px;
 width: 100px;
 height: 100px;
 background: yellow;
 margin: 10px;
}
</style>
<div class="relative">Element 1</div>
<div class="relative">Element 2</div>
<div class="relative">Element 3</div>
<div class="absolute">Element 4</div>
<div class="absolute">Element 5</div>
<div class="absolute">Element 6</div>

Listing 3-1.Difference between Relative and Absolute Positioning

列表 3-1 的结果如图 3-2 所示:相对定位的元素整齐地堆叠在一起,由于margin属性引入了 10px 的间隙。但是,绝对定位的元素都堆叠在彼此的顶部,因此您只能看到最近绘制的元素(元素 6)。这是 z- index 的一个例子,您可以在元素上设置一个属性,以改变它们在页面上的元素堆栈中的显示顺序,进而改变它们的绘制顺序。

A320135_1_En_3_Fig2_HTML.jpg

图 3-2。

The result of the code in Listing 3-1

绝对定位元素提供了大量的精细控制,但是当你处理不同大小的屏幕和浏览器窗口时,它们并不总是很方便。通常,您会希望文档流决定元素在页面上的显示位置。值得注意的是,绝对定位使用相对于其父元素的坐标。这意味着如果您将绝对定位的元素放在相对定位的元素中,绝对定位的元素会移动以反映父元素的位置。得心应手!

请看清单 3-2 中所示的示例代码,看看这在实践中是如何工作的。结果如图 3-3 所示。请注意,绝对定位的元素可以呈现在其相对父元素的边界之外。父节点只是提供计算位置的锚点。还值得强调的是,本例中最后一个绝对定位的元素不是位于相对定位的<div>中,而是位于相对定位的<body>中:它看起来呈现在页面的更高处,因为定位坐标是从整个页面的左上角开始计算的,而不是位于页面上其他地方的元素。

A320135_1_En_3_Fig3_HTML.jpg

图 3-3。

The result of the code in Listing 3-2

<style>
.relative {
 position: relative;
 top: 100px;
 left: 100px;
 width: 100px;
 height: 100px;
 background: red;
 margin: 10px;
}
#absolute1 {
 position: absolute;
 top: 100px;
 left: 200px;
 width: 100px;
 height: 100px;
 background: yellow;
}
#absolute2 {
 position: absolute;
 top: 100px;
 left: 200px;
 width: 100px;
 height: 100px;
 background: purple;
}
#absolute3 {
 position: absolute;
 top: 100px;
 left: 200px;
 width: 100px;
 height: 100px;
 background: yellow;
}
</style>
<div class="relative">
 Element 1
 <div id="absolute1">Element 4</div>
</div>
<div class="relative">Element 2</div>
<div class="relative">
 Element 3
 <div id="absolute2">Element 5</div>
</div>
<div id="absolute3">Element 6</div>

Listing 3-2.An elaboration on the previous example, showing the difference between relative and absolute positioning

相对定位和绝对定位的结合可以为 Web 上许多不同的布局挑战提供一个好的解决方案,但绝不是所有的挑战。以之前的例子为例,设计师想要将侧边栏合并到页面中。绝对定位的元素会给人一种侧边栏的感觉,但是因为绝对定位从文档流中删除了一个元素,所以侧边栏不会考虑页面上的任何其他内容。它会遮住任何想要呈现在它下面的内容,并且不会对它周围的任何其他内容区域做出反应。在这种情况下,设计师转而使用浮动元素。

浮动布局

浮动元素就是这样做的:它们在父元素中浮动,或者向左,或者向右。父元素中的内容不能侵犯浮动元素占用的空间。相反,内容围绕浮动元素流动,允许它继续影响周围的元素。但是,请注意,浮动元素会将其从页面的大小调整流程中移除。

与绝对位于相对元素内的定位元素一样,浮动不需要保持在父元素的范围内(尽管它们在水平轴上保持不变)。为什么这是一个问题?因为浮动元素可能会从相对定位元素的底部漏出,影响页面上后续相对定位元素的定位。

让我们看一个这种效果的例子。清单 3-3 显示了一个位于相对定位的父元素中的基本浮动元素。清单 3-4 扩展了布局,添加了额外的浮动元素,使它们溢出了父元素的底部。图 3-4 为列表 3-3 的结果,图 3-5 为列表 3-4 的结果。

A320135_1_En_3_Fig5_HTML.jpg

图 3-5。

The result of Listing 3-4. Note how floating elements do not contribute to the height of the relatively positioned parent element

A320135_1_En_3_Fig4_HTML.jpg

图 3-4。

The result of Listing 3-3

<style>
.relative {
 position: relative;
 width: 300px;
 background: grey;
 margin: 10px;
 padding: 10px;
}
#floater {
 float: right;
 width: 160px;
 height: 160px;
 padding: 10px;
 margin: 10px;
 background: green;
}
</style>
<div class="relative">
  <div id="floater">Floating element</div>
  <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Etiam porta sem malesuada magna mollis euismod. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
</div>

Listing 3-3.Continuing to explore the differences between Relative and Absolute Positioning

<style>
.relative {
 position: relative;
 width: 300px;
 background: grey;
 margin: 10px;
 padding: 10px;
}
.floater {
 float: right;
 width: 160px;
 height: 160px;
 padding: 10px;
 margin: 10px;
 background: green;
}
</style>
<div class="relative">
  <div class="floater">Floating element 1</div>
  <div class="floater">Floating element 2</div>
  <div class="floater">Floating element 3</div>
  <div class="floater">Floating element 4</div>
 <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Etiam porta sem malesuada magna mollis euismod. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
</div>

Listing 3-4.Floating Element within a Relative Parent: Content within the Relative Element Flows around the Floating Element

在 CSS3 之前,浮动元素通常用于创建水平导航栏。但是正如您将看到的,CSS3 中有新的、令人兴奋的(并且更加可靠的)选项。

浮动最大的问题是它们不可预测。有一些变通办法,如清单 3-5 所示,它使用clear属性来指示一个元素仅在所有浮动元素完成渲染后才出现。但是这些变通办法往往会导致页面上出现多余的代码或冗余的元素,比如一个<br>标签仅仅用于扩展一个相对定位的元素以完全包围一个浮动的子元素。同样值得一提的是,浮动元素不会影响结构布局,所以使用浮动元素创建的侧边栏在高度上无法与其父元素匹配,除非求助于黑客或脚本。

<style>
.relative {
 position: relative;
 width: 300px;
 background: grey;
 margin: 10px;
 padding: 10px;
}
.floater {
 float: right;
 width: 60px;
 height: 60px;
 padding: 10px;
 margin: 10px;
 background: green;
}
.clearfloat {
 clear: right;
}
</style>
<div class="relative">
  <div class="floater">Floating element 1</div>
  <div class="floater clearfloat">Floating element 2</div>
  <div class="floater">Floating element 3</div>
  <div class="floater ">Floating element 4</div>
  <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Etiam porta sem malesuada magna mollis euismod. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
  <br class="clearfloat" /> <!-- this isn't necessary on this page, but is commonly used to ensure the <div> with a class of relative expands to encapsulate the floating elements -->
</div>

Listing 3-5.Using the clear Property to Ensure that the Second Floating Element Doesn’t Stack Next to the First

图 3-6 显示了列表 3-5 的结果。属性强制周围的元素考虑浮动;但是正如您在最后一行代码中看到的,这可能会导致额外的元素被引入到标记中,仅仅是为了解决浮动的限制。这可不是什么好事!毕竟,CSS 旨在促进样式和内容的分离。

A320135_1_En_3_Fig6_HTML.jpg

图 3-6。

The output of Listing 3-5

先不说警告,浮动元素肯定有它们的用处。出现在文本块中的图像、引用、节内导航和旁白都是float属性的有效用法,所以不要把它当作布局工具。

到目前为止,本章讨论的所有内容都依赖于所讨论的元素在页面上的大小和位置。这就是所谓的块显示,这也是下一节要讨论的内容。

块和内嵌显示

页面上的元素有两种不同的显示类型,任何特定元素的默认显示样式取决于其语义功能。让我们看看每个术语的含义:

  • 块显示意味着元素占据水平和垂直空间,用一个不可见的边界框包围它。块元素替换页面上的其他元素,导致它们移动位置以适应其边界框的空间。块级元素总是从新的垂直空间开始,并占据全部可用宽度,尽可能地延伸。
  • 内联显示意味着元素位于内容流中,占据水平空间,但不影响垂直布局,除非元素的比例导致任何位移。

图 3-7 中的图表显示了两种显示类型之间的差异。

A320135_1_En_3_Fig7_HTML.jpg

图 3-7。

Differences between block and inline display, and how each impacts layout Note

请记住,当我说垂直和水平时,我假设您正在使用从左到右、从上到下的拉丁语。CSS 现在也支持其他阅读方向,但是为了避免混淆,我将这些术语作为页面上使用的阅读方向的同义词。

还有一种你没见过的展示:没有。如果将display属性设置为none,该元素会保留在页面上,但不会被渲染引擎绘制,也不会对周围的元素产生任何位移。您可能想知道何时需要使用display : none,因为排除 HTML 代码肯定比使用 CSS 隐藏元素更有意义。考虑一下弹出式模态对话框、页面的“阅读更多”部分和下拉菜单系统。将display属性的值设置为none是一种非常有用的能力,没有它,你在网上遇到的很多交互都是不可能的!(如果你真的需要隐藏一个元素,但仍然让它占据页面上的空间,使用visibility: hidden而不是display: none。当你准备好再次展示时,使用visibility: visible。这将继续渲染对象,但阻止它在屏幕上绘制,允许它继续占用布局中的空间。)

让我们看一些块元素和内联元素的例子。表 3-1 显示了每种情况的一些常见示例。

表 3-1。

Examples of Elements that Are Either display: block or display: inline by Default (CSS Allows You to Overwrite This Default)

| 块和内联元素的示例 | | --- | | 街区 | 在一条直线上的 | | --- | --- | | `
` | `` | | `

` | `` | | `

` | `` | | `

` | `` | | `

` |   | | `

    ` | `` | | `
  • ` | `` | | `
    ` | `` | | `
    ` | `
    ` |

    除了display: blockdisplay: inlinedisplay: none之外,还有另一个选项,它结合了display: blockdisplay: inline. Display: inline-block的属性,在两者之间提供了一个折衷方案,允许元素内嵌放置,但占用指定的宽度和高度。Inline-block相对来说是 CSS 党的后来者,主要是因为在 CSS2.1 的早期,浏览器没有可靠地支持它。但它是另一个有价值的工具,也是帮助解决布局挑战的一个选择。清单 3-6 展示了display: inline-block的一个简单例子。结果如图 3-8 所示。

    A320135_1_En_3_Fig8_HTML.jpg

    图 3-8。

    The output of Listing 3-6, where elements have been given structure thanks to display: inline- block

    <style>
    .relative {
     position: relative;
     padding: 10px;
     width: 500px;
     background: red;
     margin: 10px;
    }
    .navitem {
      display: inline-block;
      width: 70px;
      height: 40px;
      line-height: 40px;
      text-align: center;
      background: grey
    }
    </style>
    
    <div class="relative">
      <h1>Example of inline-block</h1>
      <p>Here is some content <span>that includes an inline &lt;span&gt; element</span>.</p>
      <p>Here's some more content, and this time the &lt;span&gt; elements have the class navitem applied to them: <span class="navitem">Item 1</span> <span class="navitem">Item 2</span> <span class="navitem">Item 3</span></p>
      <p>Note that inline-block elements contribute to the layout.</p>
    </div>
    
    Listing 3-6.Using inline-block to Give Inline Elements Structure in the Form of Width and Height 
    
    

    显示属性如何影响布局?

    如您所见,您对页面上元素的绘制方式有很大的控制权。display属性直接影响布局。默认情况下,一些元素的widthheight不能被显式设置,因此它们不能影响周围的元素或它们在页面上的位置。其他的默认有影响。自然,您可以使用 CSS 中的display属性覆盖任何元素的默认属性。

    让我们快速地看一下它的运行情况。清单 3-7 结合了相对和绝对定位;浮动元素;和内联块元素合并到一个页面中。这并不罕见;你通常会在最复杂的布局中找到各种布局的例子。列出 3-7 的结果如图 3-9 所示。

    A320135_1_En_3_Fig9_HTML.jpg

    图 3-9。

    The output of Listing 3-7. Note that different layout paradigms are suited to different solutions, so it’s common to use a range of tools to achieve a specific part of the overall layout

    <style>
    .relative {
     padding: 10px;
     position: relative;
     width: 920px;
     background: #efefef;
     border: 1px solid #ccc;
     margin: 10px auto;
    }
    #header {
     position: relative;
     padding: 10px;
     height: 80px;
     line-height: 80px;
     background: #999;
     color: #fff
    }
    #header h1 { font-weight: normal;margin:0;padding:0;}
    #search {
     position: absolute;
     top: 10px;
     right:10px;
    }
    #search input {
     padding: 5px;
    }
    #nav {
     position: relative;
     height: 30px;
     background: #ccc;
    }
    #nav ul {
     margin: 0;
     padding: 0;
    }
    #nav ul li {
     float: left;
     list-style:none;
     padding: 0;
     margin: 0 3px;
     width: 70px;
     height: 30px;
     line-height: 30px;
     text-align: center;
     background: #ddd;
    }
    .sidebar {
     float: right;
     width: 200px;
     background: #ebebeb;
     padding: 10px;
    }
    .ib {
     display: inline-block;
     width: 70px;
     line-height: 30px;
     text-align: center;
     background: #ddd;
     border: #ccc;
     margin: 5px;
    }
    .clearfloat {
     clear: both;
    }
    </style>
    
    <div class="relative">
     <div id="header">
      <h1>Site Name</h1>
      <form id="search"><input type="text" value="search site" /></form>
     </div>
     <div id="nav">
      <ul>
       <li><a href="#">Home</a></li>
       <li><a href="#">About</a></li>
       <li><a href="#">Contact</a></li>
      </ul>
     </div>
     <div class="sidebar">
      <h3>Popular CSS modules</h3>
      <p><span class="ib">CSS Flexbox</span><span class="ib">CSS Multi-Column</span><span class="ib">CSS Regions</span><span class="ib">CSS Grid Layout</span><span class="ib">CSS Shapes</span></p>
     </div>
     <div id="content">
      <h2>Welcome to our website</h2>
      <p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Curabitur blandit tempus porttitor. Maecenas faucibus mollis interdum. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p>
      <p>Donec id elit non mi porta gravida at eget metus. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Curabitur blandit tempus porttitor. Donec sed odio dui. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
      <p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Nulla vitae elit libero, a pharetra augue.</p>
      <p>Sed posuere consectetur est at lobortis. Sed posuere consectetur est at lobortis. Maecenas sed diam eget risus varius blandit sit amet non magna. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
     </div>
     <br class="clearfloat" />
    </div>
    
    Listing 3-7.Combining relative, absolute, float, inline, block, and inline-block Elements into One Example Layout
    
    

    表格布局

    本章讨论的最后一个布局工具是表格布局。正如你在第 1 和 2 章中所看到的,从网络的早期开始,表格就被用来实现布局。一旦 CSS 变得可用和可靠,Web 上就出现了强烈的反表格布局运动,结果表格布局几乎成了禁忌。这是一种基于 HTML 中的表格仅仅是为了使用表格数据而形成的观点,而不是为了页面的布局和显示。

    因此,区分 HTML 表格和 CSS 表格是很重要的。这里讨论的表格布局是通过将display: table分配给一个容器元素实现的。将display: table应用到现有的页面元素和使用 HTML <table>元素的区别在于,根据定义,<table>元素是并且将永远是一个表格。将display: table设置为属性的<div>可以简单地通过编辑 CSS 代码或使用@media查询来更改为使用不同的布局范式。CSS 表格有利于布局!

    CSS 表格布局提供了一种基于样式的解决方案,以类似于 HTML 表格但又不完全相同的方式呈现内容。每个不同表格元素的相应属性值如下:

    | `table    { display: table }` | | `tr       { display: table-row }` | | `thead    { display: table-header-group }` | | `tbody    { display: table-row-group }` | | `tfoot    { display: table-footer-group }` | | `col      { display: table-column }` | | `colgroup { display: table-column-group }` | | `td, th   { display: table-cell }` | | `caption  { display: table-caption }` |

    清单 3-8 展示了如何使用其中的每一个来实现基于表格的布局,以及该方法提供的所有好处。结果如图 3-10 所示。

    A320135_1_En_3_Fig10_HTML.jpg

    图 3-10。

    A page layout achieved using display: table. This is practically impossible to achieve without table layout, unless you use scripts or CSS3! Note that some properties have been ignored and aren’t rendered in the final page. display: table works just like an HTML table!

    <style>
     .table {
      display: table;
      border: 1px solid red;
      background: #eee;
      margin: 2px;
      padding: 2px;
     }
     .tr {
      display: table-row;
      border: 1px solid red;
      background: #ddd;
      margin: 2px;
      padding: 2px;
     }
     .td {
      display: table-cell;
      border: 1px solid #red;
     width: 200px;
     background: #ccc;
     margin: 2px;
     padding: 2px;
     }
    </style>
    <div class="table">
     <div class="tr">
      <div class="td"><p>This is a normal div, but displays like a cell in a table!</p></div>
      <div class="td"><p>This is another table cell</p></div>
     </div>
     <div class="tr">
      <div class="td"><p>Here is a third cell, in a second row</p></div>
      <div class="td"><p>And a final cell.</p></div>
     </div>
    </div>
    
    Listing 3-8.Creating a Layout Using display: table Properties to Achieve Something that’s Very Difficult Using Alternative CSS2.1 Layout Options
    
    

    CSS 表格布局是一个非常有用的布局工具,是无数场景中的最佳选择。在 CSS3 出现之前,实现三列布局是一个很好的选择,其中各个列匹配最长列的高度,而不需要脚本或黑客。这也是一种垂直对齐内容的有用方式,而不必求助于负边距或其他类似的解决方法。但是这本书是关于 CSS3 的——让我们不要花太多时间担心display: table。您可能会遇到这种情况,作为一种潜在的布局工具,它当然不容忽视,但您阅读本书并不是为了了解基于表格的布局!

    本章的要点是 CSS 布局模块不是孤立存在的。你几乎不可能遇到一个设计不包含 CSS 布局选项的样式。成功的设计师使用最好的工具,所以在设计页面时,不要害怕调用 CSS2.1 布局模块。在设计元素中找到最适合您的特定需求的布局模块,并使用它。

    摘要

    在本章中,您已经看到了 CSS3 之前可用的布局选项的高级概述。一些基本的例子有助于解释这些选项,本章还谈到了使用这些模块的一些布局限制。设计网站时,您每天都会用到所有这些布局模块;因此,如果你的胃口被激起,你想进一步阅读,去看看涵盖 CSS2.1 的书籍。

    现在你已经准备好使用 CSS2.1 创建布局了。让我们直奔主题,开始学习新的东西:是时候探索 CSS3 布局了!

    四、CSS 多列布局

    CSS 多列布局模块提供了一个解决方案,这个方案解决了 web 设计者从 Web 诞生之初就面临的一个基本布局问题:如何排列内容,使其占据多个垂直容器,如报纸或杂志。多年来,聪明的网页设计者开发了各种变通方法来创建多栏布局。最初,这涉及到使用表格来对齐内容列,就好像每个元素都是单元格中的一个值一样。最近,浮动元素、清除元素和偶尔的 JavaScript 的巧妙组合提供了更具语义的解决方案,但这些方法都不太适合创建多栏布局。新的 CSS3 模块克服了许多与生成这种布局相关的问题,自动处理内容的流动和分发;而且浏览器支持已经相当不错了,所以今天开始使用这个模块还是相对安全的!

    Note

    虽然浏览器的支持已经很好了,但是浏览器厂商还在实现这个模块。所有常见的警告都适用!

    什么是 CSS 多栏布局模块?

    CSS 多列布局提供了一种将内容区域划分成列的解决方案,内容可以自动分页。与本书中涉及的其他全新布局模块不同,多列布局模块扩展了现有的 CSS box 模型。因为新模块建立在现有布局范例之上,所以回退是自动处理的。不理解多栏布局属性的浏览器会忽略它们,将内容区域呈现在单个栏中,而不是呈现为多个栏;见图 4-1 。

    A320135_1_En_4_Fig1_HTML.jpg

    图 4-1。

    CSS Multi-column Layout in action versus a fallback non-columnar layout in the same container

    语法和结构

    CSS 多列布局模块扩展了现有的 CSS 框模型,总共增加了十个属性。其中的每一个都提供了对内容呈现到容器中的列的方式的一个方面的控制。

    因为所有属性都影响单个容器,所以从浏览器的角度来看,该模块非常容易理解,而且更重要的是,实现起来非常简单。因此,“在野外”对这个模块的支持是极好的!如果您的用户使用他们选择的最新版本的浏览器,您的内容将以列的形式呈现,每个常用的浏览器都支持此模块。

    Note

    与任何新的 CSS3 布局模块一样,在所有浏览器和操作系统组合中进行彻底测试总是值得的。您可以在 http://caniuse.com/ 查看最新的浏览器对 CSS 多栏的支持表。

    基本概念

    CSS3 多列布局模块引入了十个可以应用于块级元素的新属性。除了控制列数、分布、宽度和分段的新属性之外,还有一些新的关键字可用于帮助控制内容跨列拆分的方式。

    使用多栏布局模块创建多栏布局非常简单。没有不必要的复杂属性需要学习;因为所有事情都发生在单个元素中,所以除了你熟悉的 CSS2.1 的规则之外,没有必要担心内容如何在容器外包装。

    仅使用这十个属性,您就可以执行以下操作:

    • 将现有的单列元素转换为多列元素
    • 内容自动跨列换行
    • 控制列填充可用空间的方式,或者通过扩展以填充容器,或者始终遵循预设大小(这对于创建响应性布局很方便)
    • 定义出现在列之间的边框和装订线宽度
    • 呈现内容,使其跨越多列,以便在需要时打破分栏布局

    关于溢出内容的呈现方式以及内容跨列分隔的方式,有一些特殊的规则。你将在本章的后面详细了解这些。

    值得一提的是 CSS 多列布局允许您做的事情列表中的第三项。开箱即用,CSS 列可以快速响应。这意味着,如果您希望针对多种不同的设备配置对内容进行定位和分页,这是一个理想的布局模块。有很多方法可以打破这种固有的响应能力,但接下来的几页将重点介绍需要注意的事项。

    CSS 列的响应特性不仅限于文本。图像也遵循分栏布局,因此通过使用典型的响应图像技术,您还可以使图片缩放以适合用于查看页面的屏幕。这是一个很好的节省时间的方法,也是值得你花时间熟悉这个模块的另一个原因。

    我希望你相信 CSS 多列布局是你布局武库中的一个有用工具。让我们深入研究一下代码,看看它是如何工作的。

    理解术语

    与本书中涉及的一些其他布局模块不同,CSS 多列布局模块使用了我们都熟悉的现有布局范例。这使得理解和开始在你的布局中使用模块变得非常容易。也就是说(以防你对列的概念不太熟悉),让我们快速了解一下列这个词在 CSS 环境中的含义。

    列是在整个容器中呈现内容的垂直划分。一个容器可以包含一列或多列,内容根据所用语言的规则从一列流向下一列。如果您用英语创作,列从左到右呈现。当内容溢出第一列时,它开始在下一列的顶部呈现。当所有的列都被使用时,根据正常的 HTML/CSS 规则,内容会溢出,尽管这可能会导致额外的列——您稍后会看到这一点。

    CSS 多列模块的好处之一是,默认情况下,容器的高度会自动计算以容纳所有内容。这很有用,也是使用该模块优于一些旧的变通解决方案的主要好处之一。开箱即用,内容还会自动在所有列之间平衡,从而产生一个令人满意的内容块,它被划分为整齐的列,以符合您的规范。

    图 4-2 展示了 CSS 多栏布局讨论中使用的不同属性。你可能会很快学会,因为它很直观;但是如果你不确定column-fillcolumn-span之间的区别,这个数字还是值得参考的。

    A320135_1_En_4_Fig2_HTML.jpg

    图 4-2。

    The terms used to talk about multi-column layouts in CSS3

    在全神贯注于理论和财产名称/价值之前,让我们看一个例子。基本多栏布局的代码如清单 4-1 所示,您可以在图 4-3 中看到一个输出示例。在接下来的几页中,我将解释这个例子中发生了什么。注意,与所有使用供应商前缀属性实现的新兴模块一样,您可能需要添加-webkit--moz-前缀来使其显示在您的浏览器中。

    A320135_1_En_4_Fig3_HTML.jpg

    图 4-3。

    The resulting appearance from the combination of HTML and CSS code in Listing 4-1, shown at normal desktop resolution of greater than 960px width

    <style>
    .multicol {
      position:    relative;
      margin:    auto;
      max-width:    960px;
      columns:    4 12em;
      column-gap:    2em;
      column-rule:    1px solid red;
    }
    .multicol p {
      padding:    0.25em;
    }
    .multicol figure {
      margin:    0;
      padding:    0;
      width:    100%;
    }
    .multicol figcaption {
      color:    #999;
      font-size:    0.7em;
    }
    .multicol img {
      width:    100%;
    }
    .multicol h1 {
      column-span:    all;
      margin:    0.25em 0;
      padding:    0;
    }
    .multicol h2 {
      margin:    0.25em 0;
      padding:    0;
    }
    </style>
    
    <article class="multicol">
      <h1>Moby Dick; Or the Whale</h1>
      <h2>by Herman Melville</h2>
      <figure>
        <img src="img/mobydick.jpg" alt="Cover of Moby Dick" />
        <figcaption>Voyage of the Pequod, illustrated by Everett Henry</figcaption>
      </figure>
      <p>Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little ... How then is this? Are the green fields gone? What do they here?</p>
    </article>
    
    Listing 4-1.HTML Markup Being Styled with CSS Multi-column Layout Properties
    
    

    这个例子真正有用的地方在于它能立即响应,正如你在图 4-4 和 4-5 中看到的,我已经缩小了浏览器窗口的宽度来模拟更小的屏幕。让我们看看这个例子的不同元素。

    A320135_1_En_4_Fig5_HTML.jpg

    图 4-5。

    The result of Listing 4-1 rendered at 320px wide—the most common smartphone resolution

    A320135_1_En_4_Fig4_HTML.jpg

    图 4-4。

    The same rendering shown with a reduced browser window width Note

    需要一些额外的非多栏布局代码来定义图 4-3 、 4-4 和 4-5 中所示的颜色、边框和印刷样式。我还删减了清单 4-1 中标记的段落内容以节省空间。

    HTML 标记

    我不需要谈论 HTML,因为您正在使用标准的语义元素作为内容的容器。使用 CSS 多列布局没有特殊的标记要求;使用此模块,任何块级元素都可以应用多个列。

    多列模型

    关于图 4-3 和清单 4-1 中所示的例子,有一些事情需要注意,特别是关于内容如何在容器中呈现。在最初的 CSS 盒模型中,元素的内容流入该元素的内容盒。CSS 多列布局引入了一种新类型的容器,它存在于内容框和实际内容之间。W3C 称之为列框(简称为 column)。内容在一个元素内自动跨列流动,以内嵌(或阅读)方向流动。在基于拉丁语的语言(如英语)中,这是从左到右的。

    列被排列成行。一行中的所有列都有相同的宽度和高度。列之间可以有间隔,这被称为列间距(或印刷术语中的装订线)。在大多数屏幕情况下,拆分成列的元素只有一行。但是,在特殊情况下,一个元素可能包含多行列。打印的文档也可以由多行组成,其中一个内容区域占据多个打印页面。在本章的后面,您将看到一个屏幕上多行的示例。

    我在解释 CSS3 多栏布局时使用 W3C 的语言。出于这个原因,当谈到应用了多列属性的容器时,我引用了multicol元素。多列(multicol)元素是其column-widthcolumn-count未被设置为auto的任何容器。如您所见,在这种情况下,我使用了一个<article>元素。为了避免混淆,我也使用multicol作为属于这个元素的类的名称。

    下一节中涉及的所有单个属性都应用于multicol元素。在 CSS3 中,不可能在单个列上设置属性和值。明确地说,这意味着您不能为某一列指定backgroundpaddingmargin

    Note

    应用于multicol元素的Paddingmargin被应用于容器,而不是它的列

    虽然您不能控制单个列,但理解浏览器呈现器将它们视为独立的块级框(就像表格单元格一样)是很重要的。每个列框充当其内容的包含块。这意味着,例如,应用于在列中呈现的段落元素的marginpadding被应用于该列的包含块的边缘。

    CSS 属性

    查看清单 4-1 和图 4-3 、 4-4 和 4-5 中所示示例的 CSS 代码,看起来不熟悉的第一段代码应该是使用了columns属性。这是为两个 CSS 属性定义值的简写(参见清单 4-2 )。

    .multicol {
     columns: 4 12em;
    }
    
    Listing 4-2.Defining the <article> with a class of multicol as Having Four Columns, Each of Width 12em
    
    

    正如我刚才提到的,columns属性是两个 CSS 属性的简写:column-countcolumn-width。在这种情况下,我已经为.multicol元素分配了四列,每列的宽度为12em。需要注意的是,浏览器不一定会完全呈现您指定的内容。如果没有足够的空间来创建四列,每列的宽度为12em,渲染引擎会删除列以使其适合。结果宽度可能不是12em,列数可能不是四列!

    这意味着当您使用 CSS 多列布局模块定义列时,您不能确定浏览器将准确呈现您直观期望的内容。这听起来像是一个糟糕的实现;但是正如您将看到的,它是该模块最强大的方面之一的基础:CSS3 多列布局在默认情况下是响应性的。

    列计数

    column-count定义一个multicol元素应该被分成的列数。正如您将看到的,规则决定了浏览器是否尊重该属性。如果未指定或设置为auto,则根据column-width属性值划分空间。

    列宽

    column-width指定了每列在multicol元素中应该占据的最小宽度。注意,我说的是最低限度,不是最终的!同样,渲染引擎遵循一系列逻辑规则来确定是否严格遵守该规则。如果未指定或设置为auto,列宽由拆分成的列数决定——根据column-count属性值。

    columns属性是组合column-countcolumn-width属性的有效快捷方式。根据您传递给columns属性的值,浏览器会以不同的方式解释您的意图,因此理解所有可能的排列很重要。我在代码清单 4-3 中借用了 W3C 的示例代码来帮助说明。

    记住这是如何工作的一个简单方法是,如果你使用单个值和一个单位,浏览器会将其解释为一个column-width值。如果省略一个单位,该值将被解释为一个column-count值。如果您不确定,请指定两个值:一个有宽度单位,一个没有计数单位。

    columns: 12em;      /* equates to column-width: 12em; column-count: auto */
    columns: auto 12em; /* equates to column-width: 12em; column-count: auto */
    columns: 2;         /* equates to column-width: auto; column-count: 2 */
    columns: 2 auto;    /* equates to column-width: auto; column-count: 2 */
    columns: auto;      /* equates to column-width: auto; column-count: auto */
    columns: auto auto; /* equates to column-width: auto; column-count: auto */
    
    Listing 4-3.Effective Longhand Version of Each of Six Property Values Assigned Using the columns Shorthand Property
    
    

    删除列和更改宽度的规则

    如前所述,浏览器的渲染引擎并不总是严格遵循您对multicol元素的宽度和总列数的定义。W3C 的 CSS3 多列布局模块规范定义了如何以及何时改变呈现意图的规则。W3C 提供了一个伪代码列表来显示要应用的逻辑。我在清单 4-4 中复制了这个;上市后可以找我翻译的规则,不用担心看不懂这段代码!

    if ((column-width = auto) and (column-count = auto)) then
        exit; /* not a multicol element */
    
    if ((available-width = unknown) and (column-count = auto)) then
        exit; /* no columns */
    
    if (available-width = unknown) and (column-count != auto) and (column-width != auto) then
        N := column-count;
        W := column-width;
        exit;
    
    if (available-width = unknown) then
       available-width := shrink-to-fit;
    
    if (column-width = auto) and (column-count != auto) then
        N := column-count;
        W := max(0, (available-width - ((N - 1) * column-gap)) / N);
        exit;
    
    if (column-width != auto) and (column-count = auto) then
        N := max(1, floor((available-width + column-gap) / (column-width + column-gap)));
        W := ((available-width + column-gap) / N) - column-gap;
        exit;
    
    if (column-width != auto) and (column-count != auto) then
        N := min(column-count, floor((available-width + column-gap) / (column-width + column-gap)))
        W := ((available-width + column-gap) / N) - column-gap;
        Exit
    
    Listing 4-4.W3C’s Pseudocode for Calculating the Width and Number of Columns According to the Values Set for the column-width and column-count Properties
    
    

    下面是我对清单 4-4 中伪代码的翻译。请注意,规则和条件是按照以下顺序进行比较和操作的:

    If the column-count and column-width properties are both either unset or set to auto, no columns are rendered. The same is true if column-count is set to auto and the width of the multicol element is unrestricted.   If the column-count and column-width properties both have values and a width hasn’t been specified for the multicol element, use the values exactly as they are specified.   If the column-count property has been set with a value other than auto and the column-width property has been set to auto, divide the available width into the number of columns specified.   If the column-width property has been set with a value other than auto, the column-count property has been set to auto, and the container has a specified width, set the number of columns to match the available space divided by the specified width of each column. This may mean the columns end up wider than specified, if the width of the multicol element doesn’t divide perfectly by the specified width of each column.   If the column-count and column-width properties have both been set with a value other than auto and the width of the multicol element has been set, look at whether the combination of width and count will fit inside the container element. If not, reduce the number of columns to match the number of times the specified width of each column will fit in the available space, and then expand the column width to fill the multicol element using the calculated column-count.

    我希望您可以看到这种方法不仅有意义,而且使 CSS3 多列布局模块非常灵活。它被设计为自动响应,同时尽可能接近地尊重指定的column-countcolumn-width属性的值。

    列间隙

    如果你关注清单 4-4 中的代码,你会发现一个我还没有讨论的新属性:column-gap. column-gap用于定义列之间的装订线宽度。图 4-3 中的例子使用了column-gap。您可以在清单 4-5 中再次看到.multicol元素的完整定义。

    .multicol {
      position:    relative;
      margin:    auto;
      max-width:    960px;
      columns:    4 12em;
      column-gap:    2em;
      column-rule:    1px solid red;
    }
    
    Listing 4-5.Stylesheet Definition for the .multicol Element, Showing the column-gap Property in Use
    
    

    column-widthcolumn-count属性不同,column-gap属性是绝对的。这意味着如果您指定了一个值,浏览器将尊重该设置,即使这意味着牺牲列。

    列规则

    属性控制是否在呈现的列之间画一条分隔线。Column-rule的工作方式与 CSS 1 和 2.1 中的border属性非常相似。事实上,与border属性一样,column-rule是三种不同属性的简写属性:

    • Column-rule-width:和border-width一样,这个属性接受一个单位的参数,比如2px,或者关键字none
    • Column-rule-style:设置要渲染的线条样式。与border-style相同的选项可用,包括dotteddashedsolid等。
    • Column-rule-color:该颜色属性可以使用浏览器支持的任何颜色模型进行设置,包括hexrgb()

    Note

    列标尺始终绘制在列间距(装订线)的正中央。

    列规则(见图 4-6 )呈现为好像该列完全被内容填充,不管这是否是真的。如果样式表定义要求平衡填充列以外的内容,这很有用,因为这有助于直观地定义列所占的空间,即使它没有内容。回想一下,使用浮动元素生成列来实现这个简单的效果是多么困难!

    A320135_1_En_4_Fig6_HTML.jpg

    图 4-6。

    The column rule in action

    分栏符

    通常,浏览器的渲染引擎决定如何以及在哪里在一个multicol元素中跨列分解内容。这在许多情况下都很有效,但是有时您可能希望控制内容的分割方式。例如,您可能想要强制内容在每个<h3>标签之前的新列中开始呈现。有三个属性可用于控制如何以及何时中断内容:break-beforebreak-afterbreak-inside

    先断后合

    此属性指定应该在应用元素之前应用分隔符。它接受以下值:auto|always|avoid|left|right|page|column|avoid-page|avoid-column。在 CSS3 多列布局的情况下,特别有趣的是columnavoid-column选项,它们确保或防止(在可能的情况下)在multicol元素中出现中断。

    中断后

    此属性指定应该在应用了分隔符的元素之后应用分隔符。它接受以下值:auto|always|avoid|left|right|page|column|avoid-page|avoid-column。在 CSS3 多列布局的情况下,特别有趣的是columnavoid-column选项,它们确保或防止(在可能的情况下)在multicol元素中出现中断。

    闯入内部

    与其他两个选项不同,break-inside控制内容在它所应用到的元素内部如何断开。它接受以下值:auto | always | avoid | avoid-page | avoid-column。在 CSS3 多栏布局的情况下,特别有趣的是columnavoid-column选项,它们确保或防止(在可能的情况下)一个multicol元素的中断。

    Note

    当分栏符拆分一个框时,该框的边距、边框和填充对拆分位置没有视觉效果。但是,分割后的利润立即生效。

    列跨度

    column-span属性允许列中的块级元素超出该列的边界。将来可能会指定要跨越的列数,就像可以应用于表格单元格的colspan属性一样,但是在 CSS3 规范中只有两个可能的值:noneall

    默认情况下,column-span设置为none。这意味着内容在列的约束内呈现。如果它被设置为all,列将在元素被渲染的地方断开。这就产生了一种效果,一个multicol元素可以包含多行列。

    图像、响应和列中的裁剪

    图像在布局中提出了一个特殊的问题,你不能绝对确定多少空间将被分配给它们的显示。有两种方法可以处理分栏布局中的图像:

    • 用图像填充列宽,放大或缩小图像以匹配可用空间。
    • 预先确定图像应该显示的大小,并根据需要环绕或裁剪图像以填充空间。

    清单 4-1 中的例子,如图 4-3 、 4-4 和 4-5 所示,使用第一个选项。使用宽度为 100%的 CSS 规则会强制图像以整列宽度呈现。这有效地提高了图像的响应性,因为它可以根据可用空间的大小进行缩放。

    另一种方法是以设定的大小呈现图像。就像任何其他块级容器一样,浮动元素在multicol元素中工作,但是被限制在呈现它们的列中的空间内。此外,如果呈现的图像占据的水平空间比列中可用的空间多,则图像会在该列的有效内容框的边缘被裁剪。这两种不同的图像渲染方法的区别如图 4-7 所示。

    A320135_1_En_4_Fig7_HTML.jpg

    图 4-7。

    Image 1 is set to 100% width, which allows it to scale to fit the column width. Image 2 uses an absolute size, forcing it to crop to the column width when the column is narrower than the image Note

    如果您希望您的图像具有响应性,请使用第一种方法,因为它使图像能够根据可用空间调整大小。

    控制如何用内容填充列

    使用 CSS3 多列布局,可以通过两种方式在列中填充内容:可以让内容在列之间平衡,也可以按顺序填充,直到内容用完。如果使用后一个选项,有可能会呈现一个或多个没有任何内容的列。

    属性提供了对浏览器使用哪种方法的控制。它接受两个可能的值:balanceauto。正如您所料,balance在所有可用的列中平等地呈现内容,auto使用顺序方法。缺省(未指定)值是balance,所以如果您没有显式地将column-fill设置为auto,浏览器会尝试呈现平衡的列填充。清单 4-6 中的代码和图 4-8 中的浏览器内结果显示了使用两个选项呈现的相同内容。

    A320135_1_En_4_Fig8_HTML.jpg

    图 4-8。

    The two different column-fill options. The first balances the content equally across the columns, and the latter fills columns sequentially

    <style>
     .multicol1 {
      columns: 3 20em;
      column-fill: balance;
     }
     .multicol2 {
      columns: 3 20em;
      column-fill: auto;
     }
    </style>
    <div class="multicol1">
     <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis risus eget urna mollis ornare vel eu leo. Nulla vitae elit libero, a pharetra augue. Sed posuere consectetur est at lobortis.</p>
     <p>....</p>
    </div>
    <div class="multicol2">
     <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis risus eget urna mollis ornare vel eu leo. Nulla vitae elit libero, a pharetra augue. Sed posuere consectetur est at lobortis.</p>
     <p>....</p>
    </div>
    
    Listing 4-6.Two Different Column-Fill Approaches
    
    

    控制列内容溢出的方式

    正如您看到的超出列边界的图像,延伸到列间隙的内容在列间隙的中间被剪切。再看一下图 4-7 中的图表,看看它是如何工作的。

    当内容超出了为一个multicol元素分配的空间时,浏览器可以根据你在 CSS 代码中使用的设置以几种不同的方式呈现。有时这可能会导致在multicol块之外呈现额外的列。理解这一点的最好方法是使用两个简单的例子。

    清单 4-7 中的代码创建了一个简单的有三列的multicol元素,并在每个段落后填充包含强制分栏符的内容。当您在 HTML 代码中添加第四个段落时,浏览器会继续执行强制换行,并创建第四列来容纳附加的段落。这被呈现在multicol元素的内容框之外,因为有足够的空间来容纳指定的三列,并且你显式地声明了一个列宽(见图 4-9 )。

    A320135_1_En_4_Fig9_HTML.jpg

    图 4-9。

    If you force a break after the end of each paragraph, adding a fourth paragraph forces an additional column to render outside the content box

    <style>
     .multicol {
      width: 60em;
      columns: 3 18em;
     }
     p {
     break-after: column;
     }
    </style>
    <div class="multicol">
     <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis risus eget urna mollis ornare vel eu leo. Nulla vitae elit libero, a pharetra augue. Sed posuere consectetur est at lobortis.</p>
     <p>Donec id elit non mi porta gravida at eget metus. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
     <p>Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Curabitur blandit tempus porttitor. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
     <p>Maecenas sed diam eget risus varius blandit sit amet non magna. Vestibulum id ligula porta felis euismod semper. Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
    </div>
    
    Listing 4-7.Example of an Extra Column Rendering Outside the Content Box
    
    

    在图 4-9 中,内容被强制插入到内嵌方向的附加列中。如果为multicol元素显式指定了高度,并且要呈现的内容量超过了可用空间,也会出现相同的效果。

    与任何块级元素一样,如果您为overflow属性指定了一个值,它就会被执行,从而能够控制是否在文档中呈现额外的列。避免生成额外列的最简单方法是不指定multicol元素的高度,并避免强制分栏。

    对于分页媒体(如打印页面)如何处理溢出的内容,也有特殊的规则。阅读 W3C 规范以获得完整的细节。

    如何使用 CSS 多栏布局

    正如您所看到的,CSS 多列布局提供了一个明智而实用的解决方案,可以像报纸一样将内容排列成列。也许该模块最大的好处是它给网页设计过程带来的工作流程的改进,使填补和变通成为过去。此外,该模块在默认情况下具有响应能力,为移动优先的设计方法提供了一个真正有用的选项,同时减少了在所有屏幕分辨率下实现有效解决方案所需的开发时间。

    CSS 多列布局是一个很棒的整体布局工具,但它也可以用来创建更小的页面内用户界面元素,例如:

    • 内容在大屏幕上排列成栏,但在移动设备上退回到单列的表单
    • 水平导航菜单,其中每个元素占据相同的水平空间是很重要的(尽管在 Flexbox 上查看第五章可以获得更好的选择!)
    • 在您事先不知道有多少内容或水平空间可用的区域呈现内容

    也就是说,CSS 多栏布局的主要目的是作为一个整体的页面布局工具,这是你可以从中获得最大好处的地方。

    浏览器支持

    浏览器对 CSS 多栏布局的支持已经很不错了。每个主流浏览器都支持至少两个版本。Internet Explorer 目前拥有最完整的实现,从版本 10 开始,当前版本提供对该规范的完全支持和部分支持。Firefox、Chrome、Safari 和 Opera 也都提供了对该规范的部分支持,而基于 WebKit 的浏览器提供了完全支持。在移动平台上,情况是相似的:所有常见的浏览器都有很好的支持,IE mobile 提供了最完整的实现。

    CSS 多列布局模块在 2011 年 4 月达到候选推荐状态,这实际上意味着它是一个完整的模块,你可以认为它是稳定的。尽管如此,CSSWG 仍在继续努力完善和进一步开发该模块。您可以在 http://caniuse.com/#feat=multicolumn .查看最新的浏览器对 CSS 多栏布局的支持

    Caution

    尽管浏览器对该模块的支持非常好,但该标准的旧实现可能包含错误或缺陷。与任何新模块一样,为了确保最佳结果,您必须在所有可能的浏览器配置中进行测试。不要假设每个浏览器都会相同地呈现你的multicol元素。

    后备选项和聚合填充

    不理解 CSS 多栏布局属性的浏览器会对每个元素使用默认值。这意味着在大多数情况下,设计为具有多列的元素会在单个列中呈现。对于许多布局来说,这并不是什么大问题,而且对于布局的渐进增强方法来说,这是一个合理的结果。如果你的布局中必须有列,不管浏览器是否支持 CSS 多列布局,使用 Modernizr 框架将允许你识别和处理不能显示 CSS 列的浏览器。您可以在 http://modernizr.com .了解更多信息

    真实世界的例子

    尽管多栏布局并不是什么新东西,但新模块带来的工作流程改进对网页设计者来说意义重大。因此,很值得探索一个真实世界的例子,看看一切是如何组合在一起的。你不会被一个全新的视觉范例所震撼,但是如果你在网络上工作过一段时间,你会欣赏代码的美丽!

    模型

    对于这个例子,我为一份虚构的在线报纸创建了一个页面设计模型。渲染输出如图 4-10 所示。本示例使用 CSS 多列布局模块呈现设计中显示的所有列,包括布局顶部的嵌套列,其中一行有三个标注。它还使用了本章中讨论的一些特性,包括column-span属性来创建有效的引用。

    A320135_1_En_4_Fig10_HTML.jpg

    图 4-10。

    A mockup for a fictional online newspaper

    HTML 标记

    这个页面的 HTML 标记非常简单。其核心是一组元素,每个元素包含一篇文章。无论用户的浏览器是否支持 CSS 多列布局,标记都可以工作。清单 4-8 显示了整个页面的 HTML 代码。

    <div id="container">
     <header>
     <hgroup>
      <h1><span>the</span>news</h1>
      <h2>Your daily news</h2>
     </hgroup>
     <nav id="primarynav">
      <ul>
      <li>News</li>
       <li>Sport</li>
       <li>Culture</li>
       <li>The Arts</li>
       <li>Business</li>
       <li>Economy</li>
       <li>Lifestyle</li>
       <li>Travel</li>
       <li>Technology</li>
       <li>Comment</li>
      </ul>
     </nav>
     </header>
     <section id="news">
     <nav id="sectionnav">
     <ul>
      <li>News</li>
      <li>US & Canada</li>
      <li>World</li>
      <li>Politics</li>
      <li>Media</li>
      <li>Education</li>
      <li>Science</li>
      <li>Entertainment</li>
      <li>Weather</li>
     </ul>
     </nav>
     <div id="pagelayout">
     <div id="mainlayout">
      <div id="callouts">
      <div class="callout1">
       <img src="img/callout1.jpg" />
       <h2>Banks in Recovery</h2>
      </div>
      <div class="callout2">
       <img src="img/callout2.jpg" />
       <h2>Weekend ideas</h2>
      </div>
      <div class="callout3">
       <img src="img/callout3.jpg" />
       <h2>New museum set to open</h2>
      </div>
      </div> <!-- End Callouts -->
      <article>
       <h2>Island boat service due to stop in September</h2>
       <figure>
        <img src="img/article.jpg" />
        <figcaption>Above: The service provides a lifeline to the local island community</figcaption>
       </figure>
      <p>Etiam porta sem malesuada magna mollis euismod. Duis mollis, est non commodo luctus, ....</p>
      <h3>Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit.</h3>
       <p>Etiam porta sem malesuada magna mollis euismod. Duis mollis, est non commodo luctus....</p>
       </article>
      </div> <!-- End Main Layout -->
      <aside>
       <div id="promoted">
        <article>
         <img src="img/promoted1.jpg" />
          <h3>Jobs of the future</h3>
          <p>Susan Hill explains why the jobs market our children will face bears no relation to today's workplace</p>
         </article>
         <article>
          <img src="img/promoted2.jpg" />
          <h3>10 amazing getaways</h3>
          <p>Our top pick of summer breaks on a budget, that offer a lot of bang for your bucks</p>
         </article>
        </div> <!-- End Promoted -->
        <div id="features">
         <h4>Features</h4>
          <ul>
           <li>
            <img src="img/featured1.jpg" />
            <h5>Rise of the cupcake</h5>
            <p>Inceptos Aenean Dolor Sit Commodo</p>
           </li>
           <li>...</li>
          </ul>
         </div> <!-- End Features -->
        </aside>
       </div> <!-- End Page Layout -->
      </section>
     </div>
    
    Listing 4-8.HTML Code for the CSS Multi-column Layout Page
    
    

    呈现列

    仅使用 CSS2.1 肯定可以实现这种布局,但是新的 CSS 多列布局模块使得维护页面上的内容更加容易,而不必调整标记或手动对内容进行分页。我将单独向您展示每一部分,以便您可以看到 CSS 多列布局模块是多么有用。

    Note

    与许多 CSS3 属性一样,在实现阶段,浏览器供应商为属性添加了前缀。我将向您展示不带前缀的代码,以保持清单的整洁。检查您的目标浏览器,看看您是否需要使用每个属性的供应商前缀版本。

    主要文章

    主要标题和文章区域遵循贯穿全书的逻辑设计模式。CSS 如清单 4-9 所示。这是实现如图 4-10 所示的柱状布局所需的全部代码。

    #mainlayout {
     max-width: 560px;
     columns: 2 250px;
     column-rule: 1px solid #999;
     column-gap: 20px;
    }
    #mainlayout article p {
     font-size: 1.1em;
     line-height: 1.7em;
    }
    #mainlayout article figure {
     width: 100%;
     margin: 0;
     padding: 0;
    }
    #mainlayout article figcaption {
     font-style: italic;
     font-size: 0.8em;
    }
    #mainlayout article figure img {
     width: 100%;
     border: 1px solid #297C21;
    }
    #mainlayout article h2 {
     color: #297C21;
     column-span: all;
     font-size: 2.2em;
     font-weight: normal;
    }
    #mainlayout article h3 {
     column-span:  all;
     padding: 10px 0px;
     border-top: 1px solid #999;
     border-bottom: 1px solid #999;
     font-weight: normal;
     color: #333;
     font-size: 1.5em;
     line-height: 1.5em;
    }
    
    Listing 4-9.CSS Code Used to Create the Main Article’s Multi-column Layout
    
    

    这段代码中的简单规则创建了在主文章区域中呈现两列所需的布局,并打破了 pullquote 的列结构。结果是在 pullquote 的上方和下方呈现一组列行。注意,代码还将column-span: all用于<h2>标记,这将跨两列呈现标题。你可以在图 4-11 中看到输出,这是在 Safari 中渲染的。

    A320135_1_En_4_Fig11_HTML.jpg

    图 4-11。

    The primary article rendered in Safari

    其他列内容

    页面上的其他列和内容很容易呈现。使用相同的原则,但值稍有不同,可以呈现顶部的标注部分。因为这个标注区域是主容器的子容器,所以首先需要跨越标注区域的两列,然后为容器设置一个3column-count,允许三个标注呈现在三列中。HTML 再次显示在清单 4-10 中,相关 CSS 显示在清单 4-11 中,结果呈现在图 4-12 中。

    A320135_1_En_4_Fig12_HTML.jpg

    图 4-12。

    The three-column callout area sitting above the two-column article, rendered in Safari

    <div id="mainlayout">
      <div id="callouts">
      <div class="callout1">
       <img src="img/callout1.jpg" />
       <h2>Banks in Recovery</h2>
      </div>
      <div class="callout2">
       <img src="img/callout2.jpg" />
       <h2>Weekend ideas</h2>
      </div>
      <div class="callout3">
       <img src="img/callout3.jpg" />
       <h2>New museum set to open</h2>
      </div>
      </div> <!-- End Callouts -->
     ...
    </div>
    
    Listing 4-10.HTML for the Callout Area
    
    
    #callouts {
     column-span: all;
     columns: 3 180px;
    }
    
    Listing 4-11.CSS Applied to the HTML in Listing 4-10, Spanning the #mainlayout Columns and Setting Up a Three-Column Layout for the Callout Area
    
    

    剩下的部分是右边较小的列区域。这以类似于主内容区域的方式呈现,但是它包括堆叠列表项和特性。相关的 HTML 代码如清单 4-12 所示。

    <aside>
     <div id="promoted">
      <article>
       <img src="img/promoted1.jpg" />
       <h3>Jobs of the future</h3>
       <p>Susan Hill explains why the jobs market our children will face bears no relation to today's workplace</p>
      </article>
      <article>
       <img src="img/promoted2.jpg" />
       <h3>10 amazing getaways</h3>
       <p>Our top pick of summer breaks on a budget, that offer a lot of bang for your bucks</p>
      </article>
      </div> <!-- End Promoted -->
      <div id="features">
       <h4>Features</h4>
       <ul>
        <li>
        <img src="img/featured1.jpg" />
        <h5>Rise of the cupcake</h5>
        <p>Inceptos Aenean Dolor Sit Commodo</p>
        </li>
        <li>...</li>
       </ul>
      </div> <!-- End Features -->
    </aside>
    
    Listing 4-12.
    Sidebar Content Area
    
    

    对于页面的这一部分,CSS 实际上非常简单。唯一需要的 CSS3 多列布局代码强制第二列成为一个新列,并首先创建这两列。重要的位如清单 4-13 所示;结果如图 4-13 所示。

    A320135_1_En_4_Fig13_HTML.jpg

    图 4-13。

    The resulting layout shows two columns in the sidebar area. Note that I’ve used a combination of image techniques in this layout, which is rendered in Safari

    #pagelayout > aside {
     max-width: 350px;
     columns: 2 160px;
     margin-left: 10px;
    }
    #pagelayout > aside img {
     width:  100%;
    }
    #features {
     break-before: column;
    }
    #features ul li img {
     clear: left;
     width: 35%;
     float: left;
    }
    
    Listing 4-13.Pertinent Bits of CSS Used to Achieve the Two-Column Layout in the Sidebar
    
    

    记住 CSS3 多栏布局是默认响应的。这意味着随着可用水平呈现空间的减少,主布局中呈现的列数也会减少。回想一下,在主文章区域中显示了一组嵌套的列。因为您没有为这些列指定最大或固定的宽度,所以它们会收缩,直到达到 220px 的最小宽度。一旦它们达到那个宽度,它们就不能再变小了;相反,浏览器在单个列中呈现内容,该列可以扩展以填充可用空间。你可以在图 4-14 中看到这个效果。

    A320135_1_En_4_Fig14_HTML.jpg

    图 4-14。

    Notice that when the browser window is pulled in to be narrower than a typical desktop resolution, the content automatically reformats to reduce the number of columns

    当以智能手机分辨率查看内容时,也会发生同样的响应性重新格式化。您可以通过将浏览器窗口拖至尽可能小的宽度来模拟这种效果。在这种情况下,一旦窗口窄于 500px,内容将再次重新格式化,在一个连续的列中显示所有主要内容,如图 4-15 所示。

    A320135_1_En_4_Fig15_HTML.jpg

    图 4-15。

    On a smartphone, the page automatically responds, rendering content in a single column layout rather than in columns side by side Note

    需要一些额外的非 CSS 多栏布局 CSS 代码来定义颜色、边框和印刷样式,如图 4-10 到 4-15 所示。

    摘要

    CSS 多列布局提供了一种非常有用的方法,可以将内容呈现为好看且易于维护的读者友好的列。这是新模块的主要优势,因为它简化了这些复杂布局的创建,使未来更新内容的速度大大加快,并且首先需要更少的黑客和变通方法来创建布局。

    浏览器支持非常好,所以这是在网络上使用的所有新 CSS3 布局模块中最安全的一个。不支持的浏览器会自动退回到单列布局。通过为各个列使用指定的宽度,布局在默认情况下也会做出响应,自动重新格式化以适应更小或更大的屏幕,而无需任何进一步的代码。

    使用像 Modernizr 这样的库,可以很容易地为不兼容的浏览器提供一组使用旧的 CSS 2.1 规范的多填充样式。但是在很多情况下,这并不是绝对必要的,因为大多数布局都没有分栏来分隔内容。

    五、CSS 灵活的盒子布局

    CSS 灵活的盒子布局模块解决了一个定位问题,这个问题是 web 设计者从 CSS 诞生的第一天起就一直在努力解决的:沿水平或垂直轴均匀地间隔元素,而不需要求助于复杂的浮动或基于脚本的技巧。这一章将更详细地介绍灵活的盒子布局模块,并展示它如何革新你设计网页的方式。

    Note

    该模块通常被称为 Flexbox,因此在本章中,我交替使用术语 Flexbox Layout 和 Flexbox 来指代该模块。

    什么是 Flexbox?

    CSS 灵活的盒子布局提供了一个为用户界面设计优化的盒子模型。使用 flex 布局模型,启用 flex 的容器的子元素可以被布置在轴上(水平或垂直),并且这些子元素可以自动增长和收缩以填充可用空间,而不会溢出父容器。Flexbox 模块的一个特别的好处是易于设置和操作子元素的对齐。这使得定位内容变得简单,同时保留了以后引入其他兄弟元素的灵活性:使用基于像素的布局的日子已经一去不复返了。

    也可以将单个 flex 容器嵌套在其他 flex 容器中。通过将垂直容器嵌套在水平容器中,您可以构建灵活的跨两个轴的布局,反之亦然。

    CSS 2.1 引入并定义了以下四种用于呈现网页的布局模式:

    • 文档的块布局
    • 文本的嵌入式布局
    • 二维网格中表格数据的表格布局
    • 定位布局,用于在页面上显式定位元素,并将其从文档流中移除

    浏览器在解析 CSS 规则时使用这些系统。这些布局模式根据元素的同级、文档中的流动和父元素来确定元素的大小和位置。

    Flexbox 引入了第五种布局模式,W3C 将其命名为 flex layout(见图 5-1 )。这种模式是专门为排列复杂的用户界面元素而设计的。Flex-layout 模式考虑了比 CSS2.1 更复杂的页面和 web 应用程序的使用场景。

    A320135_1_En_5_Fig1_HTML.jpg

    图 5-1。

    Flexbox in action, rendering a page without the need to use workarounds to achieve the layout. You build this layout at the end of this chapter

    语法和结构

    W3C CSSWG 自 2009 年第一份工作草案发布以来一直致力于 Flexbox 模块。在此期间,规范和语法发生了实质性的变化。目前的规范包括 2012 年 9 月发布的候选人推荐和 2013 年 10 月更新的编辑草案。

    一个候选推荐被认为是稳定的,并且这一个形成了本章中详细描述的语法的基础。虽然没有太大的不同,但编辑的草稿引入了一些我也提到的改进。我会指出,这里显示的语法来自编辑的草稿,而不是候选人的推荐。此外,我会让您知道浏览器目前提供的支持。

    Note

    截至 2013 年 10 月 3 日,Flexbox 模块的最新版本是基于 W3C 候选推荐标准的编辑草案。编辑的草稿是公开讨论的,可以随着时间的推移而改变。因此,语法不能被认为是稳定的。为了避免问题,请确保您使用的是最新的候选人推荐。您可以在 http://dev.w3.org/csswg/css-flexbox/ 查看当前编辑的规范草案。

    基本概念和术语

    在对 Flexbox 的介绍中,W3C 将 flex 布局描述为表面上与块布局相似,因为它们遵循相似的设计模式。我发现把 flex layout 想象成有点像 table layout 是有帮助的,因为它允许元素相对于轴对齐和调整大小,就像表格的单元格被挤压成一行一样。正如您将看到的,flex 布局实际上非常不同,尽管它确实具有块、内联和表格布局的可识别特性。

    本质上,flex 布局很简单。但是不要被骗了,以为 Flexbox 功能没那么强大,因为它很容易上手。这是一个非常通用的布局模块,允许您执行以下任务:

    • 以四种不同方向之一布局元素:从左到右、从右到左、从上到下或从下到上
    • 仅使用 CSS 重新排列元素的顺序
    • 自动调整元素大小以适应可用空间
    • 根据容器或同级元素对齐元素,实现通用的跨轴比例
    • 折叠容器内的元素,而不影响容器的偏移量
    • 创建线性单轴布局或沿横轴缠绕的多线布局

    灵活布局模式的核心是轴的概念。Flexbox 是一个二维布局工具,有两个可能的工作轴:水平,简称row;还有垂直的,简称column

    Flexbox 布局需要一个元素作为 flex 容器,以及零个或多个作为 flex 项目的子元素。这些 flex 项目使用 flex 布局模型进行布局,而父容器可以应用其他布局模型(如 float)。这意味着您可以将 flex 容器合并到您的标准 CSS 2.1 布局中,而不必改变整个结构方法。

    浏览器支持

    浏览器支持灵活的盒子布局已经很不错了。Internet Explorer 从版本 10 开始就部分支持该规范,IE11 中包含了完全支持。Firefox、Chrome、Safari 和 Opera 都至少部分支持该规范,基于 WebKit 的浏览器提供完全支持。

    在移动平台上,iOS Safari 有很好的支持,黑莓的浏览器也是如此。IE mobile 和 Android 的浏览器都有部分支持。只有 Opera Mini 目前不支持该规范。您可以在 http://caniuse.com/#search=flex 查看 Flexbox 最新的浏览器支持。

    Caution

    在灵活盒子布局模块的开发过程中,一些浏览器实现了该规范的早期版本。语法已经改变了。因此,Web 上的许多示例现在都已经过时了,所以在遵循示例代码时要小心,以确保您使用的是模块的正确版本。

    不理解 Flexbox CSS 属性的浏览器会对每个元素使用默认值。通常情况下,<div><section><article>等结构项显示为块级元素,而<span>等内联元素则恢复为默认的内联级行为。您可以利用这些信息来处理较旧的浏览器;或者,如果您想填充类似 Flexbox 的渲染,Modernizr JavaScript 库允许您测试浏览器支持。您可以在 http://modernizr.com 了解更多信息。

    方向和大小

    要完全理解 Flexbox 容器的流程方向的含义以及起点和终点在哪里,使用通用语言定义 Flexbox 模块的相关方面会有所帮助。W3C 在灵活盒子布局的候选推荐草案中已经在这方面做了很好的尝试,所以我在讨论方向和大小时使用了相同的方法。

    flex 容器的主轴是沿其放置各个 flex 项目的轴。主开始和主结束是根据页面的语言定义的,并与主尺寸的开始和结束对齐。横轴垂直于主轴延伸,并具有十字起点和十字终点。同样,这些是由交叉大小定义的。

    图 5-2 展示了我在讨论 Flexbox 时使用的不同轴和命名约定。你可能想回头参考这个图,直到你对两个轴的概念感到舒服为止。

    A320135_1_En_5_Fig2_HTML.jpg

    图 5-2。

    Terms used when talking about Flexbox dimensions and flow direction

    举个例子会让这个理论更容易理解。清单 5-1 显示了这个例子的代码。你可以在图 5-3 中看到样本输出。我将在接下来的几页中解释这是怎么回事。

    A320135_1_En_5_Fig3_HTML.jpg

    图 5-3。

    The result of combining the HTML and CSS code shown in Listing 5-1

    <section id=library">
     <article class="library-item">
      <h1>The Wonderful Wizard of Oz</h1>
      <h2>by L. Frank Baum</h2>
      <img src="img/oz.jpg" alt="Original cover of The Wonderful Wizard of Oz" />
      <button>Remove from library</button>
     </article>
     <article class="library-item">
      <h1>Pride and Prejudice</h1>
      <h2>by Jane Austen</h2>
      <img src="img/pandp.jpg" alt="Pride and Prejudice book cover" />
      <button>Remove from library</button>
     </article>
     <article class="library-item">
      <h1>Adventures of Huckleberry Finn</h1>
      <h2>by Mark Twain</h2>
      <img src="img/huck.jpg" alt="Original cover of Huckleberry Finn" />
      <button>Remove from library</button>
     </article>
    </section>
    
    <style>
    #library {
     position: relative;
     display: flex;
     flex-flow: row wrap;
    }
    .library-item {
     display: flex;
     flex-flow: column;
    }
    .library-item > img {
     order: -1;
     align-self: center;
    }
    .library-item > button {
     margin-top: auto;
    }
    </style>
    
    Listing 5-1.HTML Markup Being Styled with Flexbox CSS Properties
    
    

    Note

    需要一些额外的非 Flexbox 代码来定义图 5-3 中所示的颜色、边框和印刷样式。

    让我们来看看这个例子的不同柠檬。

    Flex 容器

    flex 容器是根据 flex 布局的规则和属性放置 flex 项目的元素。Flex 项目是 flex 容器的直接子对象。每个 flex 容器可以包含零个或多个 flex 项目,这些项目可以是显式元素,如<div><img><section><article>,也可以是一串连续的文本,Flexbox 将其视为包含在一个元素中。

    通过使用设置为值flexinline-flexdisplay属性,将元素定义为 flex 容器。display: flexdisplay: inline-flex的区别在于display: flex将容器定义为 CSS 2.1 块级项目,而display: inline-flex将容器设置为内联级元素。清单 5-2 显示了将#library部分定义为具有自己的 flex 上下文的 flex 容器的代码。

    #library {
     display: flex;
    }
    
    Listing 5-2.Defining the Library Element as a Flex Container by Assigning display: flex;
    
    

    当您使用display: flexdisplay: inline-flex定义一个 flex 容器时,您正在为该容器的内容创建一个新的 flex 格式上下文。该上下文仅影响该容器的 flex item 子元素。外部元素不会影响嵌套的弹性项目。在flex的渲染中缺乏对外部元素的感知意味着floatclear对 flex 项目没有影响。还值得注意的是,多列布局模块中的列属性对 flex 项目没有影响。

    Flex 格式上下文

    每个 flex 格式上下文都独立于其在布局中的对应部分工作。因此,对于创建完美的网格来说,Flexbox 并不是一个好的选择,在本书的后面,当我讨论一个专门为网格布局设计的模块时,你会看到这一点。这是因为单个容器允许它们的 flex 项目根据它们的大小和内容扩展或收缩,而不引用相邻 flex 容器中的 flex 项目。相比之下,基于网格的布局严格遵循特定的节拍和节奏,并考虑到相邻的元素。图 5-4 展示了三种不同的 flex 容器,每种容器都有自己的 flex 格式上下文,不关注相邻的容器。

    A320135_1_En_5_Fig4_HTML.jpg

    图 5-4。

    Flex items are sized and positioned relative to their own flex container, not flex items inside other flex containers

    展示模型

    像 flex 容器一样,flex 项目定义了自己的格式上下文。这可以使用display属性和任何 CSS 2.1 允许的值来设置。因此,您可以将伸缩项设置为float,显示inline,或者设置为table-cell。如果使用显示值flex,flex 项本身就变成了一个 flex 容器,并支持其他属性,如visibility: collapse,这将在本章后面讨论。

    Note

    如果您使用position: absoluteposition: fixed,flex 项将从 flex 格式上下文流中取出,除非leftrighttopbottom都设置了值auto。在这种情况下,这些位置属性的值是根据 flex 容器上下文中 flex 项目的静态位置计算的。

    在下一个例子中,主 flex 容器是一个<section>元素,其idlibrary。每个子元素——一个具有library-item类的<article>元素——也被设置为使用display: flex。清单 5-3 隔离相关的 CSS。

    .library-item {
     display: flex;
     flex-flow: column;
    }
    
    Listing 5-3.CSS to Define Each Flex Item in the Context of the #library Flex Container
    
    

    每个 flex 项目实际上都是一个 flex 容器,如图 5-5 所示。因此,每个条目的内容也被视为 flex 条目,但仅在父条目library-item的上下文中。

    A320135_1_En_5_Fig5_HTML.jpg

    图 5-5。

    Each flex item in the #library flex container acts as its own flex container, following a horizontal flex direction

    弯曲方向

    flex-direction用于定义一个柔性容器的主轴。回想一下,灵活盒子布局是一个二维布局模块,因此只有两个轴可供选择:

    • row:英文横。
    • column:英文竖着。

    每个轴可以向前或向后运行。定义flex-direction: row反向版本的语法是flex-direction: row-reverse;而对于flex-direction: column,是flex-direction: column-reverse

    Caution

    术语rowcolumn可能会让你分别想到水平和垂直布局,但在 Flexbox 中,这只适用于水平书写模式。在垂直语言中,如日语,row 从上到下排列内容。

    默认主轴以及flex-direction值是根据网页上使用的书写模式设置的。对于英语来说,这是从左到右,从上到下,定义为ltr。结果是使用ltr书写模式创建的网页默认为row,并且从左到右运行。设置值row-reverse使伸缩项从右向左显示。

    柔性包装

    属性控制 flex 容器是单行的还是多行的。有三种可能的值:

    • nowrap:将 flex 容器定义为单行。容器中的所有 flex 项目都适合一个线性运行,而不需要换行到两行或更多行。这是flex-wrap的默认值。
    • wrap:允许伸缩项沿横轴分布在两条或多条线上。
    • wrap-reverse:类似wrap工作,但运行方向与默认相反。

    如果通过使用值wrapwrap-reverse允许 flex 容器跨多行呈现,当没有足够的空间在一行中显示所有项目时,flex 项目会换行到第二行(或第三、第四或第五行)。对于响应式设计来说,这是一个非常有用的选项,因为它会根据容器自动对内容重新分页。

    flex-direction一样,默认的flex-wrap方向由写入模式定义。对于英语,这是从左到右,从上到下。在某些语言中,可能是从右到左,从上到下,或从上到下,从左到右。为了避免疑问,使用 HTML 元素上的langdir属性显式设置页面的语言和书写模式,如下所示:

    <html lang="en" dir="ltr">
    
    

    柔性流

    flex-flowflex-directionflex-wrap属性提供了方便的快捷方式。它允许您使用一行代码来定义这两个属性,但是它也可以在没有flex-wrap值的情况下使用,就像flex-direction一样工作。清单 5-4 使用了flex-flow,尽管因为nowrapflex-wrap的默认值,我可以省略第二个值。最终布局如图 5-6 左侧所示;右侧显示了如果我指定了wrap的话布局会是什么样子。

    A320135_1_En_5_Fig6_HTML.jpg

    图 5-6。

    Notice the difference between the nowrap and wrap values for flow-wrap

    .library-item {
     display: flex;
     flex-flow: column nowrap; /* nowrap is the default value for flex-wrap, so isn't strictly necessary here */
    }
    
    Listing 5-4.
    Flex-flow Shorthand Solution for Defining Both the flex-direction and flex-wrap Properties
    
    

    控制项目的顺序

    Flexbox 最好的特性之一是能够使用纯 CSS 控制 flex 项目的顺序。这是允许网页设计者正确区分风格和结构的一个重大进步,也给搜索引擎优化带来了好处。

    默认情况下,伸缩项沿主轴排列。通过使用order属性,您可以覆盖缺省值并指定特定项目在流中的位置。Order取整数值,较低的值呈现在较高的值之前。负值也是允许的,如清单 5-5 所示。

    .library-item > img {
     order: -1;
     align-self: center;
    }
    
    Listing 5-5.Negative Value for the order Property, Forcing the Image to Render at the Beginning of the Flow Along the Main Axisy
    
    

    让我们修改这个 CSS 代码来看看order属性的作用。清单 5-6 用粗体显示了变化。图 5-7 按照单个元素的顺序显示了结果。

    A320135_1_En_5_Fig7_HTML.jpg

    图 5-7。

    By adding specific order property values to each library-item, you can reorder them along the main axis without having to change the markup

    <style>
    #library {
     position: relative;
     display: flex;
     flex-flow: row wrap;
    }
    .library-item {
     display: flex;
     flex-flow: column;
    }
    
    .library-item:nth-child(1) {
    
     order: 3;
    
    }
    
    .library-item:nth-child(2) {
    
     order: 1;
    
    }
    
    .library-item:nth-child(3) {
    
     order: 2;
    
    }
    
    .library-item > img {
     order: -1;
     align-self: center;
    }
    .library-item > button {
     margin-top: auto;
    }
    </style>
    
    Listing 5-6.CSS Applied to the HTML Code in Listing 5-1, Updated to Include order Properties for the library-item Elements
    
    

    Note

    order属性只影响可视媒体,因此屏幕阅读器继续按照内容在标记中出现的顺序来阅读内容。在检查页面布局的可访问性时,理解这一点很重要。

    控制柔性

    也许 Flexbox 规范中最重要的部分是定义 flex 项目的大小和间距的能力。传统上,很难在一个轴上排列导航项目,以使它们以相等的间距扩展或收缩来适应主尺寸。Flexbox 通过以下flex-属性提供对这两个设计方面的完全控制:

    • flex-grow
    • flex-shrink
    • flex-basis

    这三个属性的组合可以很好地控制一个项目在没有足够的空间时是增长以填充空间还是收缩以适应空间,这是增长和收缩的基础。您马上会看到一个示例,但是让我们先依次看一下每个属性。

    灵活增长

    flex-grow属性定义了相对于同一 flex 容器上下文中的其他 flex 项,flex 项增长了多少。该值被指定为整数,默认为 1。因为该属性与上下文中的其他项目相关,如果您为一个特定项目设置值 2,则任何额外的空间都将被分割,这样,对于分配给其他 flex 项目的每 10 个像素的额外空间,flex-grow值为 2 的项目将获得 20px 的额外空间。属性flex-grow的值0防止任何可用的额外空间被给予灵活项目。

    弯曲收缩

    flex-shrink类似于flex-grow,但是决定了当 flex 项目收缩以适合 flex 容器时如何分配空间。同样,该值是一个整数,默认值为 1,并且相对于容器中的其他 flex 项。当缺少可用空间时,flex-shrink属性的值0防止伸缩项收缩。

    弹性基础

    flex-basis设置 flex 项目的初始宽度,但也可以设置为值auto,这允许浏览器根据项目的内容计算宽度。当flex-basis设置为正值或auto时,flex-growflex-shrink的基准都设置为内容周围的间距。(参见图 5-8 。)当flex-basis的值设置为0时,flex-shrinkflex-grow对项目占用的总空间进行操作。(参见图 5-9 。)

    A320135_1_En_5_Fig9_HTML.jpg

    图 5-9。

    When flex-basis is set with a value of auto or a width greater than 0, only the extra space is distributed

    A320135_1_En_5_Fig8_HTML.jpg

    图 5-8。

    When flex-basis is set with a value of 0, all the space is evenly distributed

    flex 速记属性及其特例

    您可以使用flex属性作为flex-growflex-shrinkflex-basis的简写。对于flex有一些关于默认值和省略值的特殊规则,以说明 W3C 期望设计者使用该属性的最常见方式。这些很快就会显示出来以供快速参考,但是如果您有任何疑问,请确保在使用flex属性时指定这三个值中的每一个。

    清单 5-7 显示了flex属性的语法。属性设置等同于列表后显示的单个属性。

    // Syntax flex: <flex-grow> <flex-shrink> <flex-basis>
    
    flex: 1 1 auto;
    
    // This is short-hand for each of following property:value pairs
    
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: auto;
    
    Listing 5-7.
    flex-grow, flex-shrink, flex-basis, and the Shorthand flex Properties
    
    

    三个flex-属性的组合有几种常见的使用场景,因此规范定义了一些特殊的规则,当省略了flex速记语法的单个元素或者对其应用了文本值时,可以应用这些规则。这些是从 W3C 候选推荐标准中直接分解出来的:

    • flex: 0 autoflex: initial:相当于flex: 0 1 auto,也是该属性的默认值。它根据 CSS 中定义的widthheight属性来调整 flex 项的大小。如果项目的主轴大小设置为auto,则项目的大小基于其内容。即使 flex 容器中有可用空间,该值也可以防止 flex 项目增长,但当空间不足时,它可以缩小到最小大小。
    • flex: auto:这个跟flex: 1 1 auto一样。该值根据 CSS 中定义的widthheight属性来调整 flex 项目的大小,但允许它完全灵活地扩展和收缩,以适应可用空间的大小。
    • flex: none:相当于flex: 0 0 auto。当根据 CSS 中定义的widthheight属性调整大小时,该值创建一个不灵活的 flex 项目。它类似于flex: initial,但不允许项目收缩。
    • flex: <positive-number>:这个跟flex: <positive-number> 1 0px一样。结果是一个flex-basis为 0 的灵活伸缩项,根据容器中不同伸缩项上定义的伸缩因子来分配总空闲空间的一部分。

    flex 的一个例子

    flex属性为整个 Flexbox 模块提供了一个最令人兴奋的设计机会。现在,创建既有响应性又成比例的灵活布局变得很简单。清单 5-8 展示了这种灵活性。(你会在本章末尾看到一个更深入的例子。)

    <style>
    .layout {
     display: flex;
     flex-flow: row nowrap;
    }
    section > aside {
     flex: auto;
    }
    section > article {
     flex: 2 1 auto;
    }
    aside.level1 {
     order: -1;
    }
    aside.level2 {
     order: 2;
    }
    </style>
    
    <section class="layout">
    <article class="maincontent">
      ...
     </article>
     <aside class="level1">...</aside>
     <aside class="level2">...</aside>
    </section>
    
    Listing 5-8.HTML Markup and CSS to Which the Flexbox Properties Are Being Applied
    
    

    应用于清单 5-8 中标记的 CSS 将主要内容<article>设置为占据两倍于<aside>元素的空间。所有的元素都会根据容器的大小而增减,内容也会重新排序,形成一个典型的三列布局。这种常见的布局方式如图 5-10 所示;在 Flexbox 之前,它需要浮动元素和特定的 HTML 顺序。

    A320135_1_En_5_Fig10_HTML.jpg

    图 5-10。

    The result of the combination of HTML code and CSS shown in Listing 5-8

    控制弹性项目的对齐

    扩展和收缩 flex 项目以及沿主轴和横轴对齐和调整其大小的能力是 Flexbox 最有用的方面之一。使用 CSS,您第一次可以准确地定义项目在容器中应该如何对齐,还可以确定项目之间的间距。尽管已经有了脚本解决方法,但直到现在还不可能创建一个灵活的、水平居中的导航栏。更令人印象深刻的是垂直对齐项目(或横轴)的能力。

    主轴

    在 Flexbox 中有两种不同的方法来控制沿主轴的对齐:通过marginjustify-content属性。

    边缘

    边距在 flex 项目上的工作方式与 CSS 2.1 边距在块级元素上的工作方式非常相似。如果您设置了自动边距,flex 容器中的任何可用空间都会被分配给该轴上的边距。因此,通过将margin-left: auto指定给一个 flex 项,你将它推到容器的右边(见图 5-11 ),而margin-right: auto将该项推到左边。以这种方式使用 margin 还可以防止项目增长以填充可用空间,因为所有空间都被 margin 占用了。清单 5-9 借用了 W3C 候选推荐规范中的一个例子来说明如何使用边距将一个列表项推到导航栏的右侧。

    A320135_1_En_5_Fig11_HTML.jpg

    图 5-11。

    This output is achieved with Listing 5-9

    <style>
     nav > ul {
      display: flex;
     }
     nav > ul > #login {
     margin-left: auto;
     }
    </style>
    <nav>
     <ul>
      <li><a href=/about>About</a>
      <li><a href=/projects>Projects</a>
      <li><a href=/interact>Interact</a>
      <li id='login'><a href=/login>Login</a>
     </ul>
    </nav>
    
    Listing 5-9.Using margin to Align One Item to the Main End Edge 
    
    
    调整内容

    Justify-content控制沿主轴分配给 flex 容器上下文中的 flex 项目的对齐类型。计算完任何一个marginflex后,应用justify-content属性。这对于指定了最大弹性项目宽度或项目在某种程度上不灵活的布局非常有用。Justify-content分配剩余的可用空间。

    justify-content有五种不同的可能值:

    • flex-start从 flex 容器的主起始边缘对齐项目。如果您的 flex 流从右到左水平运行,这意味着 flex 项目与容器的左侧对齐。
    • flex-end从柔性容器的主要末端边缘对齐项目。如果您的 flex 流从右到左水平运行,这意味着 flex 项目将与容器的右侧对齐。
    • center特别令人兴奋,因为它允许项目与 flex 容器的中心对齐,自动考虑所有 flex 项目占据的总主轴空间以及它们之间的任何间距。在灵活的盒子布局出现之前,这是不可能用 CSS 单独实现的。
    • space-between沿主轴均匀分布柔性项目,第一个项目与主起点对齐,最后一个项目与主终点对齐。注意,如果没有足够的空间容纳所有的 flex 项,这个值的行为与flex-start相同。
    • space-aroundspace-between相似,但在第一个项目之前和最后一个项目之后增加了一半大小的空间。剩余的项目再次平均分布在第一个和最后一个项目之间。

    图 5-12 展示了这五个选项。

    A320135_1_En_5_Fig12_HTML.jpg

    图 5-12。

    These alignment options are available with justify-content

    在多条生产线上工作

    允许 flex 容器换行的一个好处是它给你的布局带来了灵活性。例如,如果你使用 Flexbox 导航条,你可以允许单独的导航选项溢出到第二行,如果有太多的导航选项在一行上放不下的话。这将自动使你的导航栏响应不同的屏幕尺寸。

    如图 5-13 所示,最终结果可能有点不美观。但是,正如您所看到的,您可以使用flex属性来使各个导航项目占据空间。如果你给弹性项目添加一个flex: auto规则,最终结果如图 5-14 所示更加漂亮。

    A320135_1_En_5_Fig14_HTML.jpg

    图 5-14。

    The same navigation bar with flex: auto applied to the flex items

    A320135_1_En_5_Fig13_HTML.jpg

    图 5-13。

    A navigation bar with flex-wrap: wrap enabled

    横轴对齐

    除了沿主轴对齐的能力之外,Flexbox 还提供了对横轴上 flex 项目对齐的控制。您不仅可以对齐,还可以自动拉伸项目,使它们在横轴上占据相同的空间,解决了基于浮动的布局多年来一直难以解决的问题。

    有三个属性可用于控制横轴对齐:

    • align-items
    • align-self
    • align-content

    这些属性中的每一个都行使不同类型的控制,所以让我们依次来看看它们。

    对齐项目和对齐自身

    align-items和 align-self 的工作方式与justify-content类似,但它们是沿着横轴而不是主轴工作的。align-items适用于 flex 容器,而您可以在单个 flex 项目上使用 align-self。与justify-content一样,这些属性是在应用任何余量后计算的。

    以下是align-itemsalign-self的可能值:

    • flex-startflex-end的工作方式与您预期的完全一样,分别将项目对齐十字起点或十字终点边缘。
    • center根据 flex 容器沿横轴的总尺寸,沿横轴中心对齐项目。如果容器被设置为使用wrapwrap-reverseflex-flow值,允许多行,则项目沿着它们出现的行的中心对齐。
    • baseline将每个项目的基线与十字起始边缘对齐。
    • stretch沿横轴扩展项目以填充线条。这具有使每个伸缩项沿横轴占据相同空间的效果。如果您的 flex 项目设置了min-height/min-widthmax-height/max-width,这些值仍然适用于这些项目,可能会导致项目无法填充行或溢出行。stretchalign-items的默认值。
    • Autoalign-self的默认值。

    图 5-15 显示了所有不同的选项和最终布局。

    A320135_1_En_5_Fig15_HTML.jpg

    图 5-15。

    These are the alignment options for align-items and align-self

    对齐内容

    align-content 属性的工作方式与justify-content类似,但它作用于启用了wrapwrap-reverse的 flex 容器中的行,决定如何在这些行之间分配额外的空间。与justify-content一样,有几种不同的可能值,如图 5-16 所示:

    A320135_1_En_5_Fig16_HTML.jpg

    图 5-16。

    Different align-content options are available for distributing and aligning individual lines in the flex container

    • flex-start从柔性容器的十字起始边缘对齐线条。如果您的 flex 流从右向左水平延伸,这意味着线条与容器顶部对齐。
    • flex-end从柔性容器的交叉端边缘对齐项目。如果您的 flex 流从右向左水平延伸,这意味着线条与容器底部对齐。
    • center将所有行对齐横轴上 flex 容器的中心,自动考虑所有行占据的总空间以及它们之间的任何间距。
    • space-between沿十字轴均匀分布线条,第一条线条对齐十字线起点,最后一条线条对齐十字线终点边缘。注意,如果没有足够的空间容纳所有的行,这个值的行为与flex-start相同。
    • space-around在第一行之前和最后一行之后添加半个空格。剩余的线再次平均分布在第一和最后一行之间。space-around类似于justify-content
    • 拉伸会导致线条自动拉伸,并填充任何额外的可用空间。如果没有足够的空间来容纳所有的行,这个值同样呈现给flex-start

    Note

    align-content仅适用于具有多行的柔性容器。这是因为单行容器的行自动填充分配给容器的整个空间。

    折叠的项目

    您可以通过为visibility属性指定值collapse来折叠 flex 项目的可见性。这具有将 flex 项目从页面呈现中移除的效果,同时将它保留在格式化结构中。这允许折叠的项目定义 flex 容器横轴的整体比例,同时从视图中隐藏。

    这个新选项对于用户界面元素(如下拉导航菜单)特别有用,在下拉导航菜单中,只有顶级选项才会显示,直到用户选择一个项目,子项才会显示。通过继续影响横轴比例,您可以根据菜单中的最大选项自动设置菜单大小,即使这是折叠的。清单 5-10 完美地展示了这种行为。图 5-17 显示结果。

    A320135_1_En_5_Fig17_HTML.jpg

    图 5-17。

    The navigation menu with the second option opened to reveal the submenu. The widest submenu item sets the width of the overall menu container, despite being initially hidden

    <style>
    nav > ul > li {
      display: flex;
      flex-flow: column;
     }
     /* dynamically collapse submenus when not targeted */
     nav > ul > li:not(:target):not(:hover) > ul {
      visibility: collapse;
     }
    </style>
    <nav>
      <ul>
       <li id="nav-about"><a href="#nav-about">About</a>
         ...
       <li id="nav-projects"><a href="#nav-projects">Projects</a>
        <ul>
         <li><a href="...">Art</a>
         <li><a href="...">Architecture</a>
         <li><a href="...">Music</a>
        </ul>
       <li id="nav-interact"><a href="#nav-interact">Interact</a>
        ...
      </ul>
     </nav>
    
    Listing 5-10.Example from the W3C Specification, Showing a Dynamic Menu that Collapses the Visibility of Submenu Items
    
    

    如何使用灵活的方盒子布局

    到目前为止,您应该对 Flexbox 的功能和用途有了清晰的认识。它可以单独解决许多常见的布局问题,因此很容易将 Flexbox 视为所有布局需求的答案。我想阻止你屈服于这种诱惑。尽管 Flexible Box Layout 能够呈现整个页面布局,但其他布局模块是专门为整个页面布局设计的(参见这一章之前和之后的章节,了解一些很好的选项!).

    与整体页面布局相比,Flexbox 更适合单个用户界面元素。一些常见的使用场景包括:

    • 希望在两个轴上真正居中的元素
    • 需要呈现数量未知的项目的场景,例如通过内容管理系统控制的菜单
    • 您希望根据标记顺序对内容进行重新排序的页面区域(尽管其他一些布局模块也允许您这样做)
    • 隐藏当前未选择的内容的标签和内容群组
    • 表单和表单元素布局

    当然,没有什么可以阻止你使用 Flexbox 作为你的主要布局工具,但是考虑一下最适合手头任务的布局模块是值得的。

    我不能放过一个关于 Flexbox 的章节而不提供一个 Flexbox 的实际例子。下面的示例只是一个可能的使用场景,它结合了您在前面几页中看到的许多属性。如果你还不相信灵活的盒子布局模块的能力和灵活性,我敢肯定这个例子会说服你。

    真实世界的例子

    这个例子为一个虚构的房地产公司创建了一个页面设计模型,如图 5-18 所示。该示例使用 Flexbox 来呈现几个布局部分。

    A320135_1_En_5_Fig18_HTML.jpg

    图 5-18。

    A mockup for a fictional real-estate company

    HTML 标记

    这个页面需要的 HTML 标记是基本的。它遵循的模式类似于布局设计者过去使用浮动来排列设计元素时使用的模式。您可以使用 Flexbox 来创建整个页面,但是因为最好将每个模块用于其预期目的,所以本示例将重点放在页面的以下部分:

    • 导航栏
    • 大屏幕区域
    • 利益陈述

    清单 5-11 显示了页面这些部分的相关 HTML 代码。

    <!—The navigation section -->
    <nav>
     <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">Locations</a></li>
      <li><a href="#">Financing</a></li>
      <li><a href="#">Special Offers</a></li>
      <li><a href="#">About us</a></li>
      <li><a href="#">Contact Us</a></li>
      <li class="searchform"><form><input type="text" value="search" /></form></li>
     </ul>
    </nav>
    
    <!—The big icons/jumbotron section -->
    
    <section id="jumbotron">
     <article>
      <h2>Free Advice</h2>
      <p>All our impartial advice is offered completely free of charge</p>
      <img src="img/bigicon-freeadvice.png" />
     </article>
     <article>
      <h2>Discounted Removals</h2>
      <p>Once you've found your dream...
    ...</article>
    </section>
    
    <!—The badge benefits section -->
    
    <section id="benefits">
     <article>
      <h1> Looking for a beautiful new home that won't break the bank?</h1>
      <p> Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum.</p>
     </article>
     <article class="badge">
      <div>
      <h3>Quality without compromise</h3>
      <p>We have homes that suit every budget without compromising on quality</p>
     </div>
      <img src="img/badge-quality.png" />
     </article>
     <article class="badge">...
     ...</article>
    </section>
    
    Listing 5-11.HTML Code for Three Parts of the Page Suited to Flexbox Layout
    
    

    虽然使用 CSS2.1 可以实现这种布局,但使用 Flexbox,在页面上正确排列项目几乎变得微不足道。让我们单独看一下每一部分,这样你就可以看到 Flexbox 的布局是多么强大。

    Note

    与许多 CSS3 属性一样,在实现阶段,浏览器供应商会给属性添加前缀。我将向您展示不带前缀的代码,以保持清单的整洁。在支持完成之前,您需要使用每个属性的供应商前缀版本来完全支持每个浏览器。

    航行

    导航区域遵循您在清单 5-9 中看到的相同设计模式,因此这一部分的代码几乎相同。清单 5-12 显示了实现实体模型中显示的导航布局所需的所有代码!

    /* The navigation section */
    nav > ul {
      display: flex;
      flex-flow: row wrap;
     }
      nav > ul > .searchform {
      margin-left: auto;
     }
    
    Listing 5-12.Flexbox CSS Code to Create the Navigation Layout
    
    

    这段代码中的两个简单规则创建了将搜索表单推到导航区域右侧所需的布局。你可以看到图 5-19 中的输出,它是在 Chrome 30 中渲染的。

    A320135_1_En_5_Fig19_HTML.jpg

    图 5-19。

    The navigation output in Chrome

    大屏幕

    大屏幕区域(带有大图标)也很容易成形。Flexbox 可以帮助解决该领域正在进行的几件事情,例如:

    • 每个<article>大小均匀。
    • 大屏幕中每个元素的内容在两个轴上居中对齐。
    • 图像在文本之前呈现,但出现在标记中的文本之后。

    为了对这些内容重新排序,您需要将每篇文章呈现为整个 flex 容器中的一个 flex 容器,id 为#jumbotron。参见清单 5-13 。

    /* The jumbotron section */
    #jumbotron {
      display: flex;
      flex-flow: row wrap;
      align-content: stretch;
      justify-content: center;
     }
    #jumobtron article {
      display: flex;
      flex-flow: column nowrap;
      flex: 1 1 250px;
      align-content: center;
      justify-content: center;
     }
    #jumbotron article * {
      align-self: center;
    }
    #jumbotron article img {
      order: -1;
      flex: none;
    }
    
    Listing 5-13.Flexbox Code to Style the Jumbotron Section
    
    

    图 5-20 显示了结果,用 Chrome 渲染。注意<article>元素的flex250px的底部宽度。这确保了所有的<article>以相同的宽度开始,并均匀地弯曲。这也意味着当使用 960 像素的窗口时,每行可以水平放置三篇文章。

    A320135_1_En_5_Fig20_HTML.jpg

    图 5-20。

    When the window is wider than 960px, three <article>s render per row

    当窗口大小折叠或在移动设备上查看页面时会发生什么?Flexbox 的一个主要优点是它可以作为一个响应式设计工具。这段代码足够灵活,可以处理不同大小的窗口。当窗口变得更窄时,内容会重新分页,这样每行只出现两个<article>,如图 5-21 所示。

    A320135_1_En_5_Fig21_HTML.jpg

    图 5-21。

    When the window narrows, the content automatically reformats onto more lines

    当以智能手机的分辨率观看内容时,也会发生同样的事情。您可以通过将浏览器窗口拖至尽可能小的宽度来模拟这种效果。在这种情况下,一旦窗口窄于 500px,内容将再次重新格式化,每行显示一个<article>(参见图 5-22 )。

    A320135_1_En_5_Fig22_HTML.jpg

    图 5-22。

    At smartphone resolutions the content renders a single <article> per line

    福利区

    福利区域稍微复杂一些,因为左侧部分的高度是各个徽章区域的两倍。这种布局包含嵌套的 flex 容器,但是列而不是行充当主轴。这使得可以将左侧物品上的弯曲设置为徽章弯曲的两倍。参见清单 5-14 和图 5-23 中的 Chrome 输出。

    A320135_1_En_5_Fig23_HTML.jpg

    图 5-23。

    The output in Chrome

    /* The badge benefits section */
    #benefits {
     display: flex;
     flex-flow: column wrap;
     height: 260px;
    }
    #benefits article {
     flex: 2 2 260px;
     width: 318px;
    }
    #benefits article.badge {
     display: flex;
     flex-flow: row nowrap;
     flex: 1 1 130px;
    }
    #benefits article.badge img {
     order: -1;
     flex: none;
    }
    
    Listing 5-14.CSS Code for the Benefits Area
    
    

    注意文章被设置为使用flex: 2 2 260px,而article.badge使用flex: 1 1 130px。第二条规则覆盖了第一条规则,并强制所有徽章的大小保持一致。剩下的文章正好是徽章高度的两倍,其flex-growflex-shrink值为 2,而徽章值为 1。这使得<article>占据了徽章高度的两倍。

    Note

    需要一些额外的非 Flexbox CSS 代码来定义如图 5-18 到 5-23 所示的颜色、边框和印刷样式。

    摘要

    CSS 灵活的盒子布局提供了一个非常多才多艺的布局模型,非常适合创建响应用户界面元素。该模块使用基于轴的范例,它的内容可以根据通过flex-属性集定义的一些简单规则沿着轴伸缩。

    Flexbox 解决了许多布局问题,到目前为止,这些问题都需要复杂的解决方案。在一个容器中集中排列多个项目现在变得很简单,就像对齐和调整盒子大小以使它们相互匹配一样。

    浏览器支持很好,所以在网上使用 Flexbox 相当安全。大多数情况下,不支持的浏览器会自动退回到块级布局。您可以使用诸如 Modernizr 之类的库,这使得使用旧的 CSS 2.1 规范为这些浏览器提供多填充样式集变得很容易。

    六、CSS 网格布局

    CSS 网格布局为标准布局范式提供了一个明智的解决方案,自从远离基于表格的布局和采用 CSS 布局以来,标准布局范式一直是 web 设计者的挑战。

    Note

    CSS 网格布局可能是新模块中最难使用的,因为浏览器支持仍在开发中。在撰写本文时,唯一可靠的渲染供应商是微软,尽管在您阅读本书时,这种情况可能已经发生了变化。

    什么是 CSS 网格布局?

    W3C 将 CSS 网格布局模块描述为定义了一个二维布局系统,为用户界面设计进行了优化。至关重要的是,也是对布局设计者最有用的是,他们继续阐明“在网格布局模型中,网格容器的子容器可以被放置到灵活或固定的预定义布局网格中的任意位置。”我将在接下来的几页中讨论这意味着什么,但这是个好消息!

    在讨论技术方面之前,有必要反思一下在布局设计中使用网格的问题。您已经对网格系统很熟悉了,因为您每天都会遇到它们。书籍和杂志使用网格系统来创建它们的布局,使得页面上的元素看起来彼此有某种关系。你见过的每个数据表都使用完全相同的原则来帮助确保数据点正确地归属于它们的图例。事实上,可以说基于网格的布局是 Web 的第一个主要设计步骤:HTML <table>元素被用于布局而不是数据显示。

    然而,与表格不同,网格应该能够以基于布局的偏好而不是数据偏好来显示内容,这正是 CSS 网格布局规范要实现的目标。在某些方面,你可以认为它类似于 CSS Flexbox 但是在 CSS 网格布局中,不是所有的事情都发生在一个轴上,而是使用两个维度:块和行(或者,如果你喜欢,列和行)。

    当用于布局时,CSS Grid Layout 是一个非常令人兴奋的模块,它使实现灵活流畅的布局变得轻而易举,并保持页面上元素之间的指定关系。这与您在使用浮动元素或表格时可能遇到的有时不可预测和违反直觉的行为形成了鲜明的对比,尤其是在涉及压缩的设备或窗口宽度时。图 6-1 显示了网格布局的典型使用场景。

    A320135_1_En_6_Fig1_HTML.jpg

    图 6-1。

    A grid-based layout in action

    Web 上的网格布局

    W3C CSSWG 自 2012 年发布第一份工作草案以来一直致力于 CSS 网格布局模块。在此期间,规范和语法发生了实质性的变化。撰写本文时的当前规范发布于 2015 年 9 月,此处讨论的语法基于在 www.w3.org/TR/css-grid-1/ 找到的文档。

    请务必检查在您阅读时是否有更新的规范版本。尽管整体语法正在(缓慢地)向稳定发展,但模块的语法和结构可能会有一些变化。

    重申一下,该规范目前被认为是一个工作草案,这意味着在为 1.0 版本的 CSS3 网格布局确定一切之前还有几个阶段要走。你现在是在网络设计的西部,所以穿上你的牛仔靴吧!

    Note

    理解 CSS 网格布局仍在开发中是至关重要的。您可以在 www.w3.org/TR/css-grid-1/ 查看当前的工作草案规范。

    为什么要使用网格?

    为了理解为什么你会为你的布局选择一个网格系统,在你的脑海中有一个网格可能是什么样子的图片是有帮助的。W3C 使用了我在这里借用的两个场景来帮助说明 Web 上网格背后的思想和概念。

    我已经谈到了设计者对网格作为一种布局工具的固有的熟悉,但是理解 Web 工具没有提供任何有目的的解决方案来创建基于网格的布局是有用的——直到 CSS 网格布局!历史上,设计者使用表格、脚本和像素完美的浮动元素的组合来构建具有网格系统外观的布局。这对于固定宽度的布局非常有效,在这种布局中,设计者可以控制或指定最小的视口宽度。然而,随着智能手机、平板电脑和其他网络连接设备的出现,那些日子已经一去不复返了。布局需要能够适应各种各样的设备配置文件和屏幕方向。

    网格布局的基础

    CSS 网格布局就是专门为解决这个问题而设计的。在它的基础上,它允许你把可用的空间分成一系列的区域,每个区域都可以用于布局。然后,可以对特定的内容进行定位和调整大小,以占据该网格中的各个列、行和单元格。图 6-2 借用了 W3C 的示例布局来展示一个可以用 CSS 网格布局创建的基本布局。

    A320135_1_En_6_Fig2_HTML.jpg

    图 6-2。

    A typical application layout that could be achieved with CSS Grid Layout

    固有的灵活性

    CSS 网格布局背后的核心原则之一是调整布局以适应可用空间不需要额外的工作。响应式设计的好处是 CSS 网格布局的标准!让我们看看 W3C 用来解释这个概念的例子。(此后,我坚定地转向新的例子!)

    CSS 网格布局被设计成响应性工作。这意味着随着可用视口空间的定义,元素会在页面内智能地重排。图 6-3 显示了我对 W3C 例子的解释:一个游戏屏幕,在布局中有五个不同的元素。

    A320135_1_En_6_Fig3_HTML.jpg

    图 6-3。

    My interpretation of the game screen used in the W3C’s example project

    注意图 6-3 中显示内容区域划分的虚线。这些是网格线!设想的设计概要中指定了布局的一些基本目标:

    • 统计区域总是出现在游戏标题的正下方。
    • 游戏面板出现在统计数据和标题的右边。
    • 游戏标题和游戏板的顶部应该总是对齐。
    • 当游戏达到最小高度时,游戏板的底部和统计区域对齐,否则游戏板会伸展以利用所有可用的屏幕空间。
    • 得分区域应该与游戏和统计区域创建的列对齐,控件在棋盘下方居中。

    传统上,这种布局可能使用具有指定宽度和高度的绝对定位元素、浮动元素和内联元素的组合。由此产生的代码很难破译,也很容易被破解。更糟糕的是,它在不同的分辨率下通常是不可靠的。

    通过使用 CSS 网格布局,你可以实现 brief 的所有要求!您将在下一节中详细了解属性和语法;但是首先检查图 6-4 ,它显示了与图 6-3 相同的图,但是在视口中增加了宽度。清单 6-1 展示了使用 CSS 网格布局实现这种布局的一种方式。(现在还不用太担心语法是如何工作的。)

    A320135_1_En_6_Fig4_HTML.jpg

    图 6-4。

    The same layout you saw in Figure 6-3, but with additional width and height, allowing the board to grow

    <style>
    #grid {
     display: grid;
     grid-template-columns: auto minmax(min-content, 1fr);
     grid-template-rows: auto minmax(min-content, 1fr) auto
    }
    
    #title { grid-column: 1; grid-row: 1 }
    #score { grid-column: 1; grid-row: 3 }
    #stats { grid-column: 1; grid-row: 2; align-self: start }
    #board { grid-column: 2; grid-row: 1 / span 2; }
    #controls { grid-column: 2; grid-row: 3; justify-self: center }
    </style>
    
    <div id="grid">
     <div id="title">Game Title</div>
     <div id="score">Score</div>
     <div id="stats">Stats</div>
     <div id="board">Board</div>
     <div id="controls">Controls</div>
    </div>
    
    Listing 6-1.Achieving the Layout Shown in Figures 6-3 and 6-4 Using CSS Grid Layout
    
    

    请注意,通过一些额外的造型,该设计可以重新分页以适应纵向屏幕,如图 6-5 所示。您将在本章后面看到如何使用@media查询来实现这种级别的响应。

    A320135_1_En_6_Fig5_HTML.jpg

    图 6-5。

    The same layout as in Figures 6-3 and 6-4, orientated to work in portrait Note

    使用 CSS 网格布局规范有很多方法可以实现这种布局。这个例子摘自 www.w3.org/TR/css-grid-1/ 的工作草案,目的是说明网格的力量,而不是建议最佳实践。

    理解术语

    我希望你的胃口被激起。让我们继续了解这个模块是如何工作的。与每个 CSS 模块一样,CSS 网格布局也有其特有的术语和语言。它部分是由 W3C 定义的,但是大部分是从传统的图形设计和关于网格系统的讨论中发展出来的。

    任何应用了网格布局的元素都被称为网格容器。网格本身是一组相交的水平线和垂直线,将网格容器的空间分成一系列的行和列。因此,有两种类型的线:一组定义沿块轴(也称为列轴)延伸的列,另一组定义沿内嵌轴(也称为行轴)正交延伸的列。

    术语 block 和 inline 直接指的是 CSS3 Writing Modes 模块,这意味着列轴不一定是从上到下垂直的,行轴不一定是从左到右水平的。然而,对于大多数基于拉丁语的语言,这是列和行的主要经验;因此,为了理解模块如何工作,可以从这些方面考虑。图 6-6 显示了刚刚定义的术语。

    A320135_1_En_6_Fig6_HTML.jpg

    图 6-6。

    The key terms used when describing grids in context

    在开始探索定义和使用 CSS 网格布局的属性之前,您需要了解一些额外的技术语言。网格轨迹用于定义网格列或网格行。这类似于 CSS Flexbox 使用的语言,所以如果你已经读过第五章,应该听起来很熟悉。

    网格单元是每个轴上相邻的两组网格线之间的空间。网格单元是可以放置内容的区域,是网格中的最小单位。同样,这最好用图表来说明,所以请看图 6-7 ,它显示了上下文中的术语。

    A320135_1_En_6_Fig7_HTML.jpg

    图 6-7。

    The terms grid track and grid cell in context

    我们不要忘记网格线。这些是将网格划分成网格区域的线,正如你所看到的,你可以用它们运行的轴来描述它们。在 CSS 网格布局中,还可以使用数字索引或 CSS 代码中指定的名称来显式引用单独的行。

    网格项目是分配给网格中的网格区域(或网格单元)的单个元素。网格区域由两对四条网格线定义,可以跨越多个网格单元。每个网格容器包含零个或多个网格项目;网格容器的每个子元素都自动成为网格项目。

    图 6-8 显示了上下文中的网格线、网格区域、网格单元和网格项目。您会很高兴地听到,这是在您开始使用代码之前需要的最后一个与网格相关的术语!

    A320135_1_En_6_Fig8_HTML.jpg

    图 6-8。

    Grid lines, grid areas, and grid items

    在 CSS 中定义网格

    现在你知道了在 CSS 中谈论网格时应该使用什么语言;让我们直接进入规范,探索如何使用该模块建立一个网格。清单 6-2 展示了一个简单的网格定义,以及用作网格容器和网格项的 HTML 元素。你马上就会看到每一行代码做了什么,但是首先看看图 6-9 ,这是一个根据规范应该如何渲染的图示。请注意,如果您在最新版本的 Internet Explorer 或当前版本的 Microsoft Edge 之外的任何地方进行测试,您将会非常失望!这个特性最近出现在 WebKit nightlies 中,但是只有一个-webkit-前缀。

    A320135_1_En_6_Fig9_HTML.jpg

    图 6-9。

    An illustration of how the code shown in Listing 6-2 should render in the browser

    <style type="text/css">
     #gridcontainer {
     display: grid;
     grid-template-columns: 150px 1fr; /* two columns */
     grid-template-rows: 50px 1fr 50px; /* three rows */
     }
    #griditem {
     grid-column: 2;
     grid-row-start: 1;
     grid-row-end: 4;
    }
    </style>
    
    <div id="gridcontainer">
     <!-- begin the grid item -->
     <div id="griditem">
      <p>Some content or other...</p>
     </div>
     <!-- end the grid item -->
    </div>
    
    Listing 6-2.CSS and HTML Markup Defining a Grid
    
    

    图 6-9 显示了它在浏览器中呈现时的样子(或者至少是我对它应该是什么样子的说明)。我添加了一些额外的阴影,使行更清晰。

    Note

    需要一些额外的非网格代码来定义图 6-9 中所示的颜色、边框和印刷样式。

    让我们看看这个例子的不同元素。

    网格容器

    网格容器是根据网格布局的规则和属性放置网格项目的元素。通过使用设置为值gridinline-griddisplay属性,将元素定义为网格容器。清单 6-3 突出显示了用于定义网格容器的代码。

    #gridcontainer {
     display: grid;
    }
    
    Listing 6-3.Defining the gridcontainer Element as Being a Grid Container by Assigning display: grid;
    
    

    当您使用display: griddisplay: inline-grid定义一个网格容器时,您为该容器的内容创建了一个新的网格格式上下文。该上下文只影响该容器的网格项子元素。外部元素不会影响嵌套的网格项目。

    网格容器的两个显示选项

    display: griddisplay: inline-grid的区别在于display: grid将容器定义为 CSS 2.1 块级项目,而display: inline-grid将容器设置为内联级元素。如果这听起来很熟悉,那是因为您熟悉 CSS Flexible Box Layout,它使用了关于容器及其在页面流中的处理的类似方法和语法。

    定义行和列

    当使用display: griddisplay: inline-grid将一个元素作为网格容器时,默认情况下,它有一列和一行,这构成了网格容器的完整大小。这并不是非常有用,所以您可以使用grid-template-columnsgrid-template-rows属性将一个网格容器分成列和行。

    在清单 6-4 中,您可以看到如何将网格容器分成两列三行。每行或每列都是依次定义的,每行或每列定义之间用空格隔开。可以使用任何测量单位来设置值,包括fr单位,它定义了一个灵活的空间,该空间由固定大小的项目计算后剩余的空间量来确定。

    #gridcontainer {
     display: grid;
     grid-template-columns: 150px 1fr; /* two columns */
     grid-template-rows: 50px 1fr 50px; /* three rows */
     }
    
    Listing 6-4.Defining the Number of Rows and Columns in the Grid, Along with Their Proportions
    
    

    这定义了两列。第一个被设置为总是占据内嵌轴中 150 像素的空间,第二个被允许填充该轴中剩余的可用空间。

    定义了三行。第一个和最后一个都被设置为在块轴上占据 50 个像素的空间。中间一行被设置为填充该轴中剩余的可用空间。这意味着您已经有效地创建了一个流体布局,它总是在第一列的开头有一个 150px × 50px 的单元格,后面是一个流体单元格,然后是另一个固定大小的单元格。第二列再次分为三个单元格,但每个单元格在内嵌轴上都是流体,中间的单元格在两个轴上都是流体。图 6-10 更清楚地说明了这一点。

    A320135_1_En_6_Fig10_HTML.jpg

    图 6-10。

    The effect of the CSS definition of rows and columns in Listing 6-4; incorporating both fixed and fluid sizing Note

    fr单元表示可用空闲空间的一部分,但是因为这个例子在每个轴中使用了一次fr,所以它等于所有可用的空闲空间。

    The Flexible-Length fr Unit

    值得花点时间来谈谈fr单元。fr(或<flex>)单位被定义为可用空间的一部分。每个列或行的空闲空间份额可以根据 W3C 计算为列或行的<flex> * <free space> / <sum of all flex factors>.

    最简单的方法是将你在一个轴上使用的所有 fr 单元相加,然后在使用这些单元的元素之间分配空闲空间。因此,一个带有3fr的元素占用的空间是一个带有1fr单元的兄弟元素的三倍。如果只有这两个元素被定义为沿着该轴的fr单元,那么总的可用空间将被计算为分成四部分,其中三个相等的部分被分配给第一个元素,剩余的相等部分被分配给第二个元素。

    在容器内定位网格项目

    清单 6-3 对#griditem 元素应用了一些代码,将它放在第二列,占据了第 1 到第 4 行。清单 6-5 重复了这段代码,所以你可以明白我在说什么。

    #griditem {
     grid-column: 2;
     grid-row-start: 1;
     grid-row-end: 4;
    }
    
    Listing 6-5.Positioning of the 
    #griditem Element
    
    

    清单 6-5 显示了我还没有讨论的三个属性。grid-column定义网格项目应该占据的列。这里,您使用一个数字引用来定义一个项目应该位于的列,但是正如您稍后看到的,您也可以使用一个名称。

    grid-column一样,你也可以用grid-row定义一个单行来占用。然而,在这种情况下,您跨越了多行,因此您使用grid-row-startgrid-row-end来定义项目所占据的空间的开始和结束。

    您可能想知道为什么代码只定义了三列,却引用了第 4 列。答案在于你如何看待列和行。出于 CSS 网格布局的目的,每一列都由开始该列的网格线定义;行以同样的方式工作。如果有三根柱,实际上有四条柱网轴线。请看图 6-11 来看看这是怎么回事。

    A320135_1_En_6_Fig11_HTML.jpg

    图 6-11。

    There are four grid lines to define three columns

    grid-columngrid-row使用了相同的原理,但是因为每一列和每一行前面都有相同编号的网格线,所以这并不能立即看出编号系统是如何工作的。这是需要注意的,尤其是当你开始使用装订线栏和行来分隔内容区域的时候。

    清单 6-6 给出了一个例子。它总共定义了五列和三行,但目的只是将内容放入定义为宽度或高度大于 10px 的主要内容区域。

    #gridcontainer {
     display: grid;
     grid-template-columns: 150px 10px 150px 10px 150px; /* five columns */
     grid-template-rows: 150px 10px 150px; /* three rows */
    }
    
    Listing 6-6.CSS Defining Five Columns and Three Rows, Including Gutter Columns and Rows to Separate Content
    
    

    该定义的结果如图 6-12 所示;为了清楚起见,主要内容区域都用阴影表示。请注意,即使看起来只有三列两行,您也必须将间距定义为网格容器中的列。理解这一点很重要,因为如果开始使用grid-column属性定位网格项,就需要考虑这些额外的间距列。在本例中,将一个网格项放在列 2 中会导致它占用前两个主要内容列之间的 10px 空间。

    A320135_1_En_6_Fig12_HTML.jpg

    图 6-12。

    A total of five columns and three rows, with the second and fourth columns set to be 10px wide, and the second row similarly set to occupy 10px of height. This creates the effect of a gutter around the content areas shown shaded

    速记网格项目定位

    键入grid-column-startgrid-column-end会很快变得令人厌倦;但是和以前一样,CSS 有一个简化的语法来加速开发。只需使用grid-column属性指定开始和结束列(或grid-row的行),用正斜杠分隔两个值。清单 6-7 显示了应用于图 6-12 所示示例的这种简写。最终元件的位置如图 6-13 所示。

    A320135_1_En_6_Fig13_HTML.jpg

    图 6-13。

    The positioning of element #griditem when the code shown in Listing 6-7 is applied to it

    #griditem {
     grid-column: 1 / 4;
     grid-row: 1;
    }
    
    Listing 6-7.Position and Span of the #griditem Element, Spanning Three Columns and One Row
    
    

    Caution

    术语“行”和“列”可能会让你分别想到水平布局和垂直布局。但是在 CSS 网格布局中,和 Flexbox 一样,这只适用于水平书写模式。在日语等垂直语言中,row从上到下布局内容。

    使用网格区域定位

    grid-area属性使用边界网格线显式地控制网格项目的位置,而不是使用列和行的隐喻。语法如下:

    grid-area: row-start / column-start / row-end / column-end
    
    

    通过使用基于坐标的定位方法,这为在网格中放置元素提供了更快的方法。让我们修改清单 6-7 中的代码,以利用grid-area属性,而不是grid-columngrid-row属性。结果代码如清单 6-8 所示。

    #griditem {
     grid-area: 1 / 1 / 1 / 4;
    }
    
    Listing 6-8.Same Effect as in Listing 6-7, but with Significantly Less Code
    
    

    跨越多列或多行

    如果您希望 CSS 网格布局更像基于表格的布局,可以使用span属性达到同样的效果。这是通过对列数或行数求和,并分配网格项目自动占据正确的行数和/或列数来实现的。继续这个例子,清单 6-9 使用span而不是显式使用grid-areagrid-column-startgrid-column-end。终点是根据起点和跨度计算的。当您希望从视觉上跨越多个列而不是在头脑中记住数字的角度来考虑时,这是非常有用的。你需要记住的是,任何装订线栏仍然有效!

    #griditem {
     grid-column: 1 / span 3;
     grid-row: 1;
    }
    
    Listing 6-9.Same Result as Listings 6-8 and 6-9, but Using the span Keyword to Define the Grid Item’s Size Occupying Three Columns Total
    
    

    命名网格线

    如果您发现自己因为需要考虑所有多余的列和行而感到沮丧,CSS Grid Layout 允许您根据自己的需要命名各个跨度,从而为这个问题提供了一个实用的解决方案。这是非常灵活和有用的,一旦你习惯了使用命名网格线,它对于代码的易维护性和易读性有很大的实际意义。语法如下所示:

    grid-template-columns: [name-of-line1] <width> [name-of-line2]
    
    

    解释这一点最简单的方法是在上下文中展示它,所以让我们重温一下清单 6-6 中五列三行的早期定义:

    #gridcontainer {
     display: grid;
     grid-template-columns: 150px 10px 150px 10px 150px; /* five columns */
     grid-template-rows: 150px 10px 150px /* three rows */
    }
    
    

    可以通过在方括号中指定名称来命名每条网格线。清单 6-10 展示了这在实践中的样子。这些名称几乎可以是任何适合您的名称(保留关键字除外)。

    #gridcontainer {
     display: grid;
     grid-template-columns: [col1start] 150px [col1end] 10px [col2start] 150px [col2end] 10px [col3start] 150px [col3end];
     grid-template-rows: [row1start] 150px [row1end] 10px [row2start] 150px [row2end]
    }
    
    Listing 6-10.CSS from Listing 6-6, with the Sddition of Named Grid Lines
    
    

    通过命名网格线,您现在可以在定义网格项目的位置时使用这些名称而不是数字。清单 6-11 显示了来自清单 6-7 、 6-8 和 6-9 的相同网格项目,使用清单 6-10 中的名称进行定位和定义。

    #griditem {
     grid-column: col1start / col2end;
     grid-row: row1start;
    }
    
    Listing 6-11.Size and Positioning from Listings 6-7, 6-8, and 6-9, Using the Named Lines Defined in Listing 6-10
    
    

    列表 6-11 的结果如图 6-14 所示。正如您从代码中看到的,当您使用合理的命名策略并根据您对列和行的看法而不是它们相对于装订线列和行的位置来分配名称时,这要直观得多。

    A320135_1_En_6_Fig14_HTML.jpg

    图 6-14。

    The same net result as shown in Figure 6-13, but the underlying code is potentially easier to understand than earlier listings

    此外,值得指出的是,您可以继续对命名的网格线使用span关键字,从而允许进一步的布局灵活性。span继续观察每个定义的列或行,但是。

    用重复定义网格

    网格容器中网格的定义可以通过使用关键字repeat来自动完成。其语法如下:

    grid-template-columns: repeat(<number of times to repeat>, <column definitions to repeat>);
    
    

    清单 6-12 显示了一个使用中的repeat关键字的例子,它定义了一个总共有 6 列 6 行的网格容器。

    #gridcontainer {
     grid-template-column: repeat(3, 150px 10px);
     grid-template-row: repeat(2, 75px 75px 10px);
    }
    
    Listing 6-12.Defining Six Columns and Six Rows Using the repeat Keyword
    
    

    清单 6-12 中代码的结果如图 6-15 所示。同样,为了清晰起见,我给网格加了阴影。

    A320135_1_En_6_Fig15_HTML.jpg

    图 6-15。

    Six columns and six rows defined using the repeat keyword in combination with grid-template-column and grid-template-row

    您还可以使用带有关键字repeat的命名网格线,提供更大的灵活性。清单 6-13 给出了一个例子,它定义了一个网格容器和一个网格项。

    #gridcontainer {
     grid-template-column: repeat(3, [column] 150px [colgutter] 10px);
     grid-template-row: repeat(3, [row] 150px [rowgutter] 10px);
    }
    
    #griditem {
     grid-column: column 2;
     grid-row: row 1;
    }
    
    Listing 6-13.Combining the repeat Keyword with Named Grid Lines to Create a Grid, and Positioning a Grid Item Within It
    
    

    列出 6-13 的结果如图 6-16 所示。很酷吧。您可以创建一个网格系统,并在网格中定位一个项目,只需几行 CSS 代码!如果你愿意,你仍然可以使用span关键字。

    A320135_1_En_6_Fig16_HTML.jpg

    图 6-16。

    The result of Listing 6-13, with shading added for emphasis

    还有更多!repeat关键字不一定是grid-template-column属性的唯一参数,因此您可以在重复的部分之前或之后添加额外的列(或grid-template-row的行)。这允许你用最少的代码设计一个非常灵活但是精确的网格系统。清单 6-14 中显示了一个例子。另外,请注意,您不必命名每一条网格线。

    #gridcontainer {
     grid-template-column: [sidebarstart] 200px [sidebarend] 10px repeat(3, [column] 150px [colgutter] 10px);
     grid-template-row: repeat(3, [row] 150px [rowgutter] 10px);
    }
    
    Listing 6-14.Building on the Previous Example to Add a Sidebar Column Before the Repeating Section
    
    

    列出 6-14 的结果如图 6-17 所示。有一点没有明确显示出来,但是您应该知道,当重复定义导致相邻的命名网格线时,这两个名称会连接成一个名称。举个例子grid-template-column: repeat(2, [a] 20px [b])。这相当于grid-template-column: [a] 20px [b a] 20px [b];

    A320135_1_En_6_Fig17_HTML.jpg

    图 6-17。

    The result of Listing 6-14, incorporating a sidebar defined outside the repeating section of the column specification

    定义网格区域

    我已经提到了网格单元和网格区域之间的区别。一个区域由四条网格线定义:两条列线和两条行线。这些线不需要紧邻,因此一个网格区域可以包含一个或多个网格单元。网格区域对于定义页面布局不同部分之间的语义关系很有用,允许您指定页面的哪个部分包含页眉、侧栏、内容区域和页脚。使用grid-template-area属性定义区域,该属性映射到一组现有的网格轨迹定义上。清单 6-15 展示了一个这样的例子。

    <style>
    #gridcontainer {
     display: grid;
    grid-template-areas: "header header"
                         "sidebar content"
                         "sidebar content";
    grid-template-columns: 150px 1fr;
    grid-template-rows: 50px 1fr 50px;
    }
    </style>
    
    Listing 6-15.
    grid-template-area Defining a Header, Sidebar, and Content Area in the Grid That’s Already Defined by the grid-template-columns and grid-template-rows Properties
    
    

    一旦创建了网格区域,就可以通过使用grid-area属性直接分配网格项来占据这些区域;参见清单 6-16 。组合列表 6-15 和 6-16 的结果如图 6-18 所示。请注意,该图人为地分解了网格单元的位置,以使每个网格区域的边界易于识别。

    A320135_1_En_6_Fig18_HTML.jpg

    图 6-18。

    The defined grid areas. Note that I have exploded this diagram, adding extra space between the grid cells to illustrate the bounds of each area

    #item1 { grid-area: header; }
    #item2 { grid-area: sidebar; }
    #item3 { grid-area: content; }
    
    Listing 6-16.Assigning Three Items to the Three Grid Areas Defined in Listing 6-15
    
    

    控制网格项目的顺序

    正如我所展示的,您可以通过使用grid-columngrid-row属性在网格中任意定位网格项目。此功能的主要好处之一是,它允许您控制页面上元素的视觉顺序,而与它们在代码中的顺序无关。就像 Flexbox 一样,这使得重新分页内容以适应不同的设备配置文件变得容易:响应式设计变得简单。它也促进了风格和结构的分离,并带来了搜索引擎优化的好处。

    除了能够直观地定位网格项目之外,您还可以控制它们在屏幕上的呈现顺序。该功能使用 Flexbox 中可用的相同的order属性。通过使用order属性,您可以覆盖缺省值,并指定特定项目在网格呈现流中的位置。order取整数值,较低的值呈现在较高的值之前。负值也是允许的。order在绘制元素的过程中确实会影响 z-index,所以请注意,除非您专门为元素声明了 z-index 值,否则更改它的order属性将会使它在堆栈中向前或向后移动。

    自动流动的网格项目

    我还没有提到的是,如果你没有为每个条目明确指定一个grid-columngrid-row坐标,网格条目会发生什么。回想一下,默认情况下,网格容器的任何子容器都是一个网格项。没有明确定位和定义的网格项目会自动定位和调整大小,以类似于 flex 项目在 Flexbox 容器中流动的方式流入网格容器。

    默认情况下,浏览器在流动网格项目时采用阅读方向规则。在基于拉丁语的语言中,这意味着行从左到右填充整个列,直到一行填满,然后开始新的一行。为了帮助说明这一点,清单 6-17 中的代码包含一个网格容器和九个子元素。

    <style>
     #gridcontainer {
     display: grid;
     grid-template-columns: repeat (3, 150px);
     grid-template-rows: auto;
     }
    </style>
    
    <div id="gridcontainer">
     <div class="item">1</div>
     <div class="item">2</div>
     <div class="item">3</div>
     <div class="item">4</div>
     <div class="item">5</div>
     <div class="item">6</div>
     <div class="item">7</div>
     <div class="item">8</div>
     <div class="item">9</div>
    </div>
    
    Listing 6-17.Creating a Grid Container: Child Elements Become Grid Items by Default
    
    

    默认情况下,列表 6-17 的结果如图 6-19 所示。注意,使用auto关键字允许浏览器决定需要创建多少行来容纳容器中的网格项。通过使用 grid 容器元素上的grid-auto-flow属性,您可以显式地要求浏览器将项目流入行上下文。默认是row,所以显式设置这个属性的代码是grid-auto-flow : row。将该属性更改为使用值column的结果如图 6-20 所示。

    A320135_1_En_6_Fig20_HTML.jpg

    图 6-20。

    The result of Listing 6-17, but with the grid flow set to a column specifically. grid-auto-flow: column has been applied to the #gridcontainer element

    A320135_1_En_6_Fig19_HTML.jpg

    图 6-19。

    The result of Listing 6-17. Grid items are automatically flowed into the row context, although this can also be explicitly set using grid-auto-flow: row

    auto-flow 的另一个很好的特性是,它可以处理您显式放置在网格上的任何网格项目。这意味着你可以将重要元素推到它们指定的位置,然后让你的页面或应用程序中的所有其他内容自动流入周围的空间,完成布局。

    子网格

    与 Flexbox 一样,单独定义的网格容器相互之间没有渲染效果。这意味着,如果在同一个页面上有两个网格容器,那么在每个网格中呈现和放置内容时,它们不需要(也不会)相互引用。这在大多数情况下是有用的,但有时让一个网格明确引用并遵循另一个网格的比例也是有帮助的。对于这些情况,CSS 网格布局规范中提供了subgrid赋值。

    关键字subgrid指定一个网格容器元素,它是一个现有网格容器的子元素,与父网格的布局相关。因此,子栅格中的栅格轨迹观察并符合父栅格的轨迹。这有助于实现表单的完美对齐,如清单 6-18 中的示例代码所示。

    <ul>
     <li><label>Name:</label> <input name="fn">
     <li><label>Address:</label> <input name="address">
     <li><label>Phone:</label> <input name="phone">
    </ul>
    
    <style>
    ul {
     display: grid;
     grid-auto-flow: row;
     grid-template-columns: auto 1fr;
    }
    li {
     display: grid;
     grid: subgrid;
     margin: 0.5em;
     border: solid;
     padding: 0.5em;
    }
    label {
     grid-column: 1;
    }
    input {
     grid-column: 2;
    }
    </style>
    
    Listing 6-18.Defining a Grid on the <ul> Element and Again on Each <li> within the <ul>; the <li> Elements Are Defined as Subgrids, Allowing Them to Achieve Coherent Alignment with Each Other as Well as with the Overall Parent Grid Defined on the <ul>
    
    

    列表 6-18 的结果如图 6-21 所示。我使用 auto-flow 选项在父网格中沿着行轴流自动布局每个列表项。

    A320135_1_En_6_Fig21_HTML.jpg

    图 6-21。

    The result of the subgrid in action in Listing 6-18

    在这个例子中,子网格<li>项目的跨度没有被明确地设置。渲染引擎自动注意到子网格中网格单元的使用,并将其映射到父网格上,遵守在父网格上定义的网格轨迹定义。可以用与常规网格项目相同的方式定义轨迹跨度。

    显式与隐式网格

    至此,您已经专门处理了显式定义的网格,将网格项分配到预定义的网格位置。CSS 网格布局提供了动态定义网格的选项,但是,只需将网格项分配到尚未显式创建的位置。

    在这些情况下,会自动创建附加栅格轨迹。例如,如果您将一个网格容器定义为grid-template-columns: 100px 100px 100px 100px,然后应用一个网格项来占据grid-column: 5,则定位网格项所需的额外列将被创建来容纳该网格项。清单 6-17 专门使用关键字auto来请求浏览器将这种行为应用于网格行,但是,严格来说,这不是必需的。就我个人而言,我认为如果有助于避免疑问,具体甚至详细是很好的,所以我倾向于不依赖默认值或行为。什么适合自己,你可以自己拿主意!

    将项目与网格对齐

    使用应用于网格容器的align-items属性,网格项可以相对于网格对齐。align-items的可能值如下:

    • stretch:默认。扩展项目以填充单元格定义的空间。
    • start:相对于流上下文,将内容与网格单元的开头对齐。项目的大小可以容纳内容。
    • end:和start一样,但是对齐到单元格的末尾而不是开头。
    • center:将内容与网格单元格的中心对齐,根据需要扩展以填充单元格,从而容纳网格项目的内容。

    除了沿着流上下文工作的align-items,CSS 网格布局还允许跨流上下文工作的justify-items。对于这两个属性来说,相同的一组值是可以接受的,并且它们以完全相同的方式工作,或者与流动方向一致,或者与流动方向垂直。

    图 6-22 显示了align-items的四个对准选项的结果。注意,在这个例子中,流上下文是沿着列轴的,每个网格项占据了 5 行。我调整了单个项目的大小,就好像它们装满了足够的内容,可以有效地占据这五行所提供的空间的一半。

    A320135_1_En_6_Fig22_HTML.jpg

    图 6-22。

    The four alignment options

    最后,还可以选择使用justify-selfalign-self属性在每个项目的基础上设置对齐。这些属性支持相同的四个值,但是被分配给网格项而不是网格容器。

    如何使用 CSS 网格布局

    到目前为止,您应该已经清楚 CSS 网格布局是多么强大和有用了。它可以单独解决许多常见的布局问题,在许多方面,它是自 Web 诞生以来 CSS 模块设计者一直渴望的。因此,很容易把 CSS 网格布局看作是为所有布局需求提供最终解决方案。

    的确,CSS 网格布局将为经验丰富的网页设计师提供一个天堂。注意我对 will 这个词的强调!一旦我将要讨论的问题得到解决,CSS Grid Layout 将会是您的工具集的一个极好的、非常有用的补充。常见的使用场景包括:

    • 杂志风格的布局
    • Pinterest 类型的网络应用
    • 您想要从标记顺序重新排序内容的页面区域(尽管注意 Flexbox 也允许您这样做)
    • 应用程序,尤其是在使用网络视图和针对一系列设备配置文件时
    • 表单和表单元素布局

    当然,这仅仅是网格布局好处的开始。如果能够在不同的浏览器上可靠地使用 CSS 网格布局,那么目前 Web 上的许多设计都可以使用 CSS 网格布局来呈现。

    浏览器支持

    正如我在本章开始时提到的,目前浏览器对 CSS 网格布局的支持很差。微软帮助定义了该规范,并且是迄今为止唯一一家已经准备好部分工作实现并可用于在面向消费者的浏览器版本中测试的供应商,但是一旦该规范变得完全稳定,这种情况将会迅速改变。请注意,在撰写本文时,您可以在 Chrome 的金丝雀版本中访问一些当前规范。

    和以往一样,对于目前的情况,你应该参考并定期检查 http://caniuse.com/#search=grid 。维护此站点是为了提供 CSS 网格布局的最新浏览器支持的快照。

    后备选项和聚合填充

    与所有不支持的 CSS 一样,不理解 CSS 网格布局属性的浏览器会对每个元素使用默认值。这意味着,通常情况下,<div><section><article>等结构项显示为块级元素,而<span>等内联元素则恢复为默认的内联级行为。您可以利用这一点来处理较旧的浏览器,或者如果您喜欢使用众多依赖 JavaScript 来定位和调整元素大小的网格系统中的一个来进行聚合填充。请注意,由于 Flexbox 有一些共同的交叉属性,回退选项可能比您预期的更难预测。Modernizr JavaScript 库允许您测试浏览器支持;您可以在 http://modernizr.com 了解更多信息。

    摘要

    CSS 网格布局潜在地提供了所有新的到 CSS3 模块中最令人兴奋的布局选项。但是,它还不能在野外使用——除非您愿意编写大量的 JavaScript 回退和/或聚合填充。

    然而,我们正处于网格革命的风口浪尖。一旦主流浏览器提供支持,设计者将拥有一个极其灵活的布局工具,它被设计成可以快速响应。CSS Grid Layout 将解决过去 20 年来困扰设计师的许多布局难题,让我们摆脱过去必须的费力而复杂的工作。不幸的是,浏览器支持还不存在,所以在 Web 上使用 CSS 网格布局还不安全。

    七、CSS 区域布局

    CSS 区域布局使内容从一个框流到另一个框变得容易,而不必担心内容如何适合每个容器。

    Note

    此模块仍处于编辑的草稿状态,可能会有更改。请务必在 www.w3.org/TR/css3-regions/ 查看最新的 W3C 文档,了解当前语法和规范的详细信息。在Apress.com/9781430265023的图书页面上的源代码选项卡中,也可以查看这本书的代码。

    什么是 CSS 区域布局?

    CSS 区域布局为控制不同容器之间的内容流提供了一个高级解决方案。各个容器在布局中不必彼此相邻,因此很容易创建杂志风格的布局,这种布局可以灵活地适应内容的变化。

    CSS 区域布局不控制页面上元素的布局,只控制内容在元素之间流动的方式。这允许该模块与 CSS 规范中的任何布局模型一起使用。

    也就是说,通过添加一个有用的伪元素选择器,您可以使用许多属性来设置流入区域的内容的样式。我将在本章后面讨论::region()选择器和它所替代的selector方法。

    如果你现在想使用 CSS 区域布局,你面临的最大挑战是不完整的浏览器支持。Safari 和 Chrome 都提供支持,但 Chrome 默认不支持 CSS 区域布局。Internet Explorer 10 也支持 CSS 区域布局,但源内容只能来自一个iframe。当然,正如许多新的 CSS3 布局模块一样,您可以使用 polyfill 解决方案来支持所有浏览器;我将在本章的后面讨论这些选项。

    一个例子

    理解 CSS 区域布局能做什么的最简单的方法是直接跳到一个例子中。图 7-1 显示了一个有三个盒子的简单布局。使用 CSS 区域布局来控制每个框的内容,但是使用 CSS2.1 绝对定位和 CSS3 转换的组合来设置布局。

    A320135_1_En_7_Fig1_HTML.jpg

    图 7-1。

    The layout is controlled by CSS2.1 and CSS3 transformations. The content is controlled by CSS Regions Layout.

    清单 7-1 显示了用于创建这个例子的 HTML 标记。请注意,标记中有两个不同的区域:

    • 一个<article>元素中页面的文本内容
    • 不包含可呈现内容的三个<div>元素
    <body>
     <article>
      <h1>Lorem Condimentum Fringilla</h1>
      <p>Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec id elit non mi porta gravida at eget metus. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.</p>
       <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Donec sed odio dui. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Curabitur blandit tempus porttitor.</p>
       <p>Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Nullam id dolor id nibh ultricies vehicula ut id elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas faucibus mollis interdum. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
       <p>Maecenas faucibus mollis interdum. Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
       <p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Etiam porta sem malesuada magna mollis euismod. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Nullam quis risus eget urna mollis ornare vel eu leo. Nulla vitae elit libero, a pharetra augue.</p>
     </article>
     <div id="box1"><!-- no content --></div>
     <div id="box2"><!-- no content --></div>
     <div id="box3"><!-- no content --></div>
    </body>
    
    Listing 7-1.HTML Markup for the Example Shown in Figure 7-1
    
    

    使用 CSS 区域布局时,内容从一个元素(或一系列元素)流入一个或多个区域。提供内容的元素没有在浏览器中呈现,所以清单 7-1 中的<article>没有直接出现在图 7-1 所示的呈现中。

    让我们看看用来创建这个布局的 CSS 代码。清单 7-2 展示了呈现这个页面的完整样式表。你可以在 http://www.apress.com 下载这个例子以及本书中所有其他例子的源代码。

    body {
     font-family: 'Noto Sans', sans-serif;
     font-size: 62.5%;
    }
    article {
     -webkit-flow-into: article;
     -ms-flow-into: article;
     flow-into: article;
     font-size: 1.2em;
    }
    #box1, #box2, #box3 {
     -webkit-flow-from: article;
     -ms-flow-from: article;
     flow-from: article;
    }
    #box1, #box2, #box3 {
     padding: 4em;
     border: 10px solid #fff;
     position: absolute;
     width: 200px;
     height: 400px;
     background: #fff;
     box-shadow: 0px 0px 10px #999;
    }
    #box1 {
     background: #f9e719;
     top: 100px;
     left: 100px;
     -webkit-transform: rotate(-5deg);
     transform: rotate(-5deg);
    }
    #box2 {
     background: #92f919;
     top: 100px;
     left: 370px;
    }
    #box3 {
     background: #19d2f9;
     top: 120px;
     left: 640px;
     -webkit-transform: rotate(5deg);
     transform: rotate(5deg);
    }
    
    Listing 7-2.CSS Code Used in Conjunction with Listing 7-1
    
    

    这个例子使用了flow-intoflow-from属性来创建区域。id 为box1box2box3的三个<div>各自成为一个区域,而<article>元素实际上成为一个内容存储,并不直接呈现在页面上。

    在这里使用 CSS 区域布局的好处是,如果以后想要更新内容,可以简单地编辑<article>元素中的 HTML。内容将在三个定义的区域中重排,无需任何手动格式化。

    Note

    第一个例子显示了不同厂商前缀版本的flow-intoflow-from属性。其余的例子省略了这些特定于供应商的前缀版本的属性,以避免混乱。在规范完成之前,您需要在自己的代码中包含属性的前缀版本。

    浏览器支持

    CSS 区域布局是一个相当新的规范,最初由 Adobe 在 2011 年提出并推广。尽管如此,这个提议已经有了几次迭代,一些浏览器提供了相当成熟的支持。Safari 及以上版本支持厂商前缀,Chrome 也是如此(在地址栏中输入about:flags并启用实验性网络平台功能即可启用支持)。Internet Explorer 10 和更高版本也支持 CSS 区域布局,尽管源标记必须包含在一个iframe中。在本文发表时,Firefox 还没有对 CSS 区域布局的任何支持,一些从事 Firefox 工作的工程师公开表示,他们没有实现该提议的计划。这是因为 Firefox 背后的开发团队认为 CSS 区域布局规范存在问题,特别是当提议的 CSS 溢出模块处理一些类似的布局问题时。因此,在这一点上有理由相信这可能是未来发展的一个问题。

    Tip

    勾选 http://caniuse.com/#feat=css-regions 查看显示最新浏览器支持级别的表格。

    语法和结构

    CSS 区域布局的语法非常简单。只有两个主要属性:

    • flow-into
    • flow-from

    这些属性中的每一个都接受一个命名的参数,该参数在flow-into的情况下定义一个流上下文,或者在flow-from的情况下调用一个流上下文。流上下文可以被赋予任何名称,只要它以字母开头并且包含有效的 CSS 字符。

    流入

    一旦定义了流上下文,所有分配了与该分配相匹配的flow-into属性的元素都会将其内容贡献给流。它们也从页面的可视布局中删除。

    内容分配到流中的顺序由 HTML 标记的顺序决定,按时间顺序排列。清单 7-3 显示了这一点,其中三个不同的内容区域以不同于它们在标记中的位置的顺序被分配给同一个流上下文。

    <article id="article1"> <h1>Article 1</h1>
     <p>...</p>
    </article>
    <article id="article2"><h1>Article 2</h1>
     <p>...</p>
    </article>
    <article id="article3"><h1>Article 3</h1>
     <p>...</p>
    </article>
    <div id="layout"><!-- single content container --></div>
    <style>
     #article1, #article3 {
     flow-into: reorderedcontent;
    }
    #article2 {
     flow-into: reorderedcontent;
    }
    #layout {
     flow-from: reorderedcontent;
    }
    </style>
    
    Listing 7-3.Order of Content in the Flow Is Determined by the Markup Alone
    
    

    列出 7-3 的结果如图 7-2 所示。请注意,文章在输出中没有被重新排序,尽管在分配flow-into属性时,它们是按照#article1#article3#article2的顺序定义的。

    A320135_1_En_7_Fig2_HTML.jpg

    图 7-2。

    The order of content is defined by the HTML markup, not the CSS assignment to a named flow.

    在将元素分配到流中时要小心,以避免意想不到的后果,这一点很重要。以一个表格为例,可以使用清单 7-4 中所示的代码将它分配给一个流。

    table {flow-into: table-content}
    
    Listing 7-4.Moving a Table and Its Contents into a Flow Named table-content
    
    

    如您所料,该规则将文档中的所有表格移动到名为table-content的流中。除了将所有内容移动到流中之外,表本身也保持了与其他元素的分离。清单 7-5 中显示的代码只选择表中的直接子元素移动到流中。

    table > * {flow-into: table-content}
    
    Listing 7-5.Moving All Direct Children of the Table Element(s) into the Flow
    
    

    这允许文档中来自多个源表的所有表行一起呈现在单个表中。这是一个非常有用的功能。但是,请注意,它留下了作为空元素的<table>,该元素仍然呈现在文档中;因此,如果应用了样式,它们仍然会出现。

    不过,考虑一下清单 7-6 ,你会发现这种力量可能会被意外使用,带来意想不到的后果。

    table * {flow-into: table-content}
    
    Listing 7-6.Moving All Descendants of the Table Element(s) into the Flow at the Same Level
    
    

    清单 7-6 中代码的净效果是在一个平面列表中呈现所有表格的内容,而不是像表格通常呈现的那样呈现一个嵌套树。这几乎肯定不是你所期望的。

    要吸取的教训是,在处理 CSS 区域布局时,特殊性尤其重要。尽可能具体,以避免意想不到的结果。

    Note

    CSS 区域布局的另一个潜在的意外后果是,元素周围的任何空白都不会移动到流中,从而导致添加到流中的行内元素彼此相邻。

    流动来源

    属性允许任意定位的容器形成一系列区域,通过这些区域呈现内容流。图 7-3 展示了如何使用它来创建杂志风格的布局,而不需要将内容呈现到单独的容器中。

    A320135_1_En_7_Fig3_HTML.jpg

    图 7-3。

    Two named flows forming a magazine-style layout

    flow-from属性只有两个限制:

    • 命名流必须存在,并且已经使用文档中的一个或多个元素上的flow-into属性进行了定义。
    • 应用了flow-from属性的容器不能已经是区域。

    一个页面可以包含无限数量的命名流和无限数量的区域。如果定义了一个已命名的流,但该流为空,则该元素不会以可视方式呈现。值得注意的是,命名流的循环赋值也不能使用;元素不能包含具有相同命名流的flow-intoflow-from属性。

    控制断点

    当内容从文档流移动到 CSS 区域布局流上下文中时,内容在不同容器区域之间的断点由这些区域的大小决定。当内容跨多个区域流动时,这可能会产生不希望的中断。为了帮助解决这个问题,该规范定义了与flow-from一起支持的三个附加属性:

    • break-before
    • break-after
    • break-inside

    这些属性中的每一个都可以应用于 CSS 区域中呈现的任何 HTML 元素,控制跨不同区域呈现的中断。有许多不同的潜在价值:

    • auto
    • always
    • avoid
    • left
    • right
    • page
    • column
    • region
    • avoid-page
    • avoid-column
    • avoid-region

    break-beforebreak-afterbreak-inside的属性和可能值已从 CSS3 多列布局模块扩展而来,这将在第四章中讨论。我没有详尽地重复第四章的解释,而是在这里总结并强调 CSS 区域布局引入的附加选项。

    除了auto之外,每个中断选项都定义了一个特定的点,在链中的下一个区域中继续呈现之前,内容可以或不可以在该点中断。例如,leftrightpageavoid-page值仅适用于打印页面,强制内容在打印时呈现,以便内容落在左侧页面上。

    columnregionavoid-columnavoid-region值每个都允许元素在列或区域之前、之后或内部断开,或者避免这样做。region选项是 CSS 区域布局所特有的。图 7-4 显示了break-before:region选项应用于标题标签时的效果。

    A320135_1_En_7_Fig4_HTML.jpg

    图 7-4。

    s are forced to break before a region

    选择何时以及如何在页面上的区域之间分割内容可以提供对页面外观的精细控制,同时保留抽象内容的好处。默认情况下,所有 CSS 布局容器都会扩展以适应其内容,就像普通的内联 HTML 内容一样。这在处理未知数量的内容时很有用,但在目标是基于像素的布局时不太实用。图 7-5 显示了将height属性结合break-after属性应用到一个区域的效果。这个例子的源代码如清单 7-7 所示。

    A320135_1_En_7_Fig5_HTML.jpg

    图 7-5。

    The second region does not expand to fit its contents

    <article>
     <h2>This is the first heading</h2>
     <h2>This is the second heading</h2>
    </article>
    <div id="region1"><!-- empty --></div>
    <div id="region2"><!-- empty --></div>
    <style>
     article h2 {
      flow-into: overfloweg;
      break-after: always;
     }
     #region1, #region2 {
      flow-from: overfloweg;
      float: left;
      width: 10em;
      margin-right: 1em;
     }
     #region1 {  border: 1px solid #333; }
     #region2 {
      border: 1px solid #ccc;
      height: 2em;
     }
    </style>
    
    Listing 7-7.Applying a Fixed Height to the Second Region <div>
    
    

    Note

    由于break-after: always的问题,这个例子不能在 WebKit 浏览器中正确显示。

    区域碎片和溢出

    region-fragment属性提供了对命名流的最终区域行为的控制。假设你有一股水流穿过图 7-6 所示的区域。

    A320135_1_En_7_Fig6_HTML.jpg

    图 7-6。

    A simple CSS Regions Layout flow example

    region-fragment属性定义了如果内容占据的空间超过了最终区域(在图 7-6 中标记为区域 4)所能容纳的空间,该如何呈现内容。region-fragment有两个可能的值:

    • auto
    • break

    auto允许溢出的内容作为最终区域的一部分进行渲染。break从最后一个区域移除溢出的内容,就像有另一个区域要流入一样。

    这和overflow: hidden不一样,它保留了区域内的内容,但隐藏了溢出的内容。图 7-7 结合overflow: hidden显示了两个可能值之间的差异。请注意,region-fragment并不影响最终区域的大小,因此它对调整大小以容纳内容的区域没有任何影响(也就是说,在本例中没有设置height属性)。

    A320135_1_En_7_Fig7_HTML.jpg

    图 7-7。

    Examples of how different region-fragment options render in the browser

    因为 CSS 区域布局不处理用于呈现内容的元素的位置或布局,所以理解区域根据应用的布局属性呈现区域片段是很重要的。例如,如果将 CSS 灵活盒子布局与 CSS 区域布局结合使用,内容可能会在水平轴上溢出,而不是在垂直轴上溢出。

    新的区域样式方法

    如果你还记得本章的介绍,我说过 CSS 区域布局不处理内容看起来的样子——只处理它如何流动。这是事实,但不是全部。

    新的::region()伪选择器允许在特定区域呈现的流中的内容上设置视觉特征。这些可视属性大部分是内联的,不会影响文档流,但有些会影响块级呈现。清单 7-8 中显示了使用::region()选择器的语法。

    <region-element>::region(selector) {
     // styles
    }
    
    Listing 7-8.Syntax to Assign Rules to Content Rendering in a Specific Region Element
    
    

    清单 7-9 展示了一个真实世界使用场景的例子,它选择了#region1中从流中呈现的所有段落,并应用了2emmargin-right

    #region1::region(p) {
     margin-right: 2em;
    }
    
    Listing 7-9.Applies a Right Margin of 2em to All <p> Elements Rendered from the Flow in #region1
    
    

    不幸的是,目前很少有浏览器支持 CSS 区域布局规范的这一部分。

    旧区域样式方法

    当 CSS 区域布局的原始规范在 2011 年起草时,它要求一个选择器方法,允许以类似于@media查询的方式设计区域中的内容。虽然这已经被::region()取代了,但是 Web 上的很多例子都在继续使用这种语法,三种支持良好的浏览器(Safari、Chrome 和 Internet Explorer)都支持较老的方法。

    @media一样,@region使用一个参数来选择应用一组样式的区域。清单 7-10 显示了基本语法。

    @region #region1 {
     p {
       margin-right: 2em;
     }
    }
    
    Listing 7-10.Example Syntax for the Now-Deprecated @region Selector Method
    
    

    这个例子使用旧的语法重新创建了清单 7-9 中的例子。CSS 选择 ID 为region1的区域,并将2emmargin-right应用于其中呈现的任何段落。

    我建议您避免对生产网站使用这种语法;但是在本文发表时,浏览器对::region()的支持是不存在的。相比之下,Safari 和 Chrome 对@region的支持都不错。您需要自己决定是使用旧的还是新的语法,或者完全避免使用它。

    可用选择器

    不是每个 CSS 属性都可以应用到用::region()@region选择的元素。可以分配的属性如下:

    • font属性
    • color
    • opacity
    • background
    • word-spacing
    • letter-spacing
    • text-decoration
    • text-transform
    • line-height
    • alignment和对齐属性
    • border
    • border-radius
    • border-image
    • margin
    • padding
    • text-shadow
    • box-shadow
    • box-decoration-break
    • width

    CSS 区域布局的视觉特征

    CSS 区域布局对于如何在页面上设置区域样式或位置没有任何限制。该模块可以很好地与所有的 CSS2.1 和 CSS3 布局方法结合使用,因此您可以将 CSS 区域布局与 CSS 多栏布局、CSS 网格布局、CSS 灵活盒子布局以及浮动和绝对定位元素结合使用。

    多填充选项

    正如您所看到的,浏览器对 CSS 区域布局的支持并不像是通用的,而且这在不久的将来也不太可能改变。作为一个网页设计师,这是看到新的 CSS 模块被开发时最令人沮丧的方面之一;我们都渴望尝试新功能,但它们还没有准备好迎接黄金时间。

    作为 CSS 区域布局的主要支持者,Adobe 开发了一种 polyfill,在尚未采用该提议的浏览器中为大部分规范提供支持。可以从 http://adobe-webplatform.github.io/css-regions-polyfill/ 下载 polyfill 源代码。除了使用–adobe-作为 CSS 区域布局代码的前缀之外,您可以完全按照打印的内容使用本章中显示的代码示例。

    真实世界的例子

    如前所述,CSS 区域布局对页面设计中的元素布局没有影响。它可以与本书中讨论的任何其他 CSS 布局模块一起使用。因此,我没有提供其中一个模块的示例,而是结合了 Adobe 为这个简单示例提出的另一个新模块:CSS Shapes。

    CSS 形状模块在第十章中有进一步的讨论,所以我在这里不做详细介绍,但是它是一个有趣的,虽然有点古怪的例子,说明 CSS 区域布局如何帮助解决特殊的布局问题。图 7-8 显示了在 Adobe Illustrator 中创建的一个模型:一个简单的杂志风格的布局,其中两个文本区域完美地围绕着一个吉他图像。此示例使用 CSS 区域布局呈现内容,以便内容自动流经两个文本框和 CSS 形状,从而创建包含文本的框。

    A320135_1_En_7_Fig8_HTML.jpg

    图 7-8。

    A mockup of a magazine-style layout, created in Adobe Illustrator

    HTML 标记

    这个页面所需的 HTML 标记非常简单。您有一个页面容器,它本身有两个文本框。清单 7-11 显示了页面的 HTML 代码,并包含了取自维基百科关于该主题的文章的文本内容。

    <div id="container">
     <div id="title"><h1><span>the development of</span> <br />The Gibson Les Paul</h1></div>
     <div id="box1"><!-- left side of the guitar --></div>
     <div id="box2"><!-- right side of the guitar --></div>
    </div>
    <article id="content">
     <p> The Gibson Les Paul was the result of a design collaboration between Gibson Guitar Corporation and the late jazz guitarist and electronics inventor Les Paul. In 1950, with the introduction of the radically innovative Fender Telecaster to the musical market, solid-body electric guitars became a public craze (hollow-body electric guitars have more acoustic resonance but are, therefore, more prone to amplifier feedback and have less natural note duration "sustain".) In reaction, Gibson Guitar president Ted McCarty brought guitarist Les Paul into the company as a consultant. Les Paul was a respected innovator who had been experimenting with guitar design for years to benefit his own music. In fact, he had hand-built a solid-body prototype called "The Log", a design widely considered the first solid-body Spanish guitar ever built, as opposed to the "Hawaiian", or lap-steel guitar. This guitar is known as "The Log" because the solid core is a pine block whose width and depth are a little more than the width of the fretboard; conventional hollow guitar sides were added for shape (Image 2), a design similar to the popular Gibson ES-335 semi-hollowbody guitar introduced in 1958\. Although numerous other prototypes and limited-production solid-body models by other makers have since surfaced, it is known that in 1945–1946, Les Paul had approached Gibson with "The Log" prototype, but his solid body design was rejected.[8][9]</p>
     <p>In 1951, this initial rejection became a design collaboration between the Gibson Guitar Corporation and Les Paul. It was agreed that the new Les Paul guitar was to be an expensive, well-made instrument in Gibson's tradition.[10] Although recollections differ regarding who contributed what to the Les Paul design, it was far from a market replica of Fender models. Founded in 1902, Gibson began offering electric hollow-body guitars in the 1930s, such as the ES-150; at minimum, these hollow-body electric models provided a set of basic design cues for the new Gibson solid-body, including a more traditionally curved body shape than offered by competitor Fender, and a glued-in ("set-in") neck, in contrast to Fender's bolt-on neck.</p>
     <p>The significance of Les Paul's contributions to his Gibson guitar design remains controversial. The book "50 Years of the Gibson Les Paul" limits Paul's contributions to two: advice on the trapeze tailpiece, and a preference for color (stating that Paul preferred gold as "it looks expensive", and a second choice of black because "it makes your fingers appear to move faster on the box", and "looks classy―like a tuxedo").[11]</p>
     <p>Additionally, Gibson's president Ted McCarty states that the Gibson Guitar Corporation merely approached Les Paul for the right to imprint the musician's name on the headstock to increase model sales, and that in 1951, Gibson showed Paul a nearly finished instrument. McCarty also claims that design discussions with Les Paul were limited to the tailpiece and the fitting of a maple cap over the mahogany body for increased density and sustain, which Les Paul had requested reversed.</p>
    </article>
    
    Listing 7-11.HTML Code for the Magazine-Style Layout Page (Content from Wikipedia)
    
    

    CSS 形状和 CSS 区域布局代码

    如前所述,我不打算解释这个例子中的 CSS 形状代码;你可以在书的后面读到更多关于这个提议的内容。清单 7-12 显示了创建形状和区域的 CSS 代码。和正文一样,吉他图像来自维基百科。

    #container {
     position: relative;
     margin: auto;
     width: 960px;
     height: 1200px;
     background: transparent url(guitar.jpg) no-repeat bottom left;
    }
    #container h1 {
     position: absolute;
     top: 300px;
     left: 50px;
     font-weight: 100;
     font-size: 2.2em;
     text-transform: uppercase;
     margin: 0;
     padding: 0;
    }
    #container h1 span {
     font-size: 0.5em;
     text-transform: none;
    }
    article {
     -webkit-flow-into: article;
     flow-into: article;
    }
    #box1, #box2 {
     -webkit-flow-from: article;
     flow-from: article;
    }
    
    #box1 {
     position: absolute;
     top: 385px;
     left: 50px;
     width: 390px;
     height: 600px;
     overflow: hidden;
     -webkit-shape-inside: polygon(0% 0%, 100% 0%, 100% 36%, 70% 50%, 80% 70%, 50% 100%, 0% 100%, 0% 0%);
    }
    
    #box2 {
     position: absolute;
     top: 400px;
     right: 50px;
     width: 420px;
     height: 600px;
     overflow: hidden;
     -webkit-shape-inside: polygon(3% 0%, 5% 50%, 28% 50%, 20% 68%, 35% 85%, 45% 100%, 100% 100%, 100% 0%, 0% 0%);
    }
    
    Listing 7-12.CSS Used to Render Both CSS Regions Layout and CSS Shapes
    
    

    Note

    这个例子只能在 Chrome(启用了实验特性)或 WebKit 的夜间版本中正确呈现。

    结果呢

    图 7-9 显示了清单 7-11 中的 HTML 和清单 7-12 中的 CSS 的结果,以启用实验特性的 Chrome 呈现。这不是对我的原始模型的完美再现,但通过一些额外的特定于地区的内容样式,这将是一个非常接近的匹配。

    A320135_1_En_7_Fig9_HTML.jpg

    图 7-9。

    The result of the code in Listings 7-11 and 7-12, rendered in Chrome

    摘要

    CSS 区域布局在设计者在页面上放置内容框的方式上提供了一个飞跃,从元素的表现中抽象出元素的内容。这开启了一系列潜在的令人兴奋的新布局可能性。

    不幸的是,通用浏览器支持还有很长的路要走,特别是考虑到 Firefox 似乎不太可能在不久的将来实现这一提议。聚合填充选项可以在没有本机支持的浏览器中提供功能,但与任何解决方法一样,这些功能依赖于脚本(用户可以禁用脚本)。在未来的某个时候,CSS 区域布局可能会在 web 设计者的工具箱中扮演重要角色,但目前它只是对未来的一个令人兴奋的一瞥。

    八、支持旧浏览器

    网络的一个基本原则是有许多不同的设备类型,包括尖端、最新的智能手机、平板电脑和笔记本电脑,以及较旧的企业桌面系统。这对于整个互联网的民主来说是很棒的,但是它给网页设计者带来了头痛,特别是当我们都热衷于采用最新的标准并在我们的页面中充分利用它们的时候。

    当你正在为一个网站设计一个新的布局,并且想要采用一个 CSS3 布局模块时,这个问题留给你什么?如何在使用新模块的同时,避免让旧浏览器的用户无法阅读页面?

    幸运的是,在大多数情况下,可以采用一种渐进的增强方法(见图 8-1 )来支持这些旧的、过时的浏览器;通过应用一个不需要任何新布局模块就能工作的核心基本布局,您可以将好的东西放在上面。理解新模块的浏览器会遵守增强的规则,不理解的浏览器会忽略它们,坚持核心的后备布局。

    A320135_1_En_8_Fig1_HTML.jpg

    图 8-1。

    A useful article on the A List Apart web site, found at http://alistapart.com/article/understandingprogressiveenhancement , that explains the concept of progressive enhancement in detail Tip

    定期检查你的访问者统计数据,并做出明智的决定,决定投入多少精力来支持旧的浏览器,这是非常值得的。如果仍然运行 Internet Explorer 8 的人每年只访问你 5 次,那么是时候停止花费精力让你的网站为该浏览器服务了!

    当别无选择时

    尽管渐进式改进在许多情况下都有效,但它并不总是支持旧浏览器问题的令人满意的解决方案。有时项目要求你必须采用一种布局,如果没有对特定 CSS 模块或范例的某种程度的支持,这是不可能的。

    在这种情况下,有一种替代方法,它与渐进式增强一起工作,要么以编程方式在旧浏览器中构建对模块的支持,要么使用脚本或黑客来解决缺乏支持的问题。这种处理旧软件不足之处的方法被称为多填充。

    维基百科将聚合填充描述为“可下载的代码,它提供了不是内置于网络浏览器中的工具。它实现了开发人员期望浏览器本身提供的技术,提供了一个更加统一的 API 环境。例如,早于版本 8 或 9 的 Internet Explorer 版本不支持 HTML5 的许多功能,但如果网页安装了 polyfill,则这些网页可以使用这些功能。用于描述处理不支持浏览器的类似方法的相关术语包括 shiv 和 shim。然而,不管您如何命名该方法,基本前提是相同的。JavaScript 通常用于询问浏览器对特定功能的支持,如果不支持,它要么提供 CSS 挂钩以允许替代样式(在渐进增强的情况下),要么以伪本机遵守标准的形式提供工作区支持。

    实现现代化

    在本章的学习过程中,您将会看到,有许多不同的多填充解决方案和多填充方法可供使用,但它们都依赖于使用某种方法来检测浏览器对特定功能的支持,并在发现缺乏支持的情况下,提供一种替代方法。这种方法的基础是特征检测,也许最著名的工具是 Modernizr 库(见图 8-2 )。

    A320135_1_En_8_Fig2_HTML.jpg

    图 8-2。

    The Modernizr web page: http://modernizr.com

    Modernizr 是一个 JavaScript 库,允许您使用特性检测来确定用于访问您的网站的浏览器是否可以呈现特定类型的内容或支持特定的特性。该库通过一系列测试来检查浏览器中的支持。例如,如果您正在使用 CSS 转场,您可以测试浏览器渲染这些转场的能力,如果浏览器不处理动画,则提供一个后备或替代方案。

    Modernizr 允许您编写条件 CSS 和 JavaScript 来根据用户 web 浏览器的功能定制您的网站体验。对于整个 CSS 规范来说,这是一种有用的技术,但是在这种情况下,它特别方便,因为您可以测试对新布局模块的支持。

    该库安装快捷,使用简单。当加载带有 Modernizr 的页面时,会创建一个包含测试结果的 JavaScript 对象,并将 CSS 类添加到<html>元素中,允许您通过脚本或 CSS 检查特定的特性是否受支持。

    正如我提到的,您可以对特性支持进行测试。这可能会让您想知道具体可以运行哪些测试,以及 Modernizr 支持哪些特性。这个库之所以如此有用和受欢迎,是因为它几乎是浏览器功能支持测试的一站式商店。Modernizr 允许您测试 40 多种下一代功能,包括font-facergba、CSS 动画、渐变、画布、HTML5 音频和视频、本地存储和 WebGL。最重要的是,它可以用来测试本书中讨论的 CSS3 布局模块!

    这个库不会强迫你为每一个特性运行测试;Modernizr 的一大优势是它的模块化特性。你只需要测试你需要的特性,而不是必须进行每个单独的特性测试(见图 8-3 )。

    A320135_1_En_8_Fig3_HTML.jpg

    图 8-3。

    Customizing the Modernizr library to suit the specific tests required for a given project THREE ALTERNATIVE METHODS TO TEST FEATURE SUPPORT IN BROWSERS

    在服务器上

    如果您担心依赖 JavaScript 来识别浏览器特性,您可以使用服务器端嗅探来代替。这种方法使用浏览器的user agent属性在页面被发送到浏览器之前将特定于浏览器的类注入到html元素中。请注意,这与任何类型的浏览器嗅探都有相同的潜在问题:它不能很好地伸缩。

    条件注释

    解决浏览器缺陷的另一个潜在解决方案是使用条件注释来有选择地加载样式表和脚本。这种方法通常用于 IE6 和 IE7,并允许根据版本号和供应商进行加载,尽管支持仅限于 Internet Explorer。

    @支持

    CSS3 被提议的新特性之一是@supports方法。这让您可以编写浏览器呈现特定 CSS 属性能力的条件测试,其工作方式类似于@media查询。具有讽刺意味的是,@supports最大的问题是缺乏浏览器支持。

    现代化的替代方案

    需要强调的是,Modernizr 并不是唯一一个解决浏览器中缺失支持的解决方案。事实上,Modernizr 本身只是询问浏览器是否支持特定的特性,并相应地更新 DOM 以指明哪些特性支持哪些特性不支持。

    与网络上的任何图书馆一样,在你最喜欢的搜索引擎中做一点研究是值得的,因为形势正在迅速变化(见图 8-4 )。使用 Modernizr 的一个好处是,由于它被广泛采用,bug 修复往往会定期发布。

    A320135_1_En_8_Fig4_HTML.jpg

    图 8-4。

    More than 20,000 results when searching for a polyfill for CSS Multi-columns Layout Note

    在创作您的页面时,我再怎么强调在网上查找最新最好的 polyfill 解决方案的重要性也不为过。当你读到这本书的时候,情况已经足够多变,可能会有许多新的解决方案在现有的基础上有所改进。

    夜明珠

    YepNope 挂钩到特定 Modernizr 测试的结果,并使用它们将资源加载到浏览器中(参见图 8-5 )。这非常有用:如果您能够将代码分成单独的部分,那么添加的 YepNope 允许您有条件地加载脚本和样式表。

    A320135_1_En_8_Fig5_HTML.jpg

    图 8-5。

    The YepNope download page at http://yepnopejs.com

    因为它只有在 Modernizr 测试运行之后才会被调用,所以您可以根据浏览器特性支持有条件地加载脚本和样式,从而避免在每个浏览器中加载所有的解决方案。只有那些需要多填充物的人才能得到它们。当与本章稍后描述的预构建 polyfill 解决方案结合使用时,Modernizr with YepNope 几乎为您在生产网站中实现 CSS3 布局模块时所面临的许多兼容性问题提供了一个拖放式解决方案。

    请注意,在撰写本文时,YepNope 已经停止使用,因为 Modernizr 已经更新,包含了足够的功能,使 YepNope 加载程序不再必要。如果您使用的是 Modernizr 的最新版本,几乎可以肯定您不再需要 YepNope,但我在这里提到了它,以防您在企业环境中坚持使用旧版本。

    Tip

    选择 http://caniuse.com 查看显示浏览器对单个 CSS 布局模块支持的最新级别的表格。

    使用 Modernizr 的示例

    让我们快速地看一个 polyfill 的例子,它使用 Modernizr 为不支持您正在使用的模块的旧浏览器提供类似 CSS3 的支持。这个例子使用 CSS3 多列布局模块设计了一个简单的无序列表,将列表的内容分布在一系列列中。在大多数现代浏览器中,这不需要任何供应商前缀或特殊的变通方法。查看 http://caniuse.com/#feat=multicolumn 了解最新的浏览器支持。请注意,Internet Explorer 8 和 9 不提供对此模块的任何支持。

    该项目

    首先,用一些非常基本的样式生成一个 HTML 文档,以创建一个简单的多列布局。你可以在清单 8-1 中看到代码,在图 8-6 中看到 Safari 的输出。

    A320135_1_En_8_Fig6_HTML.jpg

    图 8-6。

    Output of Listing 8-1 in Safari on a Mac

    <!DOCTYPE HTML>
    <html>
     <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
       <title>Multicol Polyfill Example</title>
       <style>
        body {
         font-family: arial, helvetica, sans-serif;
         font-size: 62.5%;
         background: #fff;
         color:#333;
         }
         article {
         background: #eee;
         position: relative;
         padding: 20px;
         width: 920px;
         margin: auto;
    }
         article h1 {
         font-size: 2em;
    }
         article ul {
         columns: 3;
         }
         article ul li {
         list-style: none;
         font-size: 1.2em;
         padding: 5px;
    }
    
      </style>
     </head>
     <body>
     <article>
     <h1>Things that I like</h1>
     <ul>
       <li>Coffee</li>
       <li>Tea</li>
       <li>The Java Jive</li>
       <li>Lazy Sunday mornings</li>
       <li>A good book</li>
       <li>Nights at the movies</li>
       <li>The smell of baking bread</li>
       <li>Smiling</li>
       <li>Old-fashioned jazz and blues</li>
       <li>A freshly-made bed</li>
       <li>Hugs</li>
      </ul>
     </article>
    </body>
    </html>
    
    Listing 8-1.Code to Achieve a Three-Column Layout with the CSS Multi-column Layout module
    
    

    如您所见,代码通过将 CSS 代码columns: 3添加到样式表,将规则应用到ul元素,创建了一个基本的三列布局。这适用于除 Internet Explorer 8 和 Internet Explorer 9 之外的所有常用浏览器。然而,你不能绝对保证用户只能使用常用的浏览器。为了确保不支持 CSS 多列布局的浏览器用户也能看到呈现为三列的列表,您可以使用 Modernizr 来测试支持,如果没有找到支持,则使用 polyfill 来呈现列。

    聚合填料

    这是一个非常基本的布局,因此您不需要任何花哨或壮观的东西来解决缺乏浏览器支持的问题。您可以使用专门为呈现多列内容而构建的多列填充:多列多列填充,您可以在 https://github.com/hamsterbacke23/multicolumn-polyfill 找到并下载。

    在使用这个脚本之前,您需要确保在您的页面上安装并激活了 Modernizr。向页面的<head>部分添加一行代码,以调用 CDN 托管版本的 Modernizr 库,如清单 8-2 所示。

    <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     <title>Multicol Polyfill Example</title>
    <script src="jquery.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
     <style>
      body {
       font-family: arial, helvetica, sans-serif;
       font-size: 62.5%;
       background: #fff;
       color: #333;
      }
    
    Listing 8-2.Adding a CDN-Hosted Version of the Modernizr Library
    
    

    现在您已经在页面上安装了 jQuery 和 Modernizr 库,您可以使用一个简单的 JavaScript 测试来检查浏览器是否支持 CSS 多列布局模块。将它添加到代码中紧接在结束的</body>标签之前,如清单 8-3 所示。

      <li>Hugs</li>
      </ul>
      </article>
      <script src="polyfill/multicolumn.js"></script>
      <script>
       if (!Modernizr.csscolumns) {
         $('article ul').multicolumn();
       }
       </script>
     </body>
    </html>
    
    Listing 8-3.Test and Polyfill in Action 
    
    

    这一额外代码的结果是,如果浏览器没有通过多列支持的 Modernizr 测试,则加载 polyfill。polyfill 使用浮动元素跨列呈现内容,并隐藏原始容器。就这么简单明了。

    这个特定的示例解决了一个非常简单的多填充布局问题,但是无论您的需求变得多么复杂,同样的原则也适用。分解每个元素和聚合填充就是识别功能、测试支持,然后为这些布局元素提供备用方案。注意,不保证支持特定的浏览器。这取决于您选择的特定聚合填充,如 IE9 没有使用前面的示例呈现列所示。

    Note

    在撰写本文时,Modernizr 正在经历一个新的大版本。您可以复制并粘贴特定的测试代码,而不是下载或安装整个库,这些代码特定于您想要检查的特性。请务必访问 Modernizr 网站以获得该库的最新版本。

    预建多孔填料

    有时,现成的聚合填充解决方案无法满足您的特定需求,在这种情况下,您可能会发现自己需要构建自己的脚本,以提供功能来替代缺少的支持。然而,在大多数情况下,简单地使用 Modernizr、YepNope 和一个预构建的 polyfill 脚本就足够了。还要注意,还有其他不使用 Modernizr 的选项。

    为了让您对涵盖布局模块的现有聚合填充的范围有所了解,以下是从 Modernizr 博客(其中有一个广泛的选项列表)中借用的一个略加整理的列表。要查看完整列表,请访问注释中的链接:

    Note

    有关本书中每个布局模块特定的 polyfills 的完整列表,请参考 Modernizr 在 https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills 发布的关于该主题的博客文章。

    摘要

    虽然当新功能出现时,人们很容易被冲昏头脑,特别是在标准实现速度非常慢的 Web 上,但是不要忽视支持旧浏览器的需要,这一点很重要,因为旧浏览器在访问您的网站的用户中占很大比例。在许多情况下,聚合填充为提供支持提供了一个实用的解决方案。如果由于技术或资源原因,这样做不切实际或不可能,那么采用渐进式增强方法可以提供一种有用的替代方法,确保您的内容易于访问且用户友好。

    随着浏览器支持的改进和用户更新他们的系统以利用最新的软件,polyfills 应该会变得不那么流行。但是就目前而言,当你想使用本书中讨论的布局模块之一,并且不能控制观众的操作系统和设备配置文件时,它们是值得使用的。

    不要忘记通过你最喜欢的搜索引擎定期检查新的和改进的 polyfills。全世界有才华的 web 开发人员都在不断构建解决方案,以解决通用浏览器中尚未实现的模块问题。

    九、加速工作流:CSS 库和框架

    从事网页设计需要大量的重复工作:虽然每个页面都是独一无二的,但是大部分底层代码都依赖于相同的核心原则和构建模块。CSS3 引入的布局模块为许多不同的布局范例提供了一个整洁的解决方案,但是当你一遍又一遍地设计本质上相同的布局时,它们可能会变得不必要的复杂。在使用核心构建块时,您如何减少时间和复杂性开销?通过使用 CSS 库和框架,您可以简化布局过程,抽象一些复杂性,并提供一个一致、快速的开发平台。

    您很可能熟悉许多这样的框架和库;它们不是新的,也不局限于 CSS3 布局模块。一些最受欢迎的网站是建立在开源框架之上的,这些框架是由 Twitter、微软、苹果和脸书背后的开发团队开发的。例如 Bootstrap,它提供了一种简单的解决方案,以响应方式创建许多布局元素,几乎适用于所有可能的设备。这些框架都倾向于去除与基础 CSS 代码的直接联系,使得开发成为将适当的结构和 CSS 类应用于页面结构中的单个元素的情况。

    许多库和框架处理的不仅仅是布局。内置的许多功能还允许您以一致的方式制作小部件和按钮以及样式副本和标题。这可能有好处,但是如果你只想能够使用一套预定义的风格进行设计,你就不会有这本书在你的手中!这一章向你介绍了一些最好的 CSS3 布局库和框架,特别关注于保持样式的工作在你的控制之下。不可避免地,你会找到一个你喜欢的,你会坚持下去。有必要定期查看网络,看看在线社区开发了哪些新的框架(例如,见图 9-1 ),因为环境是如此的不稳定,事情可能会变化得非常快。

    A320135_1_En_9_Fig1_HTML.jpg

    图 9-1。

    There are many web sites dedicated to showcasing CSS3 libraries and frameworks, such as SpeckyBoy ( http://speckyboy.com/2014/06/02/css-libraries-frameworks-tools/ ) Tip

    一旦你找到了你喜欢的图书馆,花时间去了解它的细微差别会在以后带来巨大的回报。但是不要坐以待毙,接受你已经找到了库/框架选项的顶峰。货比三家是值得的!

    不要从头开始

    库和框架有多种形式。有些是全功能的网站开发工具,充当页面布局、设计实现和内容样式的脚手架。其他人采取更结构化的方法,提供构建模块,并从美学的角度处理页面上的元素。

    这两种方法各有优缺点,但它们有一个共同的目标:加速页面的开发,使代码更容易实现一致性。您不需要从头开始设计每个新页面:相反,通过调用合适的库,您可以使用其他人的工作来减少重复工作。

    开发人员和设计人员倾向于找到他们喜欢的工具并坚持使用。当您使用特定的库或框架时,这会带来好处,因为随着您对特定代码库的方法越来越熟悉,您可以充分利用它所提供的优势。忠于一个工具也有它的缺点,尤其是因为看不到其他可用的工具,您可能会错过其他地方提供的增强功能和能力。因此,我鼓励您尝试许多不同的库和框架,并不断进行采样。

    经常反对使用其他开发人员代码的一个论点是,您可能会依赖于该供应商的意愿和能力来消除 bug 并提供更新和修订。学习每个特定代码库的细微差别也需要时间投入。我想让你相信,前期的一点投资可以在未来带来巨大的时间(和金钱)收益。

    另一个值得讨论的问题是跨浏览器的可操作性,这也是库和框架倾向于缓解的一个问题,而您对此不必太担心。尽管(幸运的是)一些最糟糕的 CSS 实现差异已经成为过去,但是对于规范中的各个模块应该如何集成,仍然存在不同的解释。对于新兴的模块来说尤其如此,比如你在本书中看到的那些。通过使用一个库,你可以在图 9-2 中看到一个例子,你可以消除提供厂商前缀版本选择器的不确定性。这意味着你有更多的时间花在整体布局上,而不是浪费时间去弄清楚为什么一个特定的浏览器不像其他浏览器那样实现你的设计。

    A320135_1_En_9_Fig2_HTML.jpg

    图 9-2。

    The YAML webpage, found at http://www.yaml.de

    同样,与这种好处相反的是,库有时会变得臃肿和笨重,这意味着它们可能会影响网站的性能。当您只对公司的企业设备感兴趣时,支持世界上所有设备的额外代码可能会超过使用库的一些好处。

    库和框架没有正确的答案

    正如你所看到的,有支持和反对使用 CSS 库和框架的争论。它是否适合您的特定项目,这个问题只能通过您自己的分析来回答,而且通常需要您做出判断。

    然而,认识到在某些情况下使用它们是有益的,本章的其余部分将致力于研究在写作时可用的一些选项。在本章快结束时,你还将重温在第五章完成的一个项目,看看如果你使用一个库而不是原始的 CSS 代码,它会如何被不同地解释和实现。

    Note

    一些库和框架使用 CSS3 布局模块和非 CSS3 布局技巧的混合方法。除非您是一个纯粹主义者,否则这可以为实现特定布局的问题提供一个好的、健壮的解决方案。

    最好的 CSS 框架和库

    考虑到你正在一个非常不稳定的时期使用 CSS3 布局模块,这一节的标题是加粗的,但是我挑选了一些目前可用的最好的 CSS 框架和库。我怎么知道他们是最好的?我对搜索引擎结果进行了一项完全不科学的研究,以确定大众观点。我会一直这么说:当你开始搜索一个图书馆的时候,你一定要看看网上社区是怎么说的。

    如前所述,有两种基本类型的库和框架可用。区别就像一个普通的汽车旅馆房间和五星级酒店房间一样。有时候,你想要的不过是四面墙和一张床,能够自己做饭,可以随心所欲地使用自己的房间;其他时候,你希望奢侈地让其他人担心细节,并且把所有东西都放在银盘上带给你!

    在最基本的层面上,CSS3 布局库只提供挂钩来允许您创建网格布局、呈现 flexbox 或调用多列布局,除了将适当的类名应用于一系列的<div><section><article>之外,无需做任何其他事情。这些类似于一个基本的汽车旅馆房间。他们只做一件事,仅此而已。剩下的就看你自己了!另一端是完成所有布局的解决方案,这些解决方案还提供小部件、样式和皮肤,它们基本上可以提供实现页面设计和布局所需的所有工具,包括所有的美学。

    我在汽车旅馆的房间里犯了错误。但是,不要让这阻止你追求全面服务的选择,如果它能更有效地满足你的特殊项目的需求。

    Flexbox 网格

    Flexbox 网格系统是一个简单明了的库,旨在允许您使用元素上的类将不同的 Flexbox 属性分配给布局,而不必直接钻研 CSS(参见图 9-3 )。由 Kristopher Joseph 创建,这是一个非常轻量级的解决方案,几乎不抽象源代码 CSS3 Flexbox 代码;但正因为如此,也真的很容易学会使用。在本章的后面,您将使用这个库来重新创建原来的 Flexbox 项目。

    A320135_1_En_9_Fig3_HTML.jpg

    图 9-3。

    Flexbox Grid, found at http://flexboxgrid.com

    ptb/flexgrid

    该框架也基于 Flexbox 模块,但它并没有提供框架,而是试图重新创建 Bootstrap 使用的相同布局范例(见图 9-4 )。由此产生的网格布局比其他选项要严格得多,但是如果您已经熟悉了 Bootstrap 12 列网格,您会立即有宾至如归的感觉。

    A320135_1_En_9_Fig4_HTML.jpg

    图 9-4。

    ptb/flexbox, found at http://ptb2.me/flexgrid/

    ptb/flexgrid 完全是为了在网格系统中布局内容而设计的——没有花哨的用户控制样式或额外的小部件。结果是,除了 Modernizr 库之外,整个框架占用的空间不到 2 KB,Modernizr 库是确保布局在所有浏览器上都能工作所必需的。

    指南针

    Compass 与本节重点介绍的其他库和框架的不同之处在于,它不仅仅使用单个 CSS3 布局模块,而是提供了一个解决方案,使得使用 CSS3 和 CSS 中的所有可用工具更加容易(参见图 9-5 )。前提很简单:减少与精心设计特定设计相关的代码混乱,并提供对 Web 上流行的可重用设计模式的轻松访问。这意味着您可以使用该框架,使用您熟悉的构建块来快速原型化和部署布局。还有许多扩展,涵盖了从排版控制到精灵生成的所有内容。

    A320135_1_En_9_Fig5_HTML.jpg

    图 9-5。

    Compass, found at http://compass-style.org

    CSS 区域聚合填充

    尽管 Francois Remy 的 CSS Regions Polyfill 在技术上并不是一个框架,但我在这里包含了它,因为它为立即使用 CSS 区域布局规范提供了一个真正有用的解决方案(见图 9-6 )。使用 Francois 的 JavaScript 库的特别好处是,它允许您实现没有浏览器供应商前缀的区域,使您今天编写的代码仍然需要直接访问和理解 CSS 区域布局模块,但由于 JavaScript,它是面向未来的,同时仍然可以被旧浏览器访问。

    A320135_1_En_9_Fig6_HTML.jpg

    图 9-6。

    CSS Regions Polyfill, found at https://github.com/FremyCompany/css-regions-polyfill

    因为该库使用原始规范,所以除了本书所涵盖的内容之外,您不需要了解任何其他内容。这不会简化您的代码,但它消除了在提供跨浏览器支持和回退方面的一个令人头痛的问题。

    反应灵敏的永旺

    这个基于网格的库使用了与这里强调的其他一些库类似的方法,但是布局工程是完全抽象的,所以不能立即看出哪些模块被用来创建布局(见图 9-7 )。事实上,最新的更新使用了大量的 CSS2.1 来产生布局,同时使用了类似于 CSS3 网格布局的方法。请记住,当你使用 CSS 布局时,你是在调用几十年工作的组合;因此,如果您需要比“开发中”的 CSS3 模块更稳定的东西,这可能是迈向完全 CSS3 解决方案的一个很好的跳板。代码非常简单,因此也适合进行定制,以形成您可以在未来项目中重用的库的基础。

    A320135_1_En_9_Fig7_HTML.jpg

    图 9-7。

    Responsive Aeon, found at http://newaeonweb.com.br/responsiveaeon/

    仅仅是开始…

    请记住,本章中强调的库和框架只是 Web 上可用选项的开始。为了加快工作流程,尽早投入时间检查和探索可用的选项至关重要。

    Note

    在这里,我再次强调,当你创作你的页面时,在网上查找最新最好的库和框架是非常重要的。当你读到这本书的时候,几乎可以肯定的是,在写作的时候,将会有许多选择加入到可用的组合中。

    加速您的工作流程:一个例子

    既然您已经看到了一些当前可用的使用 CSS 库和框架来加速页面开发的选项,那么让我们更详细地研究其中一个,看看使用其中一个库会是什么样子。出于这种探索的目的,让我们回到您在本书前面看到的一个示例项目。这是很有用的,因为它允许您看到如何通过使用框架来简化早期编写的代码。

    现实世界的例子

    如果你还没有阅读第五章的话,现在就快速浏览一下,熟悉 CSS Flexbox 以及它是如何填充空间的。此示例重新创建了该章中的项目;但是它没有使用原始的 CSS Flexbox 代码,而是利用了 Flexbox 网格库,并显示了该库对代码的影响。

    让我们回忆一下您想要创建的布局。图 9-8 显示了第五章中的模型;这个例子使用了完全相同的元素来创建这个项目的另一个版本,但是一旦你熟悉了 Flexbox 网格库,这应该会容易得多。

    A320135_1_En_9_Fig8_HTML.jpg

    图 9-8。

    The project to be re-created from Chapter 5 using a library instead of raw CSS flexbox code

    如果你一直在关注,你会发现 Flexbox 被用来创建图 9-9 中的布局。为了提供公平的比较,您将使用相同的模块来呈现库支持的布局。这意味着调用本章前面强调的 Flexbox 网格库。我不是在支持那个特定的图书馆。但是正如您将看到的,它确实为精心设计布局提供了一个有效且实用的解决方案。正如前面的布局尝试一样,让我们专门关注页面的三个部分:导航栏、大屏幕区域和利益陈述。

    A320135_1_En_9_Fig9_HTML.jpg

    图 9-9。

    If you’re eagle-eyed, you’ll notice that this is practically the same as the render in Chapter 5 following the native CSS attempt. The primary difference is that this version aligns to a grid

    HTML 标记

    让我们从第五章中使用的 HTML 标记开始,如清单 9-1 所示。这个页面的代码很简单,遵循的模式类似于过去使用浮动来排列设计元素时使用的布局。

    <!—The navigation section -->
    <nav>
     <ul>
      <li><a href="#">Home</a></li>
      <li><a href="#">Locations</a></li>
      <li><a href="#">Financing</a></li>
      <li><a href="#">Special Offers</a></li>
      <li><a href="#">About us</a></li>
      <li><a href="#">Contact Us</a></li>
      <li class="searchform"><form><input type="text" value="search" /></form></li>
     </ul>
    </nav>
    
    <!—The big icons/jumbotron section -->
    <section id="jumbotron">
     <article>
      <h2>Free Advice</h2>
      <p>All our impartial advice is offered completely free of charge</p>
      <img src="img/bigicon-freeadvice.png" />
     </article>
     <article>
      <h2>Discounted Removals</h2>
      <p>Once you've found your dream…
    ...</article>
    </section>
    
    <!—The badge benefits section -->
    <section id="benefits">
      <article>
       <h1> Looking for a beautiful new home that won't break the bank?</h1>
       <p> Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum.</p>
      </article>
      <article class="badge">
       <div>
        <h3>Quality without compromise</h3>
        <p>We have homes that suit every budget without compromising on quality</p>
       </div>
       <img src="img/badge-quality.png" />
      </article>
      <article class="badge">...
      ...</article>
    </section>
    
    Listing 9-1.HTML Code for Three Parts of the Page Suited to Flexbox Layout
    
    

    使用图书馆

    不同的库有不同的实现方案。这个例子使用了 Flexbox 网格库,所以您下载了这个库,并按照说明将其插入到我的页面中。这就像在<head>部分创建一个<link>一样简单,如清单 9-2 所示。

    <head>
      ...
       <link rel="stylesheet" href="css/flexboxgrid.min.css" type="text/css">
      ...
    </head>
    
    Listing 9-2.Installing the Library by Copying Files into the Web Site Folders and Using a <link> Statement
    
    

    Tip

    回想一下,由于新的 CSS3 模块是由浏览器供应商实现的,所以他们在实现中倾向于从特定于供应商的前缀开始。库和框架消除了你关心这些细微差别的需要。

    导航

    您需要处理的页面的第一部分是贯穿设计顶部的导航。如果你回头参考第五章,你会发现直接使用 Flexbox 非常简单。清单 9-3 重复了第五章中使用的 CSS 代码,来说明有多简单!使用 Flexbox 网格库同样简单,如清单 9-4 所示。

    /* The navigation section */
    nav > ul {
      display: flex;
      flex-flow: row wrap;
     }
     nav > ul > .searchform {
      margin-left: auto;
     }
    
    Listing 9-3.Native Flexbox CSS Code to Create the Navigation Layout
    
    
    <!—The navigation section -->
    <nav>
     <ul class="row start-xs">
      <li class="col-xs"><a href="#">Home</a></li>
      <li class="col-xs"><a href="#">Locations</a></li>
      <li class="col-xs"><a href="#">Financing</a></li>
      <li class="col-xs"><a href="#">Special Offers</a></li>
      <li class="col-xs"><a href="#">About us</a></li>
      <li class="col-xs"><a href="#">Contact Us</a></li>
      <li class="col-xs-offset-2 col-xs searchform"><form><input type="text" value="search" /></form></li>
     </ul>
    </nav>
    
    Listing 9-4.Using the Flexbox Grid Library and Altering the HTML Code to Apply Specific Classes to Elements
    
    

    如您所见,这两种方法的主要区别在于,当您通过直接编写 CSS Flexbox 代码来处理实现时,您使用 CSS 来创建布局。在 Flexbox 网格库的情况下,您可以将类名应用于 HTML。在这个例子中,差别是微不足道的;但是随着事情变得越来越复杂,如果您希望更改出现在布局中的项目数量,第二种方法会更加灵活。图 9-9 显示了实现 Flexbox 网格库后 Chrome 中的导航输出。

    大屏幕

    使用直接的 CSS,超大屏幕很容易制作。回想一下以下关于设计模型的内容,这些内容有助于将设计模型转化为功能性布局:

    • 每个<article>大小均匀。
    • 大屏幕中每个元素的内容在两个轴上居中对齐。
    • 图像在文本之前呈现,但出现在标记中的文本之后。

    回头查看 HTML 代码,注意最后一点要求您在演示过程中对内容进行重新排序。Flexbox 让这变得简单明了,Flexbox 网格库也是如此。同样,通过将特定的类应用到标记中的元素来处理所有事情。清单 9-5 中显示了使用该库的代码。

    <!—The big icons/jumbotron section -->
    <section id="jumbotron" class="row">
     <article class="col-lg-4 col-xs-12">
      <div class="marginbox row">
       <h2 class="col-xs-12">Free Advice</h2>
       <p class="col-xs-12">All our impartial advice is offered completely free of charge</p>
       <div class="col-xs-12 first-xs"><img src="img/bigicon-freeadvice.png" width="52" height="41" /></div>
      </div>
     </article>
     <article class="col-lg-4 col-xs-12">
      <div class="marginbox row">
       <h2 class="col-xs-12">Discounted Removals</h2>
       <p class="col-xs-12">Once you've found your dream home we can help get you moved in</p>
       <div class="col-xs-12 first-xs"><img src="img/bigicon-removals.png" width="50" height="41" /></div>
      </div>
     </article>
     <article class="col-lg-4 col-xs-12">
      <div class="marginbox row">
       <h2 class="col-xs-12">Buying Incentives</h2>
       <p class="col-xs-12">Many of our homes offer additional benefits such as rebates</p>
       <div class="col-xs-12 first-xs"><img src="img/bigicon-incentives.png" width="24" height="41" /></div>
      </div>
     </article>
     <article class="col-lg-4 col-xs-12">
      <div class="marginbox row">
       <h2 class="col-xs-12">Locations nationwide</h2>
       <p class="col-xs-12">We have agents and properties across all 50 States</p>
       <div class="col-xs-12 first-xs"><img src="img/bigicon-locations.png" width="41" height="41" /></div>
      </div>
     </article>
     <article class="col-lg-4 col-xs-12">
      <div class="marginbox row">
       <h2 class="col-xs-12">Highest Quality Homes</h2>
       <p class="col-xs-12">Every single home we offer is guaranteed for quality</p>
       <div class="col-xs-12 first-xs"><img src="img/bigicon-quality.png" width="51" height="41" /></div>
      </div>
     </article>
     <article class="col-lg-4 col-xs-12">
      <div class="marginbox row">
       <h2 class="col-xs-12">No obligation</h2>
       <p class="col-xs-12">You can withdraw from the process at any time without penalty</p>
       <div class="col-xs-12 first-xs"><img src="img/bigicon-noobligation.png" width="45" height="41" /></div>
      </div>
     </article>
    </section>
    
    Listing 9-5.Flexbox Grid Classes Applied to the HTML Markup, Assigning Layout Attributes to the Elements on the Page
    
    

    改变 HTML 也意味着原来的 CSS 不再相关。您可以删除所有的 Flexbox 代码,如清单 9-6 所示,留下清单 9-5 中分配的类。

    /* The jumbotron section */
    #jumbotron {
     background: #38CEB1;
     max-width:    960px;
     min-height:    380px;
     justify-content: center;
     padding-left: 1px;
    }
    #jumbotron article {
     /* Vertical align */
     justify-content: center;
     text-align: center;
    }
    .marginbox {
     /* Vertical align */
     justify-content: center;
     text-align: center;
     min-height: 190px;
     background: #EAEAEA;
     margin: 0 1px 1px 0;
    }
    
    #jumbotron article .marginbox * {
     align-self: center;
    }
    
    #jumbotron article .marginbox:hover {
     background: #efefef;
    }
    
    Listing 9-6.Removing the Flexbox Code from the CSS Used in Chapter 5, and Thus Simplifying the Code
    
    

    在 Safari 中渲染的结果如图 9-10 所示。请注意,这种替代方法要求您在每篇文章的内容周围添加一个额外的<div>元素。这是考虑到文章之间的边距,否则将导致每行仅呈现两篇文章。我还将这个额外的<div>设置为嵌套的 Flexbox 网格行,确保三个元素按照设计要求伸缩。渲染的每个其他方面都是相同的。

    A320135_1_En_9_Fig10_HTML.jpg

    图 9-10。

    The output from Listing 9-6 is identical to the original version created in Chapter 5

    如果您想知道当浏览器窗口比 960px 窄时会发生什么,Flexbox 的优势在这里仍然适用。当窗口变得更窄时,内容会重新分页。这得益于为每个元素分配多个类的能力。在这种情况下,我分配了一个额外的小屏幕,以 12 列的宽度显示每个<article>(填充整个行),这意味着每行只呈现一个<article>

    福利区

    最初使用 Flexbox 呈现的页面的剩余部分是底部的福利部分。你可能还记得,这是三个部件中最复杂的一个。

    福利部分更复杂,因为左边的列是右边部分的两倍高。为了处理这个问题,HTML 嵌套了元素。您可以在清单 9-7 中看到实现 Flexbox 网格库时所需的代码。同样,除了库处理的布局挂钩之外,还需要一些额外的 CSS 代码,如清单 9-8 所示。产生的代码量与第五章中创建的原始版本大体相似,但是布局控制已经被移植到 HTML 元素上的类的使用上,而不是纯粹在 CSS 中。这意味着通过引入额外的元素来改变布局可以直接从 HTML 中控制。

    <!—The badge benefits section -->
    <section id="benefits" class="row">
     <article class="col-lg-4">
      <h1>Looking for a beautiful new home that won't break the bank?</h1>
      <p>Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum.</p>
      <p>Curabitur blandit tempus porttitor. Aenean eu leo quam.
     </article>
     <div class="col-lg-8 row">
      <article class="badge col-lg-6 row">
       <div class="col-lg-9 row">
        <h3 class="col-lg-12">Quality without compromise</h3>
        <p class="col-lg-12">We have homes that suit every budget without compromising on quality</p>
       </div>
       <div class="col-lg-3 first-xs"><img src="img/badge-quality.png" width="38" height="38" /></div>
      </article>
      <article class="badge col-lg-6 row">
       <div class="col-lg-9 row">
        <h3 class="col-lg-12">Trade-up facilities</h3>
        <p class="col-lg-12">If you have a home to sell, we can help market it, and arrange bridging finance</p>
       </div>
       <div class="col-lg-3 first-xs"><img src="img/badge-tradeup.png" width="38" height="38" /></div>
      </article>
      <article class="badge col-lg-6 row">
       <div class="col-lg-9 row">
        <h3 class="col-lg-12">Wonderful locations</h3>
        <p class="col-lg-12">Don't settle for a nice home in a bad location. All our locations are carefully chosen</p>
       </div>
       <div class="col-lg-3 first-xs"><img src="img/badge-locations.png" width="38" height="38" /></div>
      </article>
      <article class="badge col-lg-6 row">
       <div class="col-lg-9 row">
        <h3 class="col-lg-12">Value-added service</h3>
        <p class="col-lg-12">We offer a range of packages that can add value to your home-buying experience, </p>
       </div>
       <div class="col-lg-3 first-xs"><img src="img/badge-valueadd.png" width="38" height="38" /></div>
      </article>
     </div>
    </section>
    
    Listing 9-7.Required HTML Alterations 
    
    
    /* The badge benefits section */
    #benefits {
     width:    960px;
     max-width:  960px;
     margin-top: 50px;
     height: 260px;
    }
    #benefits article.badge img {
     margin:  0.5em 0;
     margin-right: 10px;
    }
    #benefits article h1 {
     font-size:  2em;
     padding-right: 1em;
     font-weight:  normal;
     margin-bottom:  0.5em;
    }
    #benefits article h3 {
     font-size:  1.6em;
     font-weight:  normal;
     margin:  0;
     padding-left: 0;
     text-align:   left;
    }
    #benefits article p {
     text-align:   left;
     padding:  0;
     font-size:  1.2em;
     margin-bottom:  1em;
    }
    
    Listing 9-8.CSS to Size Elements on the Page
    
    

    该实现的输出如图 9-11 所示。请注意,结果再次与第五章的原始版本几乎相同。这是意料之中的,因为从根本上说,这两种实现的代码是相同的;区别在于如何将属性分配给标记。您喜欢哪种方法由您自己决定,但是使用预构建的库来按照通用的设计模式创建布局,而不需要每次都创建自己的解决方案是非常有用的。

    A320135_1_En_9_Fig11_HTML.jpg

    图 9-11。

    The output in Safari Note

    再次重申,需要一些额外的非 Flexbox CSS 代码来定义本例中显示的颜色、边框和印刷样式。我特意修剪了代码片段,只显示相关的 CSS 代码用于布局。

    摘要

    本章介绍了使用 CSS 库和框架加速页面开发的方法。虽然每次你开始一个页面布局的时候都很想重新发明轮子,但是基本上相同的核心元素支撑着你将要设计的几乎每一个页面。通过认识到这一事实,并使用库来加速布局,您可以专注于获得正确的设计细节。

    当然,有时一个库或框架不适合你的项目,所以不要害怕承认你需要不时推出自己的解决方案。最好在开发过程的早期就认识到这一点,而不是在你投入大量时间将一个设计硬塞进一个框架中之后才恍然大悟。出于这个原因,预先花一点时间调查所有选项并选择最适合您特定项目的选项是值得的——即使这导致您不使用库!

    十、CSS 布局的未来

    恭喜你!关于作为 CSS3 的一部分提供的当前布局选项,您已经到达了这本书的末尾。但是不要以为这就是故事的结局!

    在学习本章的过程中,您已经深入研究了 CSS Flexbox、CSS 多列布局、CSS 区域布局和 CSS 网格布局,您甚至快速回顾了过去提供的替代方案。我希望您也已经获得了一些想法,如何填充缺失的功能,并使用渐进增强的原则为越来越多使用最新浏览器的用户提供新的和改进的布局,同时不排除那些停留在旧浏览器上的用户。

    这一切都还在开发中

    正如你从本书中讨论的一些模块的短暂性所看到的,CSS3 正在积极开发中。不仅仅是我提到的模块还在开发中——更多的好东西正在开发中,可能会给你日常使用的布局带来全新的范例。

    在写作和研究这本书的过程中,有很多关于 Adobe、微软、苹果和 Mozilla 等公司令人兴奋的新发展的传闻。2000 年代 CSS 发展停滞的时代已经结束;随着越来越多的消费者接受新技术并对他们的在线体验提出更多要求,负责提供支持这些体验的框架的公司正在倾听并做出反应!

    Adobe 就是一个例子。以桌面出版和创意工具而闻名的 Adobe,决心拥抱数字化的未来——还有什么比开放网络更好的平台呢?除了共同发起许多你已经看到的模块,这个软件巨人的开发室里还在讨论许多其他的模块。

    即将推出的模块和想法

    我希望你已经意识到这样一个事实,即我们正处于 CSS 发展的一个非常激动人心的阶段。这种语言发展迅速,人们可以毫无畏惧地随意表达观点。这意味着有很多参与,设计师和技术人员正在接受进一步开发的想法。让我们快速看一下可能会成功的两个未来模块。

    CSS 排除项

    CSS 排除已经超越了闭门讨论的范畴,现在正在通过 W3C 进行开发。它目前处于工作草案形式,由 Adobe 和微软共同赞助;它基于 CSS2.1 中引入的浮动元素的思想。

    在某些方面类似于 CSS 区域布局,CSS 排除描述了内容围绕元素流动的方式,有效地为设计者的军火库增加了另一个布局格式化工具(见图 10-1 )。值得注意的是,该规范仍处于最早期阶段,因此在不久的将来您将无法可靠地使用它,但您可以在 www.w3.org/TR/css3-exclusions/ 找到更多信息,那里有当前的规范。在撰写本文时,还没有太多的实现可用,但这可能是一个小而重要的改进,可以让您以更杂志式的方式控制内容。

    A320135_1_En_10_Fig1_HTML.jpg

    图 10-1。

    The effect of CSS Exclusions on content, determining how wrapping should occur

    CSS 形状

    虽然不仅仅是关于布局,CSS Shapes 是另一个即将到来的规范的例子;您可以在 www.w3.org/TR/css-shapes/ 了解更多信息。同样,它建立在网页上实现更像杂志的布局的想法上;在这种情况下,它为内容确定非盒形的盒子。这是一件相当大的事情,因为到目前为止,你不得不使用烟雾和镜子来给人一种处理东西而不是盒子形状的内容区域的印象。

    同样,这个模块是由 Adobe 和微软共同赞助的,并且仍在积极开发中。请关注网站,获取关于何时可以真正使用它的最新信息(没有当前基于脚本的填充工具!).图 10-2 让你知道这对于格式化网络上的图片(或其他内容)有多么重要。

    A320135_1_En_10_Fig2_HTML.jpg

    图 10-2。

    A CSS shape acting based on the alpha channel of an image, wrapping content automatically around the image subject

    还有更多…

    正在探索的想法不仅限于这两个模块。查看 CSS 工作组网站了解更多信息,包括根据内容级别确定样式的演示级别模块(对于 PowerPoint 样式的演示非常有用)以及对网页上处理分页媒体的方式的升级。这里有很多内容超出了我的篇幅,所以很值得浏览一下,看看这本书的下一版会有什么内容!

    Caution

    事情会随着时间而改变!不要忘记定期查看权威的 CSS3——W3C——对本书中概述的规范的修订和增强。在编写这本书的这段时间里,已经有了许多发展,毫无疑问,在整套模块处于候选发布阶段之前,还会有更多的发展。但是,这也是在网络上工作的乐趣之一,不是吗?

    摘要

    这一章已经看了我们已经走了多远,以及 CSS3 布局的当前状态。我还偷偷瞥了一眼未来,以及未来几年可能会开发出哪些令人兴奋的新模块。这是一个参与网页设计的绝佳时机;随着推动网络发展的语言和技术的进步,以及允许用户浏览和享受网络的浏览器的进步,我们作为网页设计师的未来只会更加光明。前进,展开!

posted @   绝不原创的飞龙  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示