Warning:
This wiki has been archived and is now read-only.

CSS2/selector

From HTML5 Chinese Interest Group Wiki
Jump to: navigation, search

選擇器

模式匹配

在CSS中,模式匹配规则决定了哪项样式规则应用到文档树的哪个元素中。这些模式,通常成为选择器,包含了从一个简单的元素名到复杂的上下模式。如果模式中所有的条件都符合特定元素,那么这个元素和选择器就相匹配了。

选择器中元素名的大小写是否敏感取决于文档语言本身。例如,在HTML中,元素名是大小写不敏感的,但是在XML中,则是大小写敏感的。

下面的表格总结了CSS 2.1选择器中的语法:

模式 含义 对应描述的章节
* 匹配所有元素 通用选择器
E 匹配任意一个E元素(比如,一个type值为E的元素) type值选择器
E F 匹配所有作为E元素子孙的F元素 子孙选择器
E > F 匹配所有作为E元素子元素的F元素 子元素选择器
E:first-child 匹配所有E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:link E:visited 匹配所有E元素,这个元素是超链接的源锚点,并且这个标签没有被访问(:link)或者已经被访问(:visited) :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:first-child 匹配任意一个E元素,这个元素是其父级元素的第一个子元素 :first-child伪类
E:active

E:hover E:focus

匹配特定用户动作中的E元素 动态伪类
E:lang(c) 匹配所有E元素,并且此元素的语言为c(该语言为文档语言指定) :lang()伪类
E+F 匹配所有F元素,该元素需要处于同级元素E的前面 相邻选择器

选择器语法

一个简单选择器就是以type选择器或者通用选择器(*)开头,再跟上零个或者多个属性选择器,ID选择器或者伪类选择器。如果选择器的各个部分都匹配则确定该选择器匹配成功。

注意,在CSS 2.1中试用的术语和CSS3中使用有所不同。比如,CSS2.1的‘简单的选择器’只是CSS3中的一个分支。具体可以看CSS3选择器模块CSS3SEL

一个选择器是由一个或者多个简单选择器通过连接符号组合而成。一个由单个简单选择器组成的选择器会匹配满足条件的所有元素。签名增加一个简单选择器和连接符号会给选择器带来额外的匹配约束,于是一个选择器的主体总是与最后一个简单选择器相匹配元素的子集。

一个伪元素或许会被插入到选择器链的最后一个简单选择器后面,在这样的情况下样式信息会应用到每一个主体的子集中。

分组

当多个选择器共享同一份声明时,它们可以被分组到一个由逗号分割的列表内。

下面的例子中,我们对三条相同的CSS规则进行合并:

h1 { font-family: sans-serif }
h2 { font-family: sans-serif }
h3 { font-family: sans-serif }

相同的写法

h1, h2, h3 { font-family: sans-serif }

CSS还提供了其他简写方式,包括并联声明属性合并

通用选择器

通用选择器试用一个‘*’表示,用于匹配所有的元素的名字。它会匹配DOM树上的所有元素。

如果通用选择器是包含在一个[[[简单选择器]]]内部,则‘*’会被忽略。例如:

  • *[lang=fr] 和 [lang=fr] 是一样的
  • *.warning 和 .warning 是一样的
  • *#myid 和 #myid 是一样的

type选择器

type选择器会匹配文档中各类元素的名字。type选择器会匹配DOM树上所有对应类型的元素。

下面的规则会匹配DOM树上所有的H1元素:

h1{font-family: sans-serif}

后代选择器

现在,作者或许会需要一些选择器来匹配在DOM树上作为其他元素后代的元素(比如,‘匹配包含在H1元素中的所有EM元素’)。后代选择器表示了这类模式下的关系。一个后代选择器是由两个或者多个相互独立的选择器用空格连接而成。一个“A B”格式的后代选择器会匹配那些A元素下面的所有B元素。

例如,思考下面的样式规则:

h1 { color: red }
em { color: red }

虽然这些样式的目的是给文字增加颜色,但是上面样式的影响会在下面的例子里出现一些问题:

<H1>This headline is <EM>very</EM> important</H1>

这个例子的目的就是在前面样式的基础上设置所有在H1元素里EM元素的文字颜色为蓝色

