出典: w3cplus - North and South
多くのブラウザーが CSS をサポートしたばかりのとき、私はすでに CSS を使い始めており、ページ レイアウトに CSS を使用した最初の開発者の 1 人とみなされるはずです。当時、ブラウザ間の互換性はあまり良くありませんでしたが、それでも無限にある新機能を試してみたいと思っていました。近年、CSS 分野では多くの大きな進歩が見られました。中でも、Web フォント、グラデーション、シャドウ、メディア クエリは、日常のワークフローにおいて不可欠なツールとなっています。
しかし、CSS レイアウトの開発は遅れています。開発者は、絶対配置とフローティング レイアウトによって生じる制約を軽減するために、レイアウトに display:table と display:inline-block を使用しようとしました。ただし、これらの方法は標準ではないため、新たな問題が発生します。
CSS レイアウトの未来は明るいようです。この記事では、CSS 仕様の興味深いレイアウト モジュールのいくつかを見ていきます。将来的には、グリッド レイアウトをより効率的に実装できるようになり、同じ高さの列を作成したり、ページ全体にコンテンツを均等に分散したりすることが容易になります。 Adobe などの企業は、レイアウト設計の詳細に精通していることが多く、関連仕様の策定を支援してくれるため、ページのコンテンツに影響を与えることなく、ブラウザー上でページがどのように表示されるかをより正確に制御できます。
この記事の例では、1 つ以上のブラウザーでテストしましたが、引き続きテストすることもできます。これらのレイアウト モジュールの一部はまだ開発の初期段階にある可能性があり、その特定の実装は将来変更される可能性があるため、関連する問題について標準設定チームにフィードバックを提供することもできます。これは私たちのウェブであり、標準の設定に積極的に関与する必要があります。
この本のこれらのテクニックをオンライン製品で使用する場合は、そのページが下位バージョンのブラウザのユーザーにもフレンドリーであることを確認する必要があります。たとえ、これらの下位バージョンのブラウザが関連するレイアウト モジュールをサポートしていない場合でもです。ブラウザーの互換性の問題の解決にあまり時間をかけたくありませんが、各章の最後に役立つ提案とヒントをいくつか紹介します。
この記事に関係するほとんどの属性には、複数のブラウザプレフィックスが必要です。複数列レイアウトやフレックスボックス レイアウトなど、比較的安定した仕様を持つレイアウト モジュールの場合は、Lea Verou の -prefix-free スクリプトを使用します。これにより、標準プロパティのみを実証する必要があり、ブラウザ間の互換性が実現されます。オンライン製品の場合は、CSS にブラウザー プレフィックスを追加するか、CSS プリプロセッサを使用してブラウザー プレフィックスを最終的な CSS ファイルにコンパイルすることをお勧めします。
非常に新しいレイアウト モジュール (個々のブラウザーでのみサポートされ、関連する仕様が頻繁に変更されるレイアウト モジュール) については、テストされたブラウザーのプレフィックスを追加します。本書の出版時点では、他のブラウザはブラウザ固有のプレフィックスを追加することで、関連するレイアウト モジュールをすでにサポートしている可能性があります。これらのレイアウト モジュールは実験的な性質があるため、ブラウザごとに異なるレンダリング結果が発生する可能性があります。他のブラウザには可能な限り接頭辞を使用し、関連するテストを実行する必要があります。最後に、接頭辞のない関連属性をオンライン製品に追加する必要があります。
CSS3 の複数列レイアウトは長年人気がありましたが、IE でのサポートが不足しているため、期待されたほどの人気を得ていません。 IE10 がこれらの機能をサポートすると、レスポンシブ デザインにとってさらに便利になるでしょう。普及することを願っています。マルチカラム レイアウト モジュールは、本書で説明されているすべてのモジュールの中で最も成熟したテクノロジと最も高度なブラウザ サポートを備えたモジュールであるため、CSS の新しいレイアウト モジュールについて説明する場合は、マルチカラム レイアウト モジュールから始めることをお勧めします。
マルチコラム レイアウトを使用すると、コンテンツを複数のコラムに均等に分散することができます。これは、新聞の「コンテンツ フロー」効果とよく似ています。まず、ドキュメント内のコンテナを選択し、そのコンテナが複数列レイアウトであることを宣言する必要があります。そうすれば、ブラウザは期待どおりの複数列効果を実現できます。コンテンツの列数を指定すると、ブラウザーは各列の幅を自動的に計算し、親要素のサイズに自動的に適応します。各列の幅を指定すると、ブラウザーは列数を自動的に計算します。 、親要素のサイズが変更された場合、ブラウザーは自動的に再計算することもできます。
例: column-width の設定-View example
.col-wrapper { column-width: 220px;}
column-width 属性を設定するということは、コンテナーにできるだけ多くの列を作成するようにブラウザーに要求することを意味し、開発者によって指定された幅は次のように考慮されます。理想的な幅。単一列の幅を指定すると、実際には期待どおりの幅が得られないことに気づいたかもしれません。多くの場合、複数の列はスペース (スペース) で埋められます。これは、ブラウザーが指定された幅に基づいて最適な列数を計算するのに役立ちます。これについては、CSS の複数列の仕様で説明されています:
"column-width の値は、最適な単一列の幅を指定します。実際の単一列の幅は、これより広い (複数の列の間の空白が埋められる) こともあれば、狭くなる (これのみ)使用可能な幅が指定された幅より小さい場合に発生します)、このプロパティの指定値は 0 より大きい必要があります。」
因此,当需要设定单列宽度时,你只需指定一个理想宽度即可,因为为了设计的灵活性,实际宽度可能会出现一些差异。
示例:设置column-count-查看示例
你也可以使用column-count指定所需要的列数,然后让浏览器自行决定单列宽度。
.col-wrapper { column-count:3; }
在上面的例子中,你会发现多列之间并没有紧紧相邻:这是因为多列之间存在间距(gap)。在多列布局中,间距是由column-gap属性控制的。如果将column-gap设为0,那么多列之间就不会有间距,所有的文字会拥挤在一起。规范中建议浏览器在默认样式中为该属性预设1em的宽度。不过,如果让多列的间距保持一致性,那么你应该显式地为该属性设定一个值。
示例:设置column-gap属性-查看示例
.col-wrapper { column-width: 220px; column-gap: 1.5em; }
在最新的规范中已经限制了对多列布局的美化。不过,相关的工作草案也提示说:“或许在未来的规范中会添加额外的功能。比如,允许多列中的任意一列设置不同的宽度和背景。”目前来说,你还不能单独地美化多列中的某一列。
虽然没法设置单列的内外边距、宽度和背景色,但是我们可以使用一些规则来隔离多列。实现这一布局效果需要使用column-rule属性:
这些属性的用法非常类似border-style、border-width和border-color,而且也可以使用column-rule属性作为一种简写形式:
column-rule: [width] [style] [color];
上面的纵列属性(column rules)将会被应用到column-gap上。要想修改纵列两边的空白间距,就需要调整column-gap的属性值。如果上述纵列属性的值大于可用间距,那么它就会与文本区重叠??但它不会占用任何的空间。
示例:使用column-rule-查看示例
如果你想让某一个元素延伸到所有的纵列中,那么可以为该元素添加column-span并赋值为all。在下面的示例中,我要让h1标题可以延伸到所有的纵列上。
示例:强制h1延伸到多列-查看示例
.col-wrapper h1 { column-span: all; padding: 0 0 .5em 0; }
当前的规范中column-span只有两个值:all和none。
当使用多列布局的时候,你需要控制多列截断的方式。如果不希望某些元素被截断到新的纵列,或者确保某个元素固定在某一列时,下面的这个属性对你就会很有帮助。
示例:避免在段落内和引用块之前被截断-查看示例
.col-wrapper p { break-inside: avoid; } .col-wrapper blockquote { break-before: avoid; }
规范指出,多列布局内部的元素不应该出现在下一页上。如果阅读时翻到了下一页,然后让用户再返回前一页继续阅读,那么这样的体验就太让人恼火了。
你可以预设分页时段落或者元素内部内容的布局方式??就像控制多列截断一样。属性avoid-page和avoid-column就可以帮助你实现良好的控制。如果你允许段落进行截断而不允许内容分页,那么对于上面的例子,就可以使用break-inside: avoid-page替代break-inside: avoid;。
由于多列默认就是响应式的,所以多列布局也有助于实现响应式设计。正如我们所知,虽然可以根据需求设定单列宽度,但本质上浏览器会使用自己的算法,计算出一个用于渲染的宽度。
单列内的图片会被限制在单列范围之内,所以使用max-width设置的最大宽度也被局限在单列之内。如果你没有为图片设置max-width: 100%;,同时图片的宽度还大于单列宽度,那么浏览器就会自动裁剪掉多余的部分。该规则同样适用于其他宽度大于单列宽度的元素。
示例:图片宽度限制于单列之内-查看示例
一定不要认为多列布局模块只适用于创建类似报纸的版式。下面示例中的多列布局,就包含了一系列的盒模型和图片。
示例:盒模型和图片-查看示例
下面的示例演示浏览器视口较窄时的单列布局,无需编写额外的代码即可实现。
当我写下这些文字的时候,还只有几个浏览器支持多列布局。因此,有时你需要添加浏览器前缀才能使用这些属性,此外,在有一些情况下某些属性并不会生效。更多更新的浏览器支持信息,可以查看 Can I Use。如果浏览器不支持多列布局,那么它在解析样式表时就会忽略相关属性,因此可以放心使用这些属性。不支持多列布局的浏览器会将内容渲染为单列,这种渲染结果在大多数情况下也是可以接受的??不建议使用腻子脚本模拟多列布局效果。
CSS 弹性盒布局模块,通常被称为 flexbox,为我们提供了一种新的布局??flex 布局。设计该布局的初衷是为了简化复杂应用和页面的布局代码。在本节中,我将会着重介绍一些使用 flexbox 解决的布局问题。
在传统的布局设计中,将一组布局元素沿坐标轴均匀排列是件很麻烦的工作。如果使用浮动布局,那么每个浮动元素都必须设置一个宽度,否则就会宽窄不一,此外,往往需要使用 JavaScript,才能让所有的浮动元素均匀排列在同一行上。
Flexbox 极大简化了这一布局过程。在下面的示例中,我使用无序列表创建了一个导航条。
示例:flexbox 简单用法-查看示例
<nav class="mainnav"> <ul> <li><a href="">Introductory</a></li> <li><a href="">The First Cat Show</a></li> <li><a href="">Habits</a></li>? <li><a href="">Trained Cats</a></li> <li><a href="">Usefulness of Cats</a></li> </ul> </nav>
对于这个导航条,我想实现水平均匀分布的效果。如果我们选择 flexbox 布局方式,那么只需要添加display:flex属性,并指定布局元素的排列方式(所有元素平均排列或者除首尾元素外平均排列)。
示例:flexbox 简单用法-查看示例
nav ul{ margin: 0;?padding: 0;?list-style: none;?display: flex;?justify-content: space-between;}
在这里,我们将justify-content设置成了space-around,这样做的好处就是让每一个元素之间具有相同的间距,避免了溢出容器的问题。此外,在第一个元素之前和最后一个元素之后,也添加了相同的间距。
上面的示例使用了一些 flexbox 的默认属性,比如这里的布局元素默认显示为水平排列。这个默认的排列效果等同于添加了flex-direction: row的效果。
flex-direction属性一共拥有四个属性值:row、row-reverse、column和column-reverse。使用这些属性,可以实现水平排列、反向水平排列、垂直排列和反向垂直排列四种布局效果。
nav ul { margin: 0; padding: 0; list-style: none; display: flex; justify-content: space-between; flex-direction: row-reverse;}
使用 flexbox 的另一个优势在于,它可以帮你创建等高容器??即使容器内的文字不等长。align-items的默认属性值为stretch,它会根据 flexbox 内最高元素的高度,拉伸其他布局元素,使之等高。在我的导航示例中,如果你缩窄窗口,文字就会自适应为多行,但仍然保持等高拉伸的布局??从所有元素的边框就可以看出他们是等高的。
align-items的所有属性值:
为了理解其正确的解析方式,你需要首先理解 flexbox 中的两个轴概念:主轴和侧轴,其中主轴用来控制元素的布局方向。通过将flex-direction设置为row或者column,可以指定主轴,并确定布局元素的排列方向:从左到右或者从上到下;第二条轴,即侧轴,垂直于主轴。
如果将flex-direction设为row,那么主轴方向就是从左到右的。设置align-items为flex-end,意味着布局元素不会占据布局容器的全部高度,所有的布局元素在底部对齐,不做等高处理。
在之前的这个示例中,如果我们将浏览器缩窄,那么布局元素内的文字就会在布局元素内拆分成多行。究其原因,是因为布局元素的内容宽度超过了可用空间。一种可行的解决方案就是将布局容器设为wrap(表现为多行效果)。
在 flexbox 布局中,使用flex-wrap属性可以控制布局容器的多行模式,可用的属性值包括wrap、nowrap和wrap-reverse。如果没有显式声明该属性值,那么flex-box默认为nowrap。
示例:布局容器的多行模式-查看示例
nav ul{ margin: 0; padding: 0; list-style: none; display: flex; justify-content: space-between; align-items: stretch; flex-direction: row-reverse; flex-wrap: wrap;}
然而,从图中可以发现,相邻布局元素之间出现了意料之外的不规则空隙。修正这种表现的方式是为布局元素添加额外的布局间距。为布局元素设置flex: auto;即可实现这一目标??在我们的示例中,我为li元素添加了该属性。
nav li { border: 1px solid #999; border-radius: 2px; flex:auto; margin: 0 1em 1em 0; text-align: center;}
虽然为布局元素设置flex: auto;可以调整它们在布局容器内的空间排列,但该属性的作用远不止如此,这里将会介绍几种其他的用法。
在下面的示例中,我编写了三个块级元素,块级元素内部是一些关于长毛猫品种的信息。此外,我还为块级元素添加了公有的类名box和独立的类名,便于选择特定的块级元素。
示例:三个块级元素-查看示例
<div class="boxes"> <div class="box box1"> <h2>The Angora</h2> <p>... </p> </div> <div class="box box2"> <h2>The Persian Cat</h2> <p>... </p> </div> <div class="box box3"> <h2>The Russian Long-haired Cat</h2> <p>... </p> </div></div>
为了让所有的块级元素在单行内排列,我将布局容器,即boxes,设为了 flex 元素,然后为容器内的每个元素设置flex: 1。设置完成后,所有的布局元素就都具有了相同的宽度。
.boxes { display: flex;? flex-direction: row;? flex-wrap: wrap;? align-items: stretch; justify-content: space-between; } .box { border: 1px solid #999; border-radius: 5px; flex: 1;? margin: 0 1em 1em 1em; padding: 10px; }
此外,我们可能需要让某个布局元素宽于其他布局元素,同时还要根据可用的容器空间计算各个布局元素的宽度。示例中的第三个块级元素拥有一个类名box3,如果为box3添加flex属性并赋值为2,那么相比于flex: 1;的布局元素,它就会具有两倍的宽度。
.box3 { flex: 2;}
从前面的介绍中,我们已经了解到 flex 布局元素是可以反向排列的。实际上,我们可以为每个独立的布局元素设置任意的排列顺序,其中的关键,就需要用到下面介绍的order属性。
通过为每个布局元素设置order属性,我可以轻松移动box3。只需要为其添加order: 2;,就可以将这个最宽的布局元素移动到容器中央。
.box1 { order: 1;}.box2 { order: 3;}.box3 { flex: 2; order: 2; }
虽然我们更改了渲染后的布局顺序,但实际上它的 HTML 结构仍旧保持不变。这意味着你可以根据实际需求来编写 HTML 结构,这样做有助于提高可用性,改善使用文本阅读器的用户体验。此外,使用该属性还可以创建出色的布局效果。
对于响应式设计,flexbox 是一种优秀的可选方案。由于它具有包裹多行、自适应可用空间的特点,可以让我们不费吹灰之力就创建出简单的响应式效果。
如果你在 flexbox 中混合媒体查询的功能,那么就可以创建出更复杂的布局效果。由于可以按照不同于源码的结构来显示布局元素,所以我们能够在不同尺寸的屏幕上创建不同的布局效果。此外,也可以像下面的示例一样,使用flex-direction来转换布局方向。最初,我们可以让导航显示为垂直排列,当窗口宽度大于700px时,我们就可以将其转换为水平排列。
nav ul{ margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; justify-content: space-between; align-items: stretch; }@media only screen and (min-width: 700px) { nav ul { flex-direction: row; }}
Flexbox 是一个极佳的案例,展示了 CSS 规范在初期的演变方式。由于 flexbox 的具体实现和最初构想之间已经发生了诸多变动,所以在 flexbox 的可用性上存在大量无效的资料。当你需要检索有关 flexbox 的资料时,可以查看一下 CSS Tricks 上的相关文章,便于检验当前资料的准确性。
当浏览器不支持 flexbox 时,一方面可以使用 JavaScript 来模拟 flexbox 的大量特性,另一方面你也可以让浏览器优雅降级,让布局元素呈现一种线性排列,下图就是之前的布局元素在浏览器不支持 flexbox 时的渲染效果。
如果你只是将 flexbox 布局模块应用于少量的界面元素,而不是整体布局,那么优雅降级为线性排列是比较简单的。另一种方式是使用 Modernizr 检测浏览器是否支持 flexbox,然后分别为支持和不支持 flexbox 的情况编写不同的 CSS 代码。
CSS 网格布局模块是由微软提议的,目前仍在进行大量的规范化工作。该模块的最新进展已经应用到了 Internet Explorer 10 上,所以本部分的实例演示都会基于 IE10。
网格布局旨在解决复杂网页的布局问题??在该布局提出之前,我们只能通过元素的浮动和定位来模拟复杂布局。网格布局也允许开发者显示与源码结构不同的布局结构??类似上一章节的 flexbox 布局。我很喜欢网格布局,希望你在阅读完下面的示例之后也会喜欢它。
将布局元素包裹进网格的第一步,就是在它们的父元素上创建网格。首先需要添加display: grid;(通常我会加上-ms-前缀),然后设置所需的网格行数和列数。
示例:一个简单的网格布局-查看示例
.wrapper { display: -ms-grid; -ms-grid-columns: 200px 20px auto 20px 250px; -ms-grid-rows: auto 1fr;}
上面的 CSS 代码在.class元素上创建了网格,该网格拥有五个纵列:一个200px宽度的侧列,一个20px宽度的间距,一个自适应宽度的中间纵列,另一个20px宽度的间距,以及最后一个250px宽度的纵列。由此可见,这是由两个固定宽度的纵列和一个可变宽度的中间纵列构成的简单布局。
在横列上,我将第一列设为了auto??它将根据内部内容自动扩展高度,将第二列设为了1fr。1fr准确的说是一个分数比值,在这里意味着第二列在剩余空间所占的比重。由此可见,这是具有两个横列的布局。
现在,我们可以往网格里添加一些内容了。添加内容后的结构如下:
<div class="wrapper"> <nav class="mainnav"> <ul> <li><a href="">Introductory</a></li> <li><a href="">The First Cat Show</a></li> <li><a href="">Habits</a></li> <li><a href="">Trained Cats</a></li> <li><a href="">Usefulness of Cats</a></li> </ul> </nav> <h2 class="subhead">Usefulness of cats</h2> <article class="content"> <p>...</p> </article> <blockquote class="quote"> <p>....</p> </blockquote></div>
为了将导航定位到左侧固定宽度的纵列上,将文章部分定位到中间的纵列上,将引用定位到右边的纵列上,我又添加了如下的样式:
.mainnav { -ms-grid-column: 1; -ms-grid-row: 2;}.subhead { -ms-grid-row: 1; -ms-grid-column:3;}.content { -ms-grid-column: 3; -ms-grid-row: 2;}.quote { -ms-grid-column: 5; -ms-grid-row: 2;}
上面所做的处理就是在指定具体的内容所对应的纵列。一定要牢记,间距也是纵列,所以主内容区的是在第三列上,最右侧的纵列是第五列。
当我尝试理解这种网格布局时,我发现将其设想为传统的表格布局会很有帮助,不同之处在于网格布局是在 CSS 中实现的。然后,我要做的是将布局元素放入表格单元,不过,不同于表格布局,为了适配不同尺寸的显示屏幕,在 CSS 中重新定义网格结构是更加方便的。这意味着在将来,网格布局会成为响应式设计强有力的工具。
现在,我要在这里涉及一些复杂的布局??这些布局更具有实用性,展示网格布局在响应式设计中的实际应用。
示例中使用的文档结构很简单:一个添加了wrapper类名的div标签;五个添加了box类名的div标签,标签内添加了一些内容;以及一张关于猫的图片标签??图片来自维多利亚时代的书籍。为了简单起见,我给每个box元素都添加了第二个类名,便于在 CSS 中对其进行定位和检索。
示例:一个响应式的网格布局-查看示例
<h1 class="title">Extracts from "Our Cats, by Harrison Weir"</h1> <div class="wrapper"> <div class="box content1"> <h2>The first cat show</h2> <p> ...</p> </div> <div class="box content2"> <h3>The Angora</h3> <p>... </p> </div> <div class="box content3"> <h3>The Persian Cat</h3> <p>... </p> </div> <div class="box content4"> <h3>The Russian Long-haired Cat</h3> <p>...</p> </div> <div class="box picturebox"> <figure> <img src="fluffy.jpg" alt="Fluffy the cat" /> <figcaption>Fluffy, the cat</figcaption> </figure> </div> </div>
只需要使用少量基础的 CSS 属性做一下美化,我们就得到了一个如下图所示的线性设计(linearised design)。
下面,需要定义网格了。我是通过给.wrapper添加相关的属性实现的:
.wrapper { width: 90%; margin: 0 auto 0 auto; display: -ms-grid; -ms-grid-columns: 1fr (4.25fr 1fr)[6]; -ms-grid-rows: (auto 20px)[4];}
通过设置display: -ms-grid;,表示了该元素内部包含一个网格布局。通过使用一个简写形式的多列语法,我创建了多个纵列。将有关纵列的参数集合放入圆括号内,其后跟一个参数为数字的中括号,这种语法表示我们想要重复设定某种纵列类型:在这个示例中,这意味着我将这两个纵列重复了六次。纵列之间的间距被设定为1个分数单位,而纵列则拥有4.75个分数单位的宽度。
然后,我使用相同的语法设定了横列,创建了一个根据内容自适应高度的横列,其后跟着一个20px宽度的间隙,最后将上述的横列格式重复了四次。
如果添加完上述的 CSS 后刷新页面,你会发现所有的纵列都被折叠了。这是因为所有的布局元素都尝试去填充第一纵列和第一横列,我们需要进一步为布局元素设定定位信息。一旦你为某个元素声明了网格信息,那么所有的子元素就都需要在网格中进行定位。
为了适配小尺寸的屏幕,我将从元素定位开始做布局。由于用户使用小尺寸设备时是从上到下阅读的,所以我会按照源码中的内容顺序来布局,而对于使用屏幕阅读器的用户,我会根据内容的重要性来安排布局顺序。在分离源码结构和布局结构这个新领域,我无需过多担心视觉效果背后的源码结构。
.content1 { -ms-grid-row: 1; -ms-grid-column: 2; -ms-grid-column-span:12;}.content2 { -ms-grid-row:3; -ms-grid-column: 2; -ms-grid-column-span:5;}.content3 { -ms-grid-row:3; -ms-grid-column:8; -ms-grid-column-span:6;}.content4 { -ms-grid-row:7; -ms-grid-column: 2; -ms-grid-column-span:12;}.picturebox { -ms-grid-row:5; -ms-grid-column: 2; -ms-grid-column-span:12;}
这些属性看起来都相当简单。现在,我需要选择具体的横列放入合适的内容。一定要牢记横列中间有20px的间距,所以我们应该将布局元素放入奇数横列中。然后,我为每个区域设置了起始纵列和纵列跨度。到此为止,大多数布局元素的宽度都是等于容器宽度的,但我将其中的content2和content3分割成了两个纵列。现在,在浏览器中就可以显示出一个简单的布局了。
接着,我要添加第一个媒体查询了,让布局在浏览器窗口大于700px的宽度时发生一些改变。
@media only screen and (min-width: 700px) { .wrapper { -ms-grid-columns: 1fr (4.25fr 1fr)[9]; -ms-grid-rows: (auto 20px)[5]; } .content1 { -ms-grid-row: 1; -ms-grid-column: 2; -ms-grid-column-span:17; } .content2 { -ms-grid-row:3; -ms-grid-column:8; -ms-grid-column-span:5; } .content3 { -ms-grid-row:3; -ms-grid-column:14; -ms-grid-column-span:5; } .content4 { -ms-grid-row:3; -ms-grid-column: 2; -ms-grid-row-span: 3; -ms-grid-column-span:5; } .picturebox { -ms-grid-row:5; -ms-grid-column: 8; -ms-grid-column-span:11; } }
对于较宽的浏览器窗口,我重新界定了网格,增加了更多的纵列和一个额外的横列。布局顶部的第一个内容区的宽度仍然占满了整个容器。不过,我将其他的内容去分隔成了三个纵列,其中一个内容区跨越两个横列,另外两个内容区只有前者高度的一半,并将图片放在了这两个内容区的下面。
最后,我使用媒体查询,为940px以及更宽的屏幕重新设计了网格布局。
@media only screen and (min-width: 940px) { .wrapper { -ms-grid-columns: 1fr (4.25fr 1fr)[16]; -ms-grid-rows: (auto 20px)[3]; } .content1 { -ms-grid-row:1; -ms-grid-row-span: 3; -ms-grid-column: 20; -ms-grid-column-span:13; } .content4, .content2, .content3 { -ms-grid-row:1; } .picturebox { -ms-grid-row:3; } }
这次重新界定的网格是一个基于 960 网格系统的标准网格布局。现在,我创建的网格布局中,包含了三个窄小的纵列和一个较宽的纵列,图片被放在了较窄的两个纵列下面。
网格布局模块真正的魅力在于,我们无需改变源代码中的标记结构,即可轻松变换内容在布局中的位置。我认为该模块对于初次接触它的开发者也是通俗易懂的,尤其是对于那些和我一样还记得表格布局的老派开发者。
正如本章开始所解释的,因为网格布局语法是由微软提出的,所以该模块目前只被 IE10 所支持。如果你正在开发 Windows 方面的应用程序,那么可能已经在相关的开发环境中用到它了。我也希望看到它被更多的浏览器所支持。
本文的最后两章将会讨论一些由 Adobe 和微软提议的新方案,它们都很有意思。虽然这些新方案的发展比起网格布局来说还处于初级阶段,但它们可以创建一些不可思议的布局效果。此外,从探究 CSS 布局中的新特性这个角度来说,也是非常值得的。
CSS Regions 语法为内容流创建了一种高级模型。我们可以通过指定文档的特定区域,让该区域的内容实现“流动显示”的效果??即使指定的这些区域在文档结构中并不相邻。在 web 环境中,这听起来有些怪异,不过,这种布局常常被用于印刷设计,特别是杂志和报纸。
CSS Regions 并没有提出任何新的布局方法,所以可以使用现有的或将来会出现的方法来定位元素。
为了演示 CSS Regions 的使用方式,最简单的方法就是举例说明。在编写本书的时候,只有 Chrome Canary 版本的浏览器支持该布局,而且还要保证已经开启了 WebKit 的实验性特性。如果你有这样的浏览器,那么就可以把玩下面的示例代码了。
下面就是示例的 HTML 结构。我使用了一个article标签来包裹文章的所有内容,并在文档底部添加了多个空标签。
<div class="wrapper"> <article class="main"> <h2>Usefulness of cats</h2> <p>...</p> <p>...</p> </article> <div class="region1 article-regions"></div> <div class="regionwrapper"> <div class="region2 article-regions"></div> <div class="region3 article-regions"></div> <div class="region4 article-regions"></div> </div> <div class="region5 article-regions"></div> </div></div>
article标签内包含了布局前的原始内容,而后面的空标签则充当了这些内容的容器。
首先,我需要为原始内容的容器添加一个新的 CSS 属性flow-into(附加-webkit前缀),该属性的值article-thread是我为原始内容声明的一个名字,也可以用任何其他的名字。
.main { -webkit-flow-into: article-thread; }
一旦添加了该属性,那么原始内容就会消失,这是因为你还没有指定它们的布局位置。
在上面的 HTML 结构中,每个空标签都拥有一个article-regions的类名,所以我可以让它们接收原始内容。
.article-regions { -webkit-flow-from: article-thread; }
在这里,我们使用了一个新的属性flow-from,并匹配了之前为原始内容声明的名字。如果现在刷新页面,就会发现内容重新出现在页面上了。接下来,就可以让第一个区域“流动起来了”。当内容“流动起来”之后,我们添加 CSS 来指定流动区域。
.region1 { height: 10em; }.regionwrapper { display: flex; flex-direction: row;}.region2 { flex: 1; padding: 10px; height: 40em; border-right: 1px dotted #ccc;}.region3 { flex: 1; padding: 10px; height: 40em; border-right: 1px dotted #ccc; background-color: #efefef;}.region4 { flex: 1; padding: 10px; height: 40em;}.region5 { padding: 1em 0 0 0; margin: 1em 0 0 0; border-top: 1px dotted #ccc; height: auto; }
现在region1区域已经拥有了10em的高度。一旦内容超过了这个高度,内容就会尝试填充到其他地方,所以在这里它会流入下一个区域。接下来的三个区域通过使用 flexbox 布局,被定位到了三个弹性纵列中,所以内容可以“流”入这些区域。由于这三个区域是固定高度的,当内容充满它们之后,就会继续“流”入最后的区域,该区域具有自适应的高度,可以容纳剩余的所有内容。
如果我改变想法了,想要在内容中间插入其他的东西,那么我也是可以做到的。在下面的示例中,我从 flexbox 中间的纵列上移除了artcle-regions类名,所以内容就不会再“流”入其中。现在我可以为这个纵列添加一张有关猫的图片,并引用一句话??它们和周围“流动的内容”并没有多大关系。
在本章,我们尝试了 CSS 模块中非常新颖的部分,这些部分目前只在 WebKit 浏览器开启实验性特性时被支持。虽然这并不是一个可以用于线上环境的技巧,但我认为 CSS Regions 所创造的无限可能是一件激动人心的事。
如果你曾经需要用到文字环绕图形的效果,或者想要裁剪位于内容中央的图形,那么你可能会对 CSS Exclusions 和 Shapes 模块感兴趣。一个早期的、参考了浮动定位的规范,已经被当前的工作草案所取代。
我们都非常熟悉 CSS 中的浮动,关于浮动最简单的例子就是浮动图片被文字环绕的效果。不过,浮动在这种场景下是受到严格限制的。浮动元素总是出现在顶部,当我们将图片浮动到左侧时,文字就会环绕在它的右侧和下方,无法将图片置于文档的中央,实现文字的四周环绕效果,也无法将其浮动到底部,让文字环绕在上方和两侧。上面提到的,就是 Exclusions 和 Shapes 模块首要解决的问题,并已经在 IE10 和开启实验性特性的 Webkit 浏览器中获得了支持,下面我们将会看一个实例。
这个实例就是一段简单的文字,其外层被一个类名为main的article标签所包裹。在article标签之后,紧跟着一个div标签,标签内部是一张猫的图片。我希望这张图片在布局时呈现一种文字环绕的效果。
<div class="wrapper"> <article class="main"> <h2>Usefulness of cats</h2> <p>...</p> </article> <div class="exclusion"> <img src="fluffy.jpg" alt="Fluffy the cat" /> </div> </div>
首先,我要像之前一样为它创建一个网格。与浮动不同的是,Exclusion 需要被定位(因此在浮动定位前需要有个名字)。我是使用 IE10 演示该示例的,所以可以使用网格布局来实现这种定位。
我创建的是一个两行三列的网格,并在创建后让article布局范围覆盖到了所有的行列上。虽然div标签在源码结构中是紧跟在article标签之后的,但它会显示在文字的上方。
.main { -ms-grid-column: 1; -ms-grid-row: 1; -ms-grid-row-span: 3; -ms-grid-column-span: 3; padding: 0 0 2em 0;}.exclusion { -ms-grid-row:2; -ms-grid-column:2; height: 160px; width: 200px; padding: 10px;}
要创建 Exclusion,实现浮动图片的文字环绕效果,我只需要为.exclusion添加wrap-flow属性即可。
.exclusion { -ms-grid-row:2; -ms-grid-column:2; height: 160px; width: 200px; padding: 10px; -ms-wrap-flow:both; }
属性值both意味着文字将会环绕在 Exclusion 的两侧。
实现矩形的文字环绕只是 CSS Exclusions 和 Shapes 模块的一小部分特性。在一个早期的浏览器实现中,既可以让文字环绕图形的外部,也可以将文字约束在图形内部。如果你可以使用 Chrome Canary,并且开启了 WebKit 的实验性特性,那么就可以查看由 Adobe 提供的更多示例,甚至是创建自己的实例。这些特性还算是新颖的东西,并具有一定的复杂性,虽然已经在 WebKit 上做了很多测试,依然有可能在最新的浏览器上发生变化。
wrap-flow特性对于控制文字环绕效果非常有用,它一旦被大多数的浏览器所支持,一定会快速流行起来。合理构建文档的源码结构,有助于在不支持上述特性的浏览器中优雅降级到另一种布局方案;也有助于在使用类似 Modernizr 的 JavaScript 特性检测方式之后,提供一种可替换的定位模型。
甚至是 Shapes,一旦它被主流浏览器所支持,那么就可以考虑去使用它了。只要文字环绕对于你的设计是一种有益的、非必须的特性,毫无疑问你就可以为那些支持这些特性的浏览器添加它,达到画龙点睛的效果??特别是当你知道访问网站的用户常常会使用这些浏览器的时候。
推敲、把玩和测试这些布局模块是一件激动人心而又妙趣横生的事情。我非常希望本文的内容能够点燃你的热情,让你继续去探索 CSS 中既有和即将到来的新特性,去发现无限的可能性。
在学习这些出色的新特性时,虽然它们可能还不能用于线上实践,虽然会有种种障碍,但对于我们自身的职业发展将会有莫大帮助。参与这些新规范的创建和测试,并不是浏览器开发者和大公司的专利。如果希望未来在浏览器中用到这些新规范,作为网页设计师和开发者的我们,就应该参入到其中。更多信息可以查看推动 Web 发展这个网站:这里提供了多种方式让你参与到 Web 标准的制定中。
本文根据@Rachel Andrew的《CSS3 Layout Modules》电子书所整理。如果对此内容感兴趣,可以购买电子书阅读:http://www.fivesimplesteps.com/products/css3-layout-modules。