层叠样式表(Cascading Style Sheet,CSS)是一个强大的工具,能影响一个或一组文档的表现。CSS几乎触及Web的每个角落,甚至很多非Web环境也能见到它的身影。
1.1 Web样式简介
1994年,正值Web开始广泛流行开来,CSS的第一个提案发布了。那时,浏览器为用户提供了各种样式的定制功能。
CSS的目标是提供一个简单的声明式样式语言,而且具有一定的灵活性,能为文档编写人员和用户提供等同的样式化功能。
草案制定速度很快,到1996年年末,CSS 工作组开始着手制定CSS2,而各浏览器则相互协作,努力实现CSS1。
CSS2规范于1998年年初定案。随后,CSS工作组立即投身CSS3的制定工作,以及CSS2的修订工作(制定CSS2.1)。与以往不同的是,CSS3由多个(理论上)独立的模块构成,而不是单独一个臃肿的规范。
CSS3分成多个模块的根本原因是各模块可以独立演进,尤其是重要的(或受众广的)模块可以按照W3C的规划向前推进,而不必受其他模块拖累。截至2012年年初,有三个CSS3模块(CSS Color Level 3、CSS Namespaces和Selectors Level 3)变成了全力推荐状态,而有七个模块处于候选状态,还有七个模块处在不同的草案状态。如果采用以前的机制,要等其他部分完成才能在一份完成的规范中发布颜色、选择符和命名空间的新条款。得益于模块化,我们无需再等待。
可见,我们不能指着一摞厚厚的文件说,“这就是CSS3”,而应该分模块学习不同的特性。
了解这些背景之后,就可以开始学习CSS了。不过在此之前要先了解标记。
1.2元素
元素(element)是文档结构的根基。HTML中常用的元素有p、table、span、a和div等。
1.2.1 置换元素和非置换元素
对CSS来说,元素通常有两种形式:置换元素和非置换元素。
置换元素
置换元素(replaced element)指用来置换元素内容的部分不由文档内容直接表示。在HTML中,最常见的置换元素要数img,它的内容由文档之外的图像文件替换。Input元素类似,根据类型的不同,会替换成单选按钮、复选框或文本输入框。
非置换元素
HTML元素大部分是非置换元素(nonreplaced element),即元素的内容由用户代理(通常是浏览器)在元素自身生成的框中显示。
1.2.2元素的显示方式
除了置换元素和非置换元素之外,CSS还把元素分成块级和行内两种基本类型。除此之外,还有其他显示类型,不过这两种是最常见的。
图1-1: 一个HTML文档中的块级元素和行内元素
块级元素
块级元素(默认)生成一个填满父级元素内容区域的框,旁边不能有其他元素。也就是说,块级元素在元素框的前后都“断行”。HTML中最常见的块级元素是p和div。
列表项目是一种特殊的块级元素,它的表现与其他块级元素没有区别,此外还会在元素框旁生成一个记号。
行内元素
行内元素在一行文本内生成元素框,不打断所在的行。HTML中最常见的行内元素是a,此外还有strong和em。这类元素不在自身所在元素框的前后“断行”,因此可以出现在另一个元素的内容中,且不影响所在的元素。
为了进一步了解,下面来看一个CSS属性display。
display:none | inline | block | list-item | inline-block | table | inline-table | table-caption | table-cell | table-row | table-row-group | table-column | table-column-group | table-footer-group | table-header-group | run-in | box | inline-box | flexbox | inline-flexbox | flex | inline-flex
默认值:inline
适用于:所有元素
继承性:无
动画性:否
计算值:指定值,除浮动,绝对定位和根元素外
媒体:视觉
可以看出,display属性可以取很多值,前面只提过其中三个:block. Inline和list-item。其他多数值将在本书的其他章节讨论,
现在我们只关注block和inline。来看下述标记:
<body>
<p>This is a paragraph with <em>an inline element</em> within it.</p>
</body>
这里有两个块级元素(body和p)及一个行内元素(em)。根据HTML规范,em可以放在p里,而反过来却不行。一般地,HTML层次结构要求,行内元素可以放在块级元素中,反之则不行。
改变元素的显示方式对HTML文档来说是有用的,不过对XML文档而言的作用更大。XML文档中的元素没有固定的显示方式,而是完全由编写人员定义。例如,试想一下下述XML片段将如何显示:
<book>
<maintitle>Cascading Style Sheets: The Definitive Guide</maintitle>
<subtitle>Third Edition</subtitle>
<author>Eric A. Meyer</author>
<publisher>O’Reilly and Associates</publisher>
<pubdate>November 2006</pubdate>
<isbn type=”print”>978-0-596-52733-4</isbn>
</book>
<book>
<maintitle>CSS Pocket Reference</maintitle>
<subtitle>Third Edition</subtitle>
<author>Eric A. Meyer</author>
<publisher>O’Reilly and Associates</publisher>
<pubdate>October 2007</pubdate>
<isbn type=”print”>978-0-596-51505-8</isbn>
</book>
因为display属性的默认值是inline,所以上述内容默认将显示为行内文本,如图1-2所示。可以看出,这样显示没有什么用。
图1-2: XML文档的默认显示方式
可以用display定义基本布局:
book, maintitle, subtitle, author, isbn {display: block;}
publisher, pubdate {display: inline;}
我们把七个元素中的五个设为块级元素,另外两个设为行内元素。这意味着,各块级元素将像HTML中的div那样处理,两个行内元素将像span那样处理。
图1-3:添加样式后的XML文档
在学习如何编写CSS之前,要先知道如何把CSS关联到文档上。毕竟,如果不这么做,CSS就没办法影响文档。
1.3把CSS应用到HTML上
HTML文档内部有一定的结构,而这与视觉结构完全是两码事。我们可能急于创建最酷的网页,可能会以各种方式摆放页面的内容,但却忘了网页应该包含结构化的信息。
为了更好地理解这一点,下面以一个HTML文档为例,逐一说明各部分:
<html>
<head>
<title>Eric’s World of Waffles</title>
<meta http-equiv=”content-type” content=”text/html; charset=utf-8″>
<link rel=”stylesheet” type=”text/css” href=”sheet1.css” media=”all”>
<style type=”text/css”>
/* These are my styles! Yay! */
@import url(sheet2.css);
</style>
</head>
<body>
<h1>Waffles!</h1>
<p style=”color: gray;”>The most wonderful of all breakfast foods is the waffle—a ridged and cratered slab of home-cooked, fluffy goodness that makes every child’s heart soar with joy. And they’re so easy to make! Just a simple waffle-maker and some batter, and you’re ready for a morning of aromatic ecstasy!
</p>
</body>
</html>
这段标记应用样式后得到的结果如图1-4所示。
图1-4:文档示例
1.3.1 link标签
先看link标签:
<link rel=”stylesheet” type=”text/css” href=”sheet1.css” media=”all”>
图1-5中的文档链接了一个名为sheet1.css的样式表。
通过link标签链接的样式表不是HTML文档的一部分,但却供文档使用。我们称这样的样式表为外部样式表(external stylesheet),因为样式表在HTML文档外部
为了正确加载外部样式表,link标签必须放在head元素中,不能放在其他元素中。Web浏览器遇到link标签时,会查找并加载指定的样式表,使用样式表中的样式渲染HTML文档。这一过程如图1-5所示。
图1-5:文档应用外部样式表的方式
外部样式表中包含什么呢?是一系列规则,这里的规则存储在单独的文件中。
h1 {color: red;}
h2 {color: maroon; background: white;}
h3 {color: white; background: black; font: medium Helvetica;}
仅此而已,没有HTML标签或注释,只有一些简单的样式声明。外部样式表保存为纯文本文件,扩展名通常是.css,例如sheet1.css。
文件扩展名不是必须的,但是如果文件名不以.css结尾,即使在link元素中把type属性的值设为text/css,有些旧的浏览器也不会将其识别为包含样式表的文件。
属性
link标签余下的内容,即那些属性和值比较容易理解。rel是“relation”(关系)的简称,这里指定的关系是stylesheet。type属性的值始终为text/css,说明通过link标签加载的数据类型。这样Web浏览器才知道加载的样式表是CSS样式表,然后确定如何处理加载的数据。
接下来是href属性,它的值是样式表的URL,可以是绝对地址,也可以是相对地址,具体由需求而定。前例使用的是相对URL。此外,也可以使用绝对URL,例如http://meyerweb.com/sheet1.css。
最后是media属性,它的值是一个或多个媒体描述符(media descriptor),指明媒体的类型和具有的功能。多个媒体描述符以逗号分开。例如,可以像下面这样链接针对屏幕媒体和投影媒体的样式表:
<link rel=”stylesheet” type=”text/css” href=”visual-sheet.css”
media=”screen, projection”>
注意,一个文档可以关联多个样式表。如果是这样,最初显示文档时只会使用rel属性的值为stylesheet的link标签链接的样式表。因此,如果想链接两个分别名为basic.css和splash.css的样式表,可以这么做:
<link rel=”stylesheet” type=”text/css” href=”basic.css”>
<link rel=”stylesheet” type=”text/css” href=”splash.css”>
这样,浏览器会加载指定的两个样式表,合并样式规则后再应用到文档上。例如:
<link rel=”stylesheet” type=”text/css” href=”basic.css”>
<link rel=”stylesheet” type=”text/css” href=”splash.css”>
<p class=”a1″>This paragraph will be gray only if styles from the
stylesheet ‘basic.css’ are applied.</p>
<p class=”b1″>This paragraph will be gray only if styles from the
stylesheet ‘splash.css’ are applied.</p>
候选样式表
此外还有候选样式表(alternate stylesheet),定义方式为把rel属性的值设为alternate stylesheet。仅当用户自己选择,文档才会使用候选样式表渲染。
如果浏览器支持候选样式表,会使用link元素title属性的值生成候选样式列表。对下面的示例来说:
<link rel=”stylesheet” type=”text/css” href=”sheet1.css” title=”Default”>
<link rel=”alternate stylesheet” type=”text/css” href=”bigtext.css” title=”Big Text”>
<link rel=”alternate stylesheet” type=”text/css” href=”zany.css” title=”Crazy colors!”>
浏览器默认使用第一个样式表(这里是名为“Default”的样式表),此外用户还可以自行选择想使用的样式表。图1-6展示的是一种选择样式的方式。
图1-6:浏览器提供候选样式表供选择
此外,还可以为不同的候选样式表设定相同的title值,把它们分组放在一起。利用这一点,用户可以为屏幕和印刷媒体选择不同的外观。
<link rel=”stylesheet” type=”text/css” href=”sheet1.css” title=”Default” media=”screen”>
<link rel=”stylesheet” type=”text/css” href=”print-sheet1.css” title=”Default” media=”print”>
<link rel=”alternate stylesheet” type=”text/css” href=”bigtext.css” title=”Big Text” media=”screen”>
<link rel=”alternate stylesheet” type=”text/css” href=”print-bigtext.css” title=”Big Text” media=”print”>
如果用户在支持候选样式表的用户代理中选择“Big Text”,屏幕媒体将使用bigtext.css装饰文档,印刷媒体将使用print-bigtext.css,任何媒体都不会使用sheet1.css或print-sheet1.css。
另外,如果有一组首选样式表,那么只会使用其中一个,其他的则被忽略。比如下面这个例子:
<link rel=”stylesheet” type=”text/css” href=”sheet1.css” title=”Default Layout”>
<link rel=”stylesheet” type=”text/css” href=”sheet2.css” title=”Default Text Sizes”>
<link rel=”stylesheet” type=”text/css” href=”sheet3.css” title=”Default Colors”>
这三个link元素声明的都是首选样式表,因为都设定了title属性,但是文档只会使用其中一个,另外两个则完全被忽略。可是忽略的是哪两个呢?不确定,因为HTML没有提供相关的方法,无法确定该忽略哪些首选样式表,又该使用哪个首选样式表。
如果不为样式表设定标题,那它就是永久样式表(persistent stylesheet),始终用于显示文档。这通常正是文档编写人员想要的行为。
1.3.2 style元素
style元素也是一种引入样式表的方式,直接写在文档中:
<style type=”text/css”>…</style>
style元素应该始终设定type属性。对CSS文档来说,正确的值是“text/css”,这与link元素是一样的。
开始和结束style标签之间的样式称为文档样式表(document stylesheet)或嵌入式样式(embedded stylesheet,因为这种样式表内嵌在文档中)。style元素可以直接包含应用到文档上的样式,也可以通过@import指令引入外部祥式表。
1.3.3 @import指令
下面来看可以出现在stvle标答中的内容。首先是链接的外部样式表中也有的@import指令:
@import url(sheet2.css);
与link 一样,Web浏览器遇到@import指令时会加载外部样式表,使用其中的样式渲染HTML文档。二者之间唯一的主要区别在于句法和指令的位置。可以看出,@import指令在style元素内部,而且必须放在其他CSS规则前面,否则不会起作用。比如下面的例子:
<style type=”text/css”>
@import url(styles.css); /* @import comes first */
h1 {color: gray;}
</style>
与link一样,一个文档中可以有多个@import语句。然而,不同的是,@import指令导入的每个样式表都会使用,无法指定候选样式表。对下面的代码来说:
@import url(sheet2.css);
@import url(blueworld.css);
@import url(zany.css);
三个外部样式表都会加载,而且其中的所有样式都会用于显示文档。
与link类似,@import指令也可以显示导入的样式表应用于何种媒体。方法是在样式表的URL后面提供媒体描述符:
@import url(sheet2.css) all;
@import url(blueworld.css) screen;
@import url(zany.css) projection, print;
如果一个外部样式表需要用到另一个外部样式表中的样式,@import指令的作用就体现出来了。我们知道,外部样式表不能包含任何文档标记,也就是不能使用link元素,但是可以使用@import指令。因此,外部样式表中可能包含下述内容:
@import url(http://example.org/library/layout.css);
@import url(basic-text.css);
@import url(printer.css) print;
body {color: red;}
h1 {color: blue;}
此外还要注意,与内嵌在文档中一样,@import指令写在样式表的开头。CSS要求样式表中的@import指令必须在所有样式规则前面。遵守规范的用户代理会忽略放在样式规则(例如body {color: red;})后面的@import指令。
1.3.4 HTTP链接
为文档关联CSS还有一种鲜为人知的方式:使用HTTP首部。
在Apache中,若想使用这种方式,可以在.htaccess文件中引用CSS文件。例如:
Header add Link “</ui/testing.css>;rel=stylesheet;type=text/css”
这样设置之后,支持这种方式的浏览器在加载受此.htaccess文件管理的文档时便会使用指定的样式表,就像通过link元素链接的样式表一样。此外,还可以在服务器的httpd.conf文件中添加等效的规则,这样做可能更高效:
<Directory /path/to/ /public/html/directory>
Header add Link “</ui/testing.css>;rel=stylesheet;type=text/css”
</Directory>
截至2017年年末,广泛支持HTTP链接样式表的浏览器有Firefox系列和Opera。
1.3.5行内样式
如果只想为单个元素提供少量样式,不值得动用嵌入式样式表或外部样式表,可以利用HTML元素的style属性设置行内样式:
<p style=”color: gray;”>The most wonderful of all breakfast foods is the waffle—a ridged and cratered slab of home-cooked, fluffy goodness…
</p>
style属性的句法相当简单。其实,与style元素中的样式规则十分相似,不过是把花括号换成双引号。
注意,style属性的值只能是一系列规则声明,而不能包含整个样式表。
通常不建议使用style属性。而且,除了HTML,XML很少使用这个属性。倘若使用style属性,CSS的很多重要优点都不复存在了,例如集中管理样式,控制整个文档或网站中所有文档的外观。
1.4样式表中的内容
了解这么多之后,我们不禁要间,样式表中到底有什么内容呢?其实,我们见过的:
h1 {color: maroon;}
body {background: yellow;}
在深入讨论之前,我们要总览一下样式表中可以有什么内容,不可以有什么内容。
1.4.1标记
样式表中不能有标记。由于历史原因,style元素中可以有HTML注释。
<style type=”text/css”><!–
h1 {color: maroon;}
body {background: yellow;}
–></style>
仅此而已。
1.4.2规则的结构
一个规则由两个基本部分构成:选择符(selector)和声明块(declaration block)。声明块由一个或多个声明组成,而一个声明包含一个属性(property)和对应的值(value)。一个样式表由一系列规则构成。图1-7展示的是一个规则的各个部分。
图1-7:一个规则的结构
选择符(图中靠左的那一部分)定义文档中的哪部分受影响。图1-7选择的是h1元素。
图中右边那一部分是声明块,由一个或多个声明组成。一个声明包含一个CSS属性及其值。图1-7中的声明块包含两个声明,第一个声明把文档中部分文本的颜色设为红色,第二个声明把文档中那一部分的背景设为黄色。
1.4.3厂商前缀
有时你会发现,CSS中有些内容的前面有个标注,例如-o-border-image。这叫厂商前缀(vendor prefix),浏览器厂商通过它标记实验性或专属(或二者兼具)的属性、值或其他内容。截至2016年年末,市面上有不少厂商前缀,其中最常用的见表1-1。
表1-1:一些常用的厂商前缀
前缀 | 厂商 |
-epub- | 国际数字出版论坛置顶的ePub格式 |
-moz- | 基于Mozilla的浏览器 |
-ms- | 微软Internet Explorer |
-o- | 基于Opera的浏览器 |
-webkit- | 基于Webkit的浏览器(如Safari和Chrome) |
从表1-1中可以看出,厂商前缀的一般格式是一个英文破折号、一个标注和一个英文破折号。不过也有少量前缀不采用这个格式,开头没有破折号。
1.4.4处理空白
一般来说,CSS对待空白的方式跟HTML差不多:解析时,连续的空白会合并成一个空白。
当然,除此之外还有其他分隔方式。唯一的要求是,要使用空白分隔,可以是空格、制表符或换行符,可以是单个空白,也可以任意数量随意组合。
同样,规则之间的空白也可以随意使用。下面只是无数种编写方式中的五种:
html{color:black;}
body {background: white;}
p {
color: gray;}
h2 {
color : silver ;
}
ol
{
color
:
silver
;
}
1.4.5 CSS注释
CSS支持注释。与C/C++注释非常相似,CSS注释也放在/*和*/之间:
/*这是一个css1注释*/
与C++ 一样,CSS注释可以分成多行:
/*这是一个css1注释,可以分成
多行,完全没有问题*/
不过要注意,CSS注释不能嵌套。因此,下述示例是错误的:
/*这是一个注释,其中还有
一个注释,这是错的,
/*另一个注释*/
回到第一个注释*/
可惜,CSS没有一直延续到行尾的注释,即不能使用//或#等。例如,下面是正确的方式:
h1 {color: gray;} /*这个CSS注释有好几行 */
h2 {color: silver;} /* 而它放在样式旁边 */
p {color: white;} /* 因此每一行都要 */
pre {color: gray;} /* 放在注释标记里 */
如果各行没有结束标记,那么样式表的多数内容将变成注释的一部分,从而失去作用:
h1 {color: gray;} /* 这个CSS注释有好几行
h2 {color: silver;} 但是各行没有放在注释标记里
p {color: white;} 因此最后三个样式
pre {color: gray;} 变成了注释的一部分 */
在这个示例中,只有第一个规则(hi {color: gray;})会应用到文档上,余下的规则变成了注释的一部分,被浏览器的渲染引擎忽略。
1.5媒体查询
创作人员通过媒体查询(media query)定义浏览器在何种媒体环境中使用指定的样式表。
1.5.1用法
媒体查询可以在下述几个地方使用:
- link元素的media属性。
- style元素的media属性。
- @import声明的媒体描述符部分。
- media声明的媒体描述符部分。
1.5.2简单的媒体查询
在介绍媒体查询的各种可能用法之前,先看几个简单的媒体块。假设我们想在投影环境(例如幻灯片)中使用一些不同的样式。下面是这个CSS中比较简单的两个规则:
h1 {color: maroon;}
@media projection {
body {background: yellow;}
}
针对这个例子,在所有媒体中,h1元素的颜色都是红褐色,但是,在投影媒体中body元素会有一个黄色背景。
一个样式表中可以有任意多个@media块,而且每一个都有自己的一套媒体描述符(详情参见本章后文)。如果愿意,可以把所有规则都放在一个@media块里,就像下面这样:
@media all {
h1 {color: maroon;}
body {background: yellow;}
}
上述示例中的projection和all就是设定媒体查询的位置。媒体查询包含描述媒体类型的词组和对媒体参数的说明(例如分辨率或显示屏高度),决定块中的CSS何时应用。
1.5.3媒体类型
媒体查询最基本的形式媒体类型,由CSS2引入。媒体类型就是指明不同媒体的标注:
all:用于所有展示媒体。
print:为有视力的用户打印文档时使用,也在预览打印效果时使用。
screen:在屏幕媒体(如桌面电脑的显示器)上展示文档时使用。在桌面计算机上运行的所有Web浏览器都是屏幕媒体用户代理。
多个媒体类型使用逗号分隔罗列。下面四种方式都能把一个样式表(或一个规则块)同时应用到屏幕媒体和印刷媒体上:
<link type=”text/css” href=”frobozz.css” media=”screen, print”>
<style type=”text/css” media=”screen, print”>…</style>
@import url(frobozz.css) screen, print;
@media screen, print {…}
1.5.4媒体描述符
下面两种方式都能把指定的外部样式表应用到彩打上:
<link href=”print-color.css” type=”text/css”
media=”print and (color)” rel=”stylesheet”>
@import url(print-color.css) print and (color);
能使用媒体类型的地方都能使用媒体查询。继续以彩打为例,这意味着可以通过一个逗号分隔的列表列出多个查询:
<link href=”print-color.css” type=”text/css”
media=”print and (color), screen and (color-depth: 8)” rel=”stylesheet”>
@import url(print-color.css) print and (color), screen and (color-depth: 8);
只要其中一个媒体查询的条件得到满足,就会应用指定的样式表。
一个媒体描述符包含一个媒体类型和一个或多个媒体特性列表,其中特性描述符要放在圆括号中。如果没有媒体类型,那就应用到所有媒体上,因此下面两个示例是等效的:
@media all and (min-resolution: 96dpi) {…}
@media (min-resolution: 96dpi) {…}
一般情况下,媒体特性描述符的格式类似于CSS中的一对属性和值。二者之间最大的区别是,特性描述符可以不指定值。
多个特性描述符使用逻辑关键字and连接。媒体查询中可使用的逻辑关键字有两个:
and:连接的两个或多个媒体特性必须同时满足条件,整个查询得到的结果才是真值。
not:对整个查询取反。假如所有条件都为真,那样式表不会应用到文档上。例如,not (color) and (orientation: landscape) and (min-device-width: 800px)表示三个条目都满足时,整个语句得到的结果与之相反。因此,当媒体环境是彩色的、横向放着,而且设备的屏幕宽至少为800像素,样式表不会应用到文档上。除此之外的情况下,都将应用样式表。
注意,not关键字只能在媒体查询的开头使用。写成这样是无效的:(color) and not (min-device-width: 800px)。
媒体设备不支持OR关键字。不过,分隔多个媒体查询的逗号相当于OR。例如,screen,print的意思是,“为屏幕或印刷媒体时应用样式”
此外还有一个only关键词,专门用于保证向后兼容
only:在不支持媒体查询的旧浏览器中隐藏样式表。例如,如果想在所有媒体中应用一个样式表,但是只在支持媒体查询的浏览器中应用,可以这样写:@import url(newcss) only all。
1.5.5媒体特性描述符和值的类型
目前,我们在示例中见过一些媒体特性描述符了,但这不是全部。下面列出所有可用的描述符(截至2017年年末):
- width
- min-width
- max-width
- device-width
- min-device-width
- max-device-width
- height
- min-height
- max-height
- device-height
- min-device-height
- max-device-height
- aspect-ratio
- min-aspect-ratio
- max-aspect-ratio
- device-aspect-ratio
- min-device-aspect-ratio
- max-device-aspect-ratio
- color
- min-color
- max-color
- color-index
- min-color-index
- max-color-index
- monochrome
- min-monochrome
- max-monochrome
- resolution
- min-resolution
- max-resolution
- orientation
- scan
- grid
1.6特性查询
2015-2016年间,CSS新增了一个功能:根据用户代理是否支持特定的CSS属性及其值来应用一段样式。这个功能称为特性查询(feature query)。
特性查询在结构上与媒体查询很像。假设我们想在用户代理支持color属性时(显然是支持的)为元素设定颜色,可以这样写:
@supports (color: black) {
body {color: black;}
h1 {color: purple;}
h2 {color: navy;}
}
上述代码的意思其实是,“如果你能识别并处理color:black这样的属性和值组合,那就应用这段样式;否则,跳过这段样式。”如果用户代理不支持@supports,整段样式都会跳过。
特性查询是渐进增强样式的完美方式。比如说你想在浮动布局之外增加栅格布局,可以保留现有的布局方式,在样式表中添加下面这段样式:
@supports (display: grid ) {
section#main {display: grid;}
/* 去掉旧布局的样式 */
/* 栅格布局的样式 */
}
这段样式在支持栅格布局的浏览器中应用。它会覆盖旧的页面布局,然后应用通过栅格实现的新布局。不支持栅格布局的旧浏览器很可能也不支持@supports,因此会跳过整段样式,就像没出现过一样。
特性查询可以嵌套,其实还可以嵌套在媒体查询中,而且反过来嵌套也可以。若想使用弹性盒布局编写针对屏幕和印刷媒体的样式,可以把媒体查询块放在@supports (display: flex)块里:
@supports (display: flex) {
@media screen {
/* 针对屏幕媒体的弹性盒样式 */
}
@media print {
/* 针对印刷媒体的弹性盒样式 */
}
}
反过来,也可以在实现响应式设计的媒体查询块中添加@supports()块:
@media screen and (max-width: 30em){
@supports (display: flex) {
/* 针对小屏的弹性盒样式 */
}
}
@media screen and (min-width: 30em) {
@supports (display: flex) {
/* 针对大屏的弹性盒样式 */
}
}
与媒体查询一样,特性查询也支持使用逻辑运算符。假如想在用户代理同时支持栅格布局和CSS形状时应用一段样式,可以这样写:
@supports (display: grid) and (shape-outside: circle()) {
/* 栅格和形状样式 */
}
这与下述写法是等效的:
@supports (display: grid) {
@supports (shape-outside: circle()) {
/* 栅格和形状样式 */
}
}
除了and之外,还有其他的运算符可用。CSS形状(详情参见第10章)体现了or的用处,因为很长一段时间以来,WebKit只支持通过带厂商前缀的属性绘制形状。因此,如果想绘制形状,可以使用这样的特性查询:
@supports (shape-outside: circle()) or
(-webkit-shape-outside: circle()) {
/* 绘制形状的样式 */
}
带厂商前缀的形状属性和不带厂商前缀的形状属性最好同时使用,但是上例这样做既能兼容WebKit以后的版本,也能支持其他无需使用厂商前缀的浏览器。
有时,我们想使用的属性与测试的属性不同。还以栅格布局为例,你可能想在支持栅格时修改布局元素的外边距等。下面是简化的版本:
div#main {overflow: hidden;}
div.column {float: left; margin-right: 1em;}
div.column:last-child {margin-right: 0;}
@supports (display: grid) {
div#main {display: grid; grid-gap: 1em 0;
overflow: visible;}
div#main div.column {margin: 0;}
}
此外,还可以使用取反运算符。例如,下述样式在不支持栅格布局时应用:
@supports not (display: grid) {
/* 不支持栅格使用的样式 */
}
一个特性查询中可以使用多个逻辑运算符,但是为了保证条理清晰,要使用括号。假如我们想在支持颜色的同时还支持栅格或弹性盒布局中的一个时应用一段样式,可以这样写:
@supports (color: black) and ((display: flex) or (display: grid)) {
/* 相关的样式 */
}
注意,判断支持栅格或弹性盒的查询放在一对括号里。必须这么做,如若不然,整个表达式都将失效,而块中的样式则会跳过。也就是说,不要写成这样:
@supports (color: black) and (display: flex) or (display: grid) {
最后,你可能想知道,为什么特性查询的测试中既要写属性也要写值。毕竟,想使用形状时,我们只需要测试支不支持shape-outside,对吧?这是因为浏览器可能支持某个属性,但不支持它的全部取值。栅格布局就是个很好的例子。如果像下面这样测试是否支持栅格肯定是不行的:
@supports (display) {
/* 栅格样式 */
}
因为连Internet Explorer 4都支持display。支持@supports的浏览器肯定支持display及其很多取值,但不一定支持grid这个值。鉴于此,特性查询既要测试属性也要测试值。
转载请注明:陈童的博客 » CSS权威指南(第四版)读书笔记——第1章 CSS和文档