h1 { color: red }
em { color: red }
h1 em { color: blue }

第三条样式规则会匹配下面的HTML片段中的EM:

<H1>This <SPAN class="myclass">headline is <EM>very</EM> important</SPAN></H1>

下面的选择器

div * p

会匹配一个P元素,并且该元素应该是DIV元素的孙元素或者更加后代的元素。注意“*”两边的空格并不是通用选择器的一部分;空格是作为连接符,来表示DIV必须是一些元素的祖先,而这些元素则需要时P元素的祖先。

下面规则的选择器包含了后代选择器和属性选择器,用于匹配含有href属性并且存在于P元素内部的元素,这个P元素也必须存在于DIV元素内部。

div p *[href]

子代择器

子代选择器会匹配一些元素的子代元素。子代选择器是由两个或者更多的选择器通过“>”连接而成。

下面的样式规则可以设置BODY元素下的所有子代P元素的样式:

body > P { line-height: 1.3 }

下面的例子同时使用了后代选择器和子代选择器:

div ol>li p

它会匹配所有作为LI元素后代的P元素;LI元素同时必须是OL元素的子代元素。OL元素也必须是DIV的后代元素。注意“>”两边的空格已经被移除。

关于选择第一个子代元素的选择器信息,可以阅读下面first-child伪元素章节。

相邻选择器

相邻选择器的语法是:E1 + E2, E2是选择器的主体。如果E1和E2在同一个父级元素下且E1直接位于E2的前面(忽略非元素类型的节点,比如文本节点和注释节点),则该选择器匹配成功

因此,下面的样式规则匹配了P元素紧跟在MATH元素后面的情况,该P元素不应该被缩进:

math + p { text-indent: 0 } 

下一个例子减少了直接相邻的H1和H2之间的垂直空间:

h1 + h2 { margin-top: -5mm }   

下面的样式规则和前一个例子类似,除了它增加了一个类名选择器。因此,只有当H1含有名为opener的class时,指定的效果才会应用:

h1.opener + h2 { margin-top: -5mm }   

属性选择器

CSS2.1允许作者去指定匹配元素特定属性的规则。

匹配属性和属性值

属性选择器有四种匹配方式:

[att]

    当元素设置了“att”属性,无论值是什么,都会匹配成功

[att=val]

    当元素的“att”属性为“val”时,匹配成功

[att~=val]

    当一个元素含有att属性,而且值是由空格连接的一些字符,其中一个是“val”。如果“val”里存在一些空格,则不会正确显示(因为文字被空格分割了)。如果“val”是一个空字符串,则也不会匹配成功。

[att|=val]

    当一个元素含有att属性,而且这个属性对应的值就是“val”,或者是以“val”开头,后面紧跟着“-”(U+002D)时,匹配成功。这样的匹配模式可以实现文字前缀的匹配(例如:HTML元素中的hreflang属性),在BCP 47及其后续中有所描述。如果要了解lang(或者xml:lang)前缀的匹配,可以阅读lang伪类

属性值必须是特定的标识符或者字符串。属性名和值是否大小写敏感,取决于文档语言本身的设置。

例如,下面的属性选择器会匹配所有制订了title属性的H1元素,无论值是什么:

h1[title] { color: blue; }

下面的例子里,选择器会匹配所有class值为“example”的span元素

span[class=example] { color: blue; }

多重属性选择器可以用于对应元素的多个属性,或者多次对同个属性进行匹配。

下面的例子,匹配所有hello值为“Cleveland”,并且goodbye值是“Columbus”的span元素:

span[hello="Cleveland"][goodbye="Columbus"] { color: blue; }

下面的选择器说明了“=”和“~=”之间的区别。第一个选择器可以匹配“rel”值为“copyright copyleft copyeditor”的元素。第二个选择器则只能匹配“href”值为“http://www.w3.org/”元素。

下面的样式会把所有“lang”属性为“fr”的元素设置为隐藏,(语言是French)。

*[lang=fr] { display : none }

下面的样式会匹配所有“lang”值为“en”开头的元素,包括“en”,“en-US”和“en-cockney”。

*[lang|="en"] { color : red }

类似地是,下面的听觉样式表会允许脚本在不同的声音下阅读:

DIALOGUE[character=romeo] 
     { voice-family: "Laurence Olivier", charles, male }
      
DIALOGUE[character=juliet]  
     { voice-family: "Vivien Leigh", victoria, female }

DTDs上的默认属性值

选择器匹配会发生在dom树的所有属性上。默认属性会在DTD或者其他地方定义,但是不能通过属性选择器匹配到。设计样式表的时候需要保证在默认值不在dom树上的时候,样式还是能正常应用。

更恰当的说法是,一个用户代理,没有必要一定去了解DTD的扩展子集。但是必须得了解文档子集的默认属性值。(阅读【XML10】来了解这些子集的定义)。DTD扩展子集中的默认属性值或许不会在文档树中出现,这取决于用户代理的实现。

一个可以识别XML命名空间的用户代理,没有强制要求去使用命名空间的支持去将默认属性值当作好像在文档中存在一样展示。(一个XHTML UA不会被要求去使用它的内置XHTML DTD)

注意,经典的实现方式是忽略扩展子集

例如,如果一个元素含有“notation”属性,这个属性对应的默认值是“decimal”。DTD片段或许是

<!ATTLIST EXAMPLE notation (decimal,octal) "decimal">

如果样式表包含了下面的规则

EXAMPLE[notation=decimal] { /*... default property settings ...*/ }
EXAMPLE[notation=octal]   { /*... other settings...*/ }

第一条样式可能不能匹配含有默认值的“notation”属性,这个例子可能还不够清晰。为了覆盖所有的情况,属性选择器的默认值部分必须去掉:

EXAMPLE                   { /*... default property settings ...*/ }
EXAMPLE[notation=octal]   { /*... other settings...*/ }

这样,由于选择器EXAMPLE[notation=octal]是更加符合规范的,第二条样式声明会覆盖那些含有“notation”属性并且值为“octal”。需要注意的是,所有的属性声明只会应用到已经被未默认样式覆盖的情况。

class选择器

编写HTML的时候会用到class属性,我们可能会将点(.)作为类似~=对等的符号。因此,在HTML中,div.value和div[class~=value]的作用是一样的。class属性需要直接跟在点(.)符号后面。如果,用户代理会在XML文档中应用这些带点(.)的符号。如果用户代理包含了指定的命名空间来注明哪些属性是对应命名空间的“class”选择器,那么用户代理需要利用到XML文档中的符号点(.)。其中一个指定命名空间的例子就是规范中的prose,用来规定命名空间(例如,SVG 1.1 [SVG11]描述了SVG的“class”属性)还有一个用户代理是如何处理的,类似的还有MathML 3.0[MATH30]描述了MathML的"class"属性。)

例子,我们按照下面的方式来应用样式到所有的class~="pastoral"元素:

*.pastoral { color: green }  /* all elements with class~=pastoral */

或者只需要写

.pastoral { color: green }  /* all elements with class~=pastoral */

下面的样式就只会应用到符合class~="pastoral"条件的H1元素上:

H1.pastoral { color: green }  /* H1 elements with class~=pastoral */

按照上面的规则,下面的例子里第一个H1元素的文本不会是绿色,而第二个是绿色。

<H1>Not green</H1>
<H1 class="pastoral">Very green</H1>

为了匹配“class”值的子类,每一个值必须通过一个“.”分隔。

比如,下面的规则会匹配所有P元素,如果它们的“class”属性是一连串空格分隔的值,并且要包含“pastoral”和“marine”:

p.marine.pastoral { color: green }

这个样式会匹配到class="pastoral blue aqua marine",但是没有不会匹配到class="pastoral blue"的元素。

注意:CSS给"class"属性提供了强大的能量,以至于作者可以想象到设计一门基于没有语义的元素“文档语言”(比如HTML里的DIV和SPAN),并且可以通过“class”属性来应用样式。由于文档语言中的结构化元素通常会含有已经被认知的还有一些被接受的意思,但是开发者自定义的却未必,这是开发者需要避免的。

注意:如果一个元素含有多个class属性,在进行查找之前,他们的值必须通过空格连接。现在,工作小组还没有了解这样情况下的处理方式,那么,对应的处理方式也就不会在规范里提及。

ID选择器

文档语言可能会包含以id声明的属性。真正让ID特别的地方是它的唯一性,文档中不能包含一样的ID值;无论文档语言是什么类型,ID属性总是会被作为元素的唯一标志存在。在HTML中,所有的ID属性都以"id"命名;XML应用可能会有不一样的ID属性,但是一样的应用场景。

文档语言的ID属性允许作者去应用一个标识符到文档数中的一个元素实例上。CSS ID选择器会匹配一个基于对应标识符的元素实例。一个CSS ID选择器会包含一个紧跟在ID值后面的“#”符号,这个符号必须是一个标识符。

注意CSS不会指向UA识别元素ID属性的方式。UA可以通过读取文档的DTD,直接硬编码进去或者询问用户的方式实现。

下面的ID选择器会匹配ID属性的值为“chapter1”的H1元素:

h1#chapter1 { text-align: center }

在下面的例子里,样式规则会匹配ID值为 "z98y" 的元素。样式会因此匹配到P元素:

<HEAD>
  <TITLE>Match P</TITLE>
  <STYLE type="text/css">
    *#z98y { letter-spacing: 0.3em }
  </STYLE>
</HEAD>
<BODY>
   <P id=z98y>Wide text</P>
</BODY>

在下一个例子里,样式规则只会匹配一个ID值为"z98y"的H1元素。而不会匹配到P元素上:

<HEAD>
  <TITLE>Match H1 only</TITLE>
  <STYLE type="text/css">
    H1#z98y { letter-spacing: 0.5em }
  </STYLE>
</HEAD>
<BODY>
   <P id=z98y>Wide text</P>
</BODY>

ID选择器在属性选择器中有更高的优先级。例如在HTML中,选择器#p123比[id=p123]优先级更高。

注意:在XML 1.0[XML1.0]中,哪个属性包含了元素的ID实在DTD中规定的。当解析XML的时候UA不会总是读取DTD,因此可能会出现某个元素的ID不被识别。如果一个样式表的设计者知道或者对此产生质疑,他需要使用普通的属性选择器来替代:[name=p371]替代#p371。然而,普通属性选择器的优先级也和ID选择器的不一样。他可能需要增加一个“!important”来声明:[name=p371]{color:red!important}。

如果一个元素含有多个ID属性,所有都会认为是元素的ID,应用的选择器也是有所的ID组成。这样的情况可能在XML:ID混用时出现[XMLID],dom3 核心[DOM-LEVEL-3-CORE], XML DTDs [XML10]和指定命名空间的技术上。

伪元素选择器和伪类选择器

在CSS2.1中,样式应用到元素的方式与其在文档树上的位置有关。这个简单的模型可以满足很多情况,但是一些普通的文本场景可能会因为DOM树结构的不同而出现一些问题。例如,在HTML4中,没有元素可以表达段落的第一行,也没有简单的选择器可以指向它。

CSS引入了伪元素和伪类的概念来允许基于DOM树之外的信息进行格式化:

  • 伪类创建了文档语言规定的文档树之外的抽象位置。例如,文档语言不会提供访问第一个字母或者第一行文字的机制。CSS伪类允许样式设计者去访问这些本来不可访问的信息。伪类还会提供一个方式来将样式应用到不存在源文档上的内容(例如,:before和:after伪类会访问到新生成的内容)。
  • 伪类会通过使用元素的name,属性以及内容之外的特征来对元素进行分类。这些特征在原则上不会在文档树上出现。伪类可以使动态的,这是因为元素可以在用户和文档进行交互的时候获得或者市区一个伪类。“:first-child”这样的伪类会直接在文档树上找到,而“:lang()”这样的伪类只会在部分情况下出现。

伪类和伪元素都不会在文档源或者文档树上出现。

伪类允许在选择器的任意位置出现,而伪元素只能出现在简单选择器的最后。

伪元素和伪类是大小写敏感的。

一些伪类是相互独立的,这意味着多个伪类可能作用于同个元素。最终的效果由规则的顺序决定。

伪类

:first-child伪类

first-child伪类用于匹配元素的第一个子元素。

下面的例子里,选择器会匹配DIV元素下的第一个P元素。该样式规则用于控制DIV下第一条段落的缩进。

div > p:first-child { text-indent: 0 }

这个选择器会匹配下面片段中DIV内部的的P元素。

<P> The last P before the note.
<DIV class="note">
   <P> The first P inside the note.
</DIV>

但是不会匹配下面片段中的P元素,因为这个P元素是DIV的第二个子元素。

<P> The last P before the note.
<DIV class="note">
   <H2>Note</H2>
   <P> The first P inside the note.
</DIV>

下面的规则会将所有的EM元素的font weight属性设置为“bold”,条件是EM必须是所有P元素的第一个子元素的子元素。

p:first-child em { font-weight : bold }

注意,由于匿名盒并不是文档树的一部分,所以并不会作为第一个子元素计算。

比如,下面例子中的EM元素:

<P>abc <EM>default</EM> 

依然是P元素的第一个子元素。

下面的两个选择器是等价的:

* > a:first-child   /* A元素是所有元素的第一个子元素 */
a:first-child       /* 等价 */

链接伪类::link和:visited

用户代理通常在表现上会区分没有访问过的链接和访问过的链接。CSS提供了伪类“:link”和“:visited”来对它们进行辨别:

  •  :link伪类会对所有没有被访问过的链接元素生效
  •  :visited伪类会应用到所有已经被用户访问过的元素上

在点击一个没有访问过的链接之后,用户代理会将其设置成点击过的链接。

这两个状态是相互独立的。

文档语言会规定哪些元素是作为超链接元素。例如,在HTML4中,伪类连接会应用到含有“href”属性的A元素上。因此,下面的CSS 2.1声明是一样的效果:

a:link { color: red }
:link  { color: red }

如果下面的链接:

<A class="external" href="http://out.side/">external link</A>

已经被访问过了,那么这条规则:

a.external:visited { color: blue }

会使这个链接变成蓝色。

注意,即使用户没有同意,还是可以通过滥用:link和:visited伪类来告知用户那些链接已经被访问过。

用户代理因此会将所有的连接都当作没有访问过的处理,或者实现其他措施来保护用户在面对链接访问过和未访问过的渲染不同时的权利。阅读P3P来了解更多处理用户权利的信息。

动态伪类::hover,:active和:focus

用户和用户代理之间的交互会需要改变界面的渲染。CSS提供了三个伪类来满足日常需求:

  •  :hover伪类用于当用户的选定某个元素(使用一些选定的设备),但是并没有对其进行激活。例如,一个可视的用户代理可以在鼠标位于一个元素的盒形范围上的时候,应用伪类的样式。用户代理或许不支持交互媒体,也就不会支持这样的伪类。一些符合条件支持交互媒体的用户代理也可能不支持这个伪类(例如,触控笔操作的用户代理)
  •  :active伪类在一个元素被用户激活的时候生效。例如,在用户用鼠标点击按钮并释放的过程中。
  •  :focus伪类在元素被聚焦的时候生效(通过键盘事件或者其他表单的文本框)

一个元素可以在同个时间匹配多个伪类。

CSS没有定义哪些元素可以拥有这些状态,或者这些状态如何开始和结束。脚本也可以控制这些样式是否反应给用户,不同的设备和用户代理也有不同的方式来指向或者控制元素。

CSS 2.1没有定义父元素也处于:active或者:hover时的处理情况。

用户代理不是一定要因为伪类变化而重绘当前的文档树。比如,一个样式表规定了一个:active元素的“font-size”变得比正常情况下大,但是由于这个变化会导致字符位置的变化,用户带可以或许会忽视这样的样式规则。

a:link    { color: red }    /* unvisited links */
a:visited { color: blue }   /* visited links   */
a:hover   { color: yellow } /* user hovers     */
a:active  { color: lime }   /* active links    */

注意A:hover必须处于A:link和A:visited规则的后面,因为不这样的话,样式表的优先级计算会把hover规则的color属性隐藏掉。相同的是,因为A:active是在A:hover的后面,active状态对应的颜色也会在用户激活和hover一个元素的时候出现。

一个合并使用动态伪类的例子:

a:focus { background: yellow }
a:focus:hover { background: white }

最后一个选择器会匹配同时处于focus和hover状态下的A元素。

关于focus outline的展示,请查看动态focus outline的章节。

注意,在CSS1中,“:active”伪类和“:link”与“:visited”伪类是相互独立的。这已经不再是一个问题。一个元素可以同时是“:visited”和“:active”(或者“:link”和“:active”),并且通常的样式优先级规则会决定哪个样式声明来应用。

注意,在CSS1中,“:active”伪类只会应用到链接上。

语言伪类::lang

如果文档语言制定了元素的语言,那就可以基于一个元素的语言对其写特定的CSS选择器。例如,在HTML4中,语言是由“lang”属性,META元素和协议的信息指定的。XML使用叫做xml:lang的属性,并且还会存在其他文档的语言指定方法来指定语言。

“:lang(C)”伪类会匹配语言是C的元素。是否能匹配取决于标识符C是不是能等于或者是元素lang值的一部分,和“|=”操作符的行为一样。元素语言值的匹配是大小写敏感的,并且限制在ASCII范围内。C不需要是一个有效的语言名。

C不能为空。

注意,推荐的做法是文档和协议都使用BCP 47BCP47或者其后续规则来指定语言,并且从字面上看“xml:lang”属性是在基于XML的文档上使用的。阅读“FAQ:两个字母或者三个字母的语言代码”。

下面的规则会设置语言是加拿大语,法语或者德语的HTML文档中的引用标志:

html:lang(fr-ca) { quotes: '« ' ' »' }
html:lang(de) { quotes: '»' '«' '\2039' '\203A' }
:lang(fr) > Q { quotes: '« ' ' »' }
:lang(de) > Q { quotes: '»' '«' '\2039' '\203A' }

第二对规则会根据其父元素的语言来设置Q元素的“quotes”属性。这样能生效的原因是引用标志的选择是基于周围元素的元素语言,而不是引用本身:就像英文中的一句法语“à l'improviste”会使用英文的引用标志。

注意,[lang|=xx]和:lang(xx)是不一样的。在下面的HTML例子里,虽然BODY和P元素都可以匹配:lang(fr)(因为都是法语),只有BODY会匹配[lang|=fr](因为它含有LANG属性)。

<body lang=fr>
  <p>Je suis Français.</p>
</body>

伪元素

伪元素行为就像在CSS中的真实元素一样,如下面或者其他地方的描述

注意本章节并没有定义所有情况下“:first-line”和“:first-letter”渲染的方式。未来的CSS或许会对其做一些定义

:first-line伪类

first-line伪类会给段落的第一行应用样式。例如:
p:first-line { text-transform: uppercase }

上面的规则表示“将每一段文字的第一行文字设为大写”。然而,选择器“p:first-line”不会匹配任何HTML元素。它实际上会匹配一个由[1]代理在每一段文字前插入的伪类。

注意,第一行文字的长度有很多影响因素,包括页面的宽度,文字尺寸等等。因此,一段普通的HTML段落比如:

<P>This is a somewhat long HTML 
paragraph that will be broken into several 
lines. The first line will be identified
by a fictional tag sequence. The other lines 
will be treated as ordinary lines in the 
paragraph.</P>

结果如下

THIS IS A SOMEWHAT LONG HTML PARAGRAPH THAT
will be broken into several lines. The first
line will be identified by a fictional tag 
sequence. The other lines will be treated as 
ordinary lines in the paragraph.

上面的结果也有可能被浏览器重写,因为浏览器给其插入为:first-line准备的包含标签序列。这个虚拟标签帮助展示了属性是如何被继承。

<P:first-line> This is a somewhat long HTML paragraph that </P:first-line> will be broken into several lines. The first line will be identified by a fictional tag sequence. The other lines will be treated as ordinary lines in the paragraph.

如果一个伪类影响了一个真实元素,那么想要的效果会经常被用于关闭和重新打开元素的虚拟标签序列描述。因此,如果我们给前面的段落增加一个span元素作为标记:

<P><SPAN class="test"> This is a somewhat long HTML
paragraph that will be broken into several
lines.</SPAN> The first line will be identified
by a fictional tag sequence. The other lines 
will be treated as ordinary lines in the 
paragraph.</P>

当给:first-line插入虚拟标签序列的时候,用户代理会计算span开始和结束的标签。

<P><P:first-line><SPAN class="test"> This is a
somewhat long HTML
paragraph that will </SPAN></P:first-line><SPAN class="test"> be
broken into several
lines.</SPAN> The first line will be identified
by a fictional tag sequence. The other lines
will be treated as ordinary lines in the 
paragraph.</P>
first-line伪类只会应用在级包含元素上
元素的“格式化首行”可能会存在于相同流下的块级子元素上(例如,一个没有定位也没有浮动的块级子元素)。例如,

This line...

中DIV的第一行是P的第一行(前提是P和DIV都表现为块级元素)。 table-cell或者inline-block元素的第一行无法作为格式化首行。因此,在

Hello
Goodbye

etcetera
下,DIV的格式化首行并不是“Hello”。 注意下面片段中P元素的首行,


First...没有包含任何字母(假设这是HTML4中的默认样式)。“First”也不是格式化首行。 如果first-line的伪类虚拟起始标签被插入到内部,那么用户代理应当表现的和大部分闭合块级元素一样。(Since CSS1和CSS2在这方面都没有例子,作者并不需要回应这个行为)。这里有一个例子。下面HTML片段的虚拟标签序列:

<DIV>
  <P>First paragraph</P>
  <P>Second paragraph</P>
</DIV>

<DIV>
  <P><DIV:first-line><P:first-line>First paragraph</P:first-line></DIV:first-line></P>
  <P><P:first-line>Second paragraph</P:first-line></P>
</DIV>
first-line伪类和行内元素类似,但是有一些特定的限制:font properties, color property, background properties, 'word-spacing', 'letter-spacing', 'text-decoration', 'text-transform', and 'line-height' 这些属性都无法生效。用户代理在其他属性上正常处理就行。

:first-letter伪元素

first-letter伪元素是用于匹配一段文字中第一行的第一个字母,前提是这个字母没有被替换成其他内容(比如images或者行内tables)。:firest-letter伪类可以用于处理“首字母大写”和“大写字母下坠”,这两个需求都来自日常的排版效果。此类大写首字母有点类似没有float属性的行内元素或者含有float属性的元素。

可以应用在:first-letter伪类上的属性有:font属性,'text-decoration', 'text-transform', 'letter-spacing', 'word-spacing' (适当的值), 'line-height', 'float', 'vertical-align' (只有在float值为none的时候), margin properties, padding properties, border properties, color property, background properties。用户代理也许会让其他属性也能生效。为了让用户代理能正确渲染“首字母大写”和“大写字母下坠”,不同于其他普通元素的处理,用户代理需要基于字母的形状选择行高,宽度和高度。CSS3在未来或许会有一些特定的属性用于设定first-letter。

这个例子展示了首字母大写的渲染。注意虽然first-letter继承的行高是1.1,但是用户代理针对首字母采用了不同的计算方式,其结果就是两行之间不会有多余的空白。同时,我们还需要注意首字母的虚拟标签是在SPAN里的,因此首字母的font weight是普通,而不是SPAN的bold。

p { line-height: 1.1 }
p:first-letter { font-size: 3em; font-weight: normal }
span { font-weight: bold }
...
<p><span>Het hemelsche</span> gerecht heeft zich ten lange lesten<br>
Erbarremt over my en mijn benaeuwde vesten<br>
En arme burgery, en op mijn volcx gebed<br>
En dagelix geschrey de bange stad ontzet.

下面的例子里,CSS2.1会在两行之间产生一个大写字母下坠的效果:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
 <HEAD>
  <TITLE>Drop cap initial letter</TITLE>
  <STYLE type="text/css">
   P              { font-size: 12pt; line-height: 1.2 }
   P:first-letter { font-size: 200%; font-style: italic;
                    font-weight: bold; float: left }
   SPAN           { text-transform: uppercase }
  </STYLE>
 </HEAD>
 <BODY>
  <P><SPAN>The first</SPAN> few words of an article
    in The Economist.</P>
 </BODY>
</HTML>

这个例子的实际效果类似下面:

File:Http://www.w3.org/TR/CSS2/images/first-letter.png

虚拟标签序列展示:

<P>
<SPAN>
<P:first-letter>
T
</P:first-letter>he first
</SPAN> 
few words of an article in the Economist.
</P>

注意:first-line伪类起始标签是插入在块级元素的起始标签后面,而:first-letter伪类标签是紧靠文字内容的。

为了实现传统的文字下坠效果,用户代理会让文本有个近似的尺寸,比如参考对齐用的基线。同时,字形的outline也会在计算的范围内。

一些标点符号,比如Unicode里定义的"open" (Ps), "close" (Pe), "initial" (Pi). "final" (Pf) 和 "other" (Po) 标点类,字母前后的标点符号都应该算作计算范围内。

File:Http://www.w3.org/TR/CSS2/images/first-letter2.png

如果首字母是一个数字,那么:first-letter也应该生效,例如,"67 million dollars is a lot of money."里的字符“6”。

first-letter为元素也可以应用在块级容器元素上。
first-letter伪类可以用在所有包含文本或者在含有同个流下子元素并含有文本的元素上。用户代理要做的就是把first-letter伪类的虚拟起始标签插入到文本的前面,即使这段文本在子元素上也一样。

这里有一个例子,展示了下面HTML片段里的虚拟标签序列:

<div>
<p>The first text.
is:
<div>
<p><div:first-letter><p:first-letter>T</...></...>he first text.
table-cell或者inline-block元素的首字母不能是其父元素的首字母。因此在
<P STYLE="display: inline-block">Hello
Goodbye</P> etcetera
中,DIV的首字母不是“H”。实际上,DIV并没有首字母。

首字母必须出现在第一个格式化行内。例如,在片段“<p>
First... ”中,首行没有包含任何内容,:first-letter也就不会匹配任何内容(如果BR的样式是HTML4规定的默认样式)。所以,它并不能匹配“First”的“F”。

如果元素是一个列表项,那么':first-letter'会应用在列表项标记后面的主盒子中。如果列表项的list-style-position是inside,则用户代理可以忽略':first-letter'。如果一个元素含有':before' 或者 ':after' 内容,‘:first-letter’还是应用到包含内容的元素的首字母上。

例如,在规则'p:before {content: "Note: "}'生效后,选择器就会匹配到“Note”的"N"上。

一个语言可能会制定一些对待特定字母连接符的规则。在Dutch中,如果字母连接符“ij”出现在文字的开头,那么两个字母都会作为:first-letter为元素要匹配到的内容。

如果应用样式的首字母不在同一个元素上,比如<p>'T....</p>中的T,那么用户代理需要从其中一个元素中创建一个first-letter伪元素。

相同的是,如果一个块的首字母不是一行的起点(比如双向排序的文字),那么用户代理就不需要创建伪元素。

下面的例子阐述了重叠为元素是如何相互影响的。P元素的首字母表现为绿色并字体大小为24pt.剩下的首行字母会会变成蓝色,而段落的其余文字会变成红色。

p { color: red; font-size: 12pt }
p:first-letter { color: green; font-size: 200% }
p:first-line { color: blue }
<P>Some text that ends up on two lines</P>
Assuming that a line break will occur before the word "ends", the fictional tag sequence for this fragment might be:
<P>
<P:first-line>
<P:first-letter> 
S 
</P:first-letter>ome text that 
</P:first-line> 
ends up on two lines 
</P>

注意,:first-letter元素是在:first-line元素内。设置在:first-line上的属性会被:first-letter继承,但是可以被设置在:first-letter上的属性覆写。


before和after伪类

before和after为元素可以用于在元素的内容前后插入内容。这些内容会在实际内容中展示。

h1:before {content: counter(chapno, upper-roman) ". "}

当first-letter和first-line伪元素应用到已经设置:before和:after的元素上,则这些属性就会设置到实际生效的首字母上。

p.special:before {content: "Special! "}
p.special:first-letter {color: #ffd800}
This will render the "S" of "Special!" in gold.