以下学习内容是翻译自Apple的Programming with Objective-C,内容有部分删减,主要是自己一个学习和理解的过程,如有翻译不当,还请谅解。

Block是被添加到CObjective-CC++的语言级别的特性,它允许你创建不同的代码片段,这些代码片段可以作为值传入到方法或函数中。BlocksObjective-C对象,这意味着它可以被添加到类似NSArrayNSDictionary的集合中。他们同样有从封闭作用域中捕获值的能力,使他们类似于其他编程语言的closureslambdas

Block语法

定义一个block是使用^符号,就像这样:

1
2
3
^{
NSLog(@"This is a block");
}

就像函数和方法的定义,大括号表明了block的开始和结束。在这个例子中,block没有返回任何值,也没有任何参数。

以同样的方式,您可以使用一个函数指针来引用一个C函数,你可以定义一个变量来记录一个block,就像这样:

1
void (^simpleBlock)(void);

这个例子定义了一个变量:simpleBlock,该变量用于引用一个block,且该block没有参数且不返回值,这意味着您可以像下面这样将block字面赋给simpleBlock变量,就像这样:

1
2
3
simpleBlock = ^{
NSLog(@"This is a block");
};

要注意的是大括号末尾的分号。您同样可以结合变量定义和赋值:

1
2
3
void (^simpleBlock)(void) = ^{
NSLog(@"This is a block");
};

最后你就可以像下面这样来调用block了:

1
simpleBlock();

带参数和返回值的Block

Block是可以接受参数和返回值的,就像函数和方法那样。

作为一个例子,考虑一个变量引用到一个block,该block返回两个值的乘积:

1
double (^multiplyTwoValues)(double, double);

关联的block字面可能是这样的:

1
2
3
^ (double firstValue, double secondValue) {
return firstValue * secondValue;
}

当你声明和定义好了block,你可以调用它就像一个函数一样:

1
2
3
4
5
6
double (^multiplyTwoValues)(double, double) =
^(double firstValue, double secondValue) {
return firstValue * secondValue;
};
double result = multiplyTwoValues(2,4);
NSLog(@"The result is %f", result);

Block能从封闭作用域中捕获值

如果你在一个方法中定义了一个block,例如,它能从该方法的作用域中捕获任何能访问到的值,就像这样:

1
2
3
4
5
6
7
- (void)testMethod {
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
testBlock();
}

在这个例子中,anInteger是定义在block之外的,但是当block定义时该变量被捕获到了。

只有值被捕获了,除非你指定。这意味着当你在定义block和调用block之间改变该变量的外在值时,就像这样:

1
2
3
4
5
6
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();

block捕获的值并没有受到影响。这意味着同样会输出:

1
Integer is: 42

使用__block来共享存储

如果你需要能够在block中改变捕获变量的值,你可以使用__block存储类型修饰符对原变量声明。这意味着该变量所在的存储是在原始变量的词法作用域和任何定义在该作用域的block之间共享。

作为一个例子,你可以重写之前都例子:

1
2
3
4
5
6
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();

因为anInteger被定义为一个__block变量,它的存储会在block定义中共享。上面的代码会输出:

1
Integer is: 84

这也意味着在block中可以修改原始值,就像这样:

1
2
3
4
5
6
7
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
anInteger = 100;
};
testBlock();
NSLog(@"Value of original variable is now: %i", anInteger);

以上会输出:

1
2
Integer is: 42
Value of original variable is now: 100

你可以传递Block给方法或函数作为参数

在前面的所有例子中,你都是定义block之后立即调用它。实践中,传递block给函数或方法调用是非常常见的。你可能会使用Grand Central Dispatch在后台调用block,例如,或者定义一个block代表重复被调用的任务,例如当枚举一个集合的时候。

Block也同样可以被用于回调,定义一些代码在任务完成后执行。作为一个例子,你的app可能需要通过创建一个对象来响应用户的动作以此处理复杂的任务,例如从web服务器请求信息。因为这个任务可能会需要很长一段时间,在任务正在进行时您应该显示某种进度指示器,而一旦任务完成,您就需要隐藏掉任务指示器。

这将可能使用委托来完成这些:您需要创建一个合适的委托协议,实现必须的方法,设置您的对象为任务的委托,然后等待您的对象在任务完成时调用委托方法。

Block使这些变得更加容易,然而,因为你可以定义回调行为在你初始化任务的时候,就像这样:

1
2
3
4
5
6
- (IBAction)fetchRemoteInformation:(id)sender {
[self showProgressIndicator];
XYZWebTask *task = ...
[task beginTaskWithCallbackBlock:^{
[self hideProgressIndicator];
}]; }

这个例子调用了一个方法来显示进度指示器,然后创建任务并开始。回调的block指定了在任务完成后执行的代码;在这种情况下,它只是调用了一个方法来隐藏进度指示器。要注意,这个回调block为了能够调用hideProgressIndicator方法而捕获了self。有一点非常重要的是在捕获self时要非常注意,因为它会造成strong reference cycle

在代码的可读性方面,block使得很容易在一个地方看出在任务完成之前和之后会发生什么,避免了需要通过跟踪委托方法来找出发生了什么事情。

下面是beginTaskWithCallbackBlock:方法的声明:

1
- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock;

(void (^)(void))指定了这个参数是一个不接受任何参数也没有返回值的block。该方法的实现可以以通常的方式来调用block

1
2
3
4
- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock {
...
callbackBlock();
}

block必须为方法的最后的参数

在方法中只使用一个block参数通常是最好的做法。如果一个方法同样需要其他的非block参数,那么block应该放在最后:

1
- (void)beginTaskWithName:(NSString *)name completion:(void(^)(void))callback

这也使得在方法调用时代码具有更好的可读性,就像这样:

1
2
3
self beginTaskWithName:@"MyTask" completion:^{
NSLog(@"The task is complete");
}];

使用类型定义简化block语法

如果你需要定义不只一个block,且它们具有相同的签名,你可能想定义自己的类型签名。

作为一个例子,你可以定义一个没有参数也没有返回值的简单block类型,就像这样:

1
typedef void (^XYZSimpleBlock)(void);

然后你就可以使用你的自定义类型来创建block了:

1
2
3
XYZSimpleBlock anotherBlock = ^{
...
};

对象使用属性来记录block

该语法定义了一个属性来记录一个block,这很类似一个block变量:

1
2
3
@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end

一个block属性就像其他block变量一样被设置和调用:

1
2
3
4
self.blockProperty = ^{
...
};
self.blockProperty();

同样可能使用类型定义来定义block属性声明,就像这样:

1
2
3
4
typedef void (^XYZSimpleBlock)(void);
@interface XYZObject : NSObject
@property (copy) XYZSimpleBlock blockProperty;
@end

捕获self时避免Strong Reference Cycles

如果你需要在block中捕获self,例如,当定义一个回调block,有一点非常重要当是要考虑内存管理的影响。

Block保持对任何捕获对象的强引用,也包括self,这意味着最后很容易造成强引用循环,例如,一个对象为一个block保持为一个copy属性然后捕获了self

1
2
3
@interface XYZBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end
1
2
3
4
5
6
7
@implementation XYZBlockKeeper
- (void)configureBlock {
self.block = ^{
[self doSomething];
};
}
... @end

编译器会警告你一个简单的例子是这样的,但更复杂的例子可能涉及到对象创建周期之间的多个强引用,使之更难以诊断。

为了避免这个问题,捕获一个对self对弱引用是最好的办法,就像这样:

1
2
3
4
5
6
7
- (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture the weak reference
// to avoid the reference cycle
}
}

Block简化枚举

除了一般的完成处理,许多CocoaCocoa Touch API使用block来简化常用的任务,如集合枚举。NSArray类,例如,提供了三个基于block的方法,包括:

1
2
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL
*stop))block;

该方法接受一个参数,它是一个block会被数组中的每一个元素调用:

1
2
3
4
NSArray *array = ...
[array enumerateObjectsUsingBlock:^ (id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"Object at index %lu is %@", idx, obj);
}];

Block简化并发任务

block代表了一个工作的不同单位,结合可执行代码和从周围作用域捕获的可选状态。这使得它非常适用于在iOS和OS X中使用并发选项之一来异步调用。而不必弄清楚如何与低层次的机制工作,就像线程,您可以使用block简单地定义你的任务,然后让系统执行这些任务随着处理器资源可用。

OS X和iOS提供了各种技术的并发性,其中包括两个任务调度机制:操作队列和Grand Central Dispatch,这些机制围绕队列任务等待被执行的想法。您按照您想block执行的顺序将blocks添加到队列中,然后系统将它们出列直到处理器时间和资源可用。

串行队列只允许一个任务同时执行——队列中的下一个任务将不被出列并调用直到前一个任务已完成。并发队列调用尽可能多的任务,无需等待前一个任务来完成。

使用Block操作与操作队列

操作队列是CocoaCocoa Touch的任务调度方式。你创建一个NSOperation实例为了封装工作单位以及任何必要的数据,然后将那个操作添加到NSOperationQueue执行。

尽管你创建了你自己的自定义NSOperation子类去实现复杂的任务,但还是可能去使用NSBlockOperation来用block创建一个操作,就像这样:

1
2
3
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
...
}];

这是可能手动去执行操作,但是操作可能通常被添加到一个已经存在到操作队列或你自己创建的一个队列,准备执行:

1
2
3
4
5
6
 // schedule task on main queue:
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperation:operation];
// schedule task on background queue:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];

如果你使用一个操作队列,你可以在操作之间配置优先级和依赖,例如指定某个操作必须在其他一些操作执行后才能操作。

调度Block在GCD的调度队列(Schedule Blocks on Dispatch Queues with Grand Central Dispatch)

如果你需要调度执行代码的任意块,你可以直接使用被GCD(Grand Central Dispatch )控制的调度队列,调度队列使得操作任务更加简单,不管是相对于调用者的同步或异步操作,且执行这些任务的顺序为先进先出。

你可以创建你自己的调度队列或使用GCD提供的队列。如果你需要调度一个任务为并发执行,例如,你可以通过dispatch_get_global_queue()获取一个存在队列的引用,和指定一个队列优先级,就像这样:

1
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

为了将block调度到队列,您可以使用dispatch_async()dispatch_sync()函数。dispatch_async()函数是立即返回,不用去等待block的执行。

1
2
3
dispatch_async(queue, ^{
NSLog(@"Block for asynchronous execution");
});

本文是从Selectors Level 3提取出的一些重点,如有不懂的地方可以看原文对照。

1. 选择器语法

一个选择器是一个或多个被连结符分隔的简单选择器序列组成的链。一个伪元素可能会附加到选择器中的最后一个简单选择器序列。

一个简单选择器序列是没有被连结符分隔的简单选择器组成的链。它总是以一个类型选择器通用选择器开始。除了类型选择器和通用选择器,没有其他类型的选择器允许在序列中。

一个简单选择器可以是类型选择器通用选择器属性选择器类选择器id选择器伪类

连结符可以是:空白、>+~

一个文档树的元素被选择器所代表,它是选择器的主题(subject)。一个选择器组成了一个简单选择器的单一序列,代表了任何满足它需求的元素。前面加上其他的简单选择器序列,且序列中的连结符施加了额外的匹配限制,所以一个选择器的主题总是最后一个简单选择器序列所代表的元素的子集。

一个空的选择器,没有包含简单选择器序列和伪元素,是一个无效的选择器

选择器中的字符可以根据在CSS2中相同的转义规则并通过\来转义。

2. 选择器组

一个逗号分隔的选择器列表表示了被任何单一选择器选择的所有元素的组合。例如,在CSS中当一些选择器共享相同的声明时,它们可以组合成一个逗号分隔的列表。空格可能出现在逗号的前面或后面。

CSS实例:

1
2
3
h1 { font-family: sans-serif }
h2 { font-family: sans-serif }
h3 { font-family: sans-serif }

上面等价于:

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

注意:在本例中等价是真的,因为所有的选择器是有效的选择器。如果选择器中的一个是无效的选择器,那么整个声明是无效的。

无效的CSS实例:

1
2
3
h1 { font-family: sans-serif }
h2..foo { font-family: sans-serif }
h3 { font-family: sans-serif }

不等价于:

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

在实际应用中也没有人这样写了。否则肯定早晚开除了。

3. 简单选择器

3.1 类型选择器

一个类型选择器是文档语言元素类型的名称,并使用CSS qualified names语法。一个类型选择器表示了在文档树中元素类型的实例。

实例

以下的选择器表示了在文档树中的h1元素:

1
h1

3.1.1 类型选择器和命名空间

类型选择器允许一个可选的命名空间组件:一个命名空间前缀被定义在元素名的前面,并通过|符号来分隔。

命名空间可能为空,代表了选择器没有命名空间。

一个*可被用作为命名空间前缀,表明代表了元素的所有命名空间。

元素类型选择器在没有命名空间组件时代表了元素不会考虑元素的命名空间(等价于*|),除非定义了一个默认的命名空间。如果一个默认命名空间被声明,这些元素会代表在默认命名空间中的元素。

那怎么定义默认命名空间呢?

1
2
@namespace "http://www.w3.org/1999/xhtml";
@namespace svg "http://www.w3.org/2000/svg";

上面的http://www.w3.org/1999/xhtml就为默认的命名空间。

总结(要注意的是|前后没有空格的哟):

ns|E
元素为E且在命名空间ns

*|E
元素为E且在任何命名空间中

|E
元素为E且没有命名空间

E
如果没有为选择器定义默认的命名空间,这个等价于*|E。否则等价于ns|E,且ns为默认的命名空间。

CSS实例:

1
2
3
4
5
6
@namespace foo url(http://www.example.com);
foo|h1 { color: blue } /* first rule */
foo|* { color: yellow } /* second rule */
|h1 { color: red } /* ...*/
*|h1 { color: green }
h1 { color: green }

第一条规则只会匹配在http://www.example.com命名空间中的h1元素。
第二条规则会匹配在http://www.example.com命名空间中的所有元素。
第三条规则只会匹配没有命名空间的h1元素。
第四条规则会匹配在任何命名空间中的h1元素。
第五条规则等价于第四条规则,因为没有默认的命名空间被定义。

3.2 通用选择器

通用选择器,用*来表示,它代表了任何元素类型的限定名。它代表了在文档树中的任何命名空间的任何单一元素,如果没有为选择器指定默认的命名空间。如果指定了默认的命名空间,可以看下面的通用选择器和命名空间

如果一个通用选择器不是选择器序列的唯一组件,或者它后面紧跟了伪元素,那么*可以省略,通用选择器隐含的表示存在。

实例:

  • *[hreflang|=en][hreflang|=en]是等价的
  • *.warning.warning是等价的
  • *#myid#myid是等价的

3.2.1 通用选择器和命名空间

通用选择器允许一个可选的命名空间组件。它可以按照以下方式来使用:

ns|*
ns命名空间中的所有元素

*|*
所有元素

|*
所有没有命名空间的元素

*
如果没有默认指定默认的命名空间,则等价于*|*,否则等价于ns|*,如果ns为默认的命名空间。

3.3 属性选择器

选择器允许表示元素的属性。当选择器被用作为一个表达式来匹配元素时,属性选择器必须认为匹配元素如果元素有一个属性且匹配属性选择器所代表的属性时。

3.3.1 属性存在和值选择器

CSS2介绍了四种属性选择器:

[att]
代表了元素有一个att属性,不管属性的值是什么。

[att=val]
代表了元素有一个att属性,且值为val。这种可以用于选择例如:input[type="text"]

[att~=val]
代表了元素有一个att属性,且它的值为空白分隔的列表,其中的一个值为val,如果选择器中的val包含了空白,它永远不会代表什么。同样,如果val为空字符串,它永远不会代表什么。

[att|=val]
代表了元素有一个att属性,且它的值为val或者val紧跟着-

实例:

下面的属性选择器代表了h1元素,且它有一个title属性,且不管值为多少:

1
h1[title]

下面的例子选择器代表了一个span元素它的class属性的值为example

1
span[class="example"]

下面的选择器代表了一个a元素,且它的hreflang属性值为enen-US

1
a[hreflang|="en"]

3.3.2 子字符串匹配属性选择器

三个附加的属性选择器被提供给匹配属性值的子字符串:

[att^=val]
代表了元素有一个att属性,且值以val前缀开始。如果val为空字符串,则这个选择器不会代表任何元素

[att$=val]
代表了元素有一个att属性,且值以val后缀结束。如果val为空字符串,则这个选择器不会代表任何元素

[att*=val]
代表了元素有一个att属性,且值包含至少子字符串val的一个实例。如果val为空字符串,则这个选择器不会代表任何元素

实例:

下面的选择器代表了一个HTMLobject,引用了一个图片:

1
object[type^="image/"]

下面的选择器代表了一个HTML链接a,且它的href属性以.html结尾:

1
a[href$=".html"]

下面的选择器代表了HTML段落中title属性包含了子字符串hello

1
p[title*="hello"]

3.3.3 属性选择器和命名空间

在属性选择器中的属性名是以CSS限定名给出:先前已声明的命名空间前缀可预先准备给由命名空间分隔符|分隔的属性名。为了保持命名空间在XML中的推荐,默认的命名空间不会应用到属性中,因此,没有命名空间组件的属性选择器只应用到那些没有命名空间的属性。一个*可能被用于命名空间前缀以表明该选择器可匹配所有属性名而不用考虑属性的命名空间。

一个属性选择器有一个属性名包含了命名空间前缀,但是该命名空间没有在之前定义,这时该属性选择器是一个无效的选择器。

CSS实例:

1
2
3
4
5
@namespace foo "http://www.example.com";
[foo|att=val] { color: blue }
[*|att] { color: yellow }
[|att] { color: green }
[att] { color: green }

第一条规则只匹配有在http://www.example.com命名空间下的属性att,且值为val的元素。

第二条规则只匹配具有属性att,且不管属性的命名空间。

最后两条规则是等价的,且只匹配具有属性att,且该属性不在任何命名空间下的元素。

3.3.4 在DTDs中的默认属性值

属性选择器代表了在文档树中的属性值。文档树如何构建是在选择器之外的。在某些文档格式中,默认的属性值可以定义在DTD或其他地方,如果它们出现在文档树中的话,这些只能通过属性选择器来选择。选择器的设计应该使它们工作,不管默认值是否包含在文档树中。

例如,一个XML的用户代理可能并不需要去读取一个DTD外部子集,但是需要在文档的内部子集寻找默认属性值(看这里:XML10)。取决于用户代理,一个定义在DTD的外部子集的默认的属性值可能会或可能不会出现在文档树中。

一个识别XML命名空间的用户代理可能不需要利用它的对于那个命名空间的认知来对待默认的属性值,就好像它们就在文档中。(例如,一个XHTML的用户代理不需要利用它内置的该XHTML DTD的认知)

实例:

考虑一个元素example,它有一个属性radix,且其默认值为decimalDTD片段可能为:

1
<!ATTLIST EXAMPLE radix (decimal,octal) "decimal">

如果样式表包含了这些规则:

1
2
EXAMPLE[radix=decimal] { /*... default property settings ...*/ }
EXAMPLE[radix=octal] { /*... other settings...*/ }

第一条规则可能不会匹配那些radix属性被设置为默认值的元素,即为明确设置。为了捕获所有情况,属性选择器的默认值必须被舍弃:

1
2
EXAMPLE                { /*... default property settings ...*/ }
EXAMPLE[radix=octal] { /*... other settings...*/ }

3.4 类选择器

HTML工作,作者可能会使用句点符号(也就是.)来代替~=符号表示class属性。因此,对于HTMLdiv.valuediv[class~=value]是具有同样的含义的。该属性值必须紧跟在.符号后面。

如果用户代理具有命名空间特定的知识,且允许它确定哪个属性是class属性用于各个命名空间,用户代理可能使用.符号在XML文档中应用选择器。

CSS实例:

我们可以通过以下方式来分配样式给所有class~="pastoral"的元素:

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

或者只是:

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

以下只分配样式给所有class~="pastoral"h1元素:

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

3.5 ID选择器

文档语言可以包含声明为ID类型的属性。ID类型属性的特殊之处在于在一致性的文档中没有两个这样的属性可以有相同的值,且不管携带该属性的元素类型;无论什么文档语言,一个ID类型属性可被用于唯一地标识其元素。

ID选择器是以#开头,然后紧跟着ID值。

实例:

以下ID选择器代表了一个h1元素,且它的id属性值为chapter1

1
h1#chapter1

不过很少会像上面这样写,一般是像下面这样:

1
#chapter1

3.6 伪类

伪类的概念被引入以允许选择位于该文档树以外或者使用其他简单选择器不能表达的信息。

一个伪类总是包含:跟着伪类的名称和一个可选的值被放在圆括号之间。

伪类中允许包含在选择器中的所有简单选择器序列。伪类可以出现在简单选择器序列的任何地方,类型选择器和通用选择器(可能省略)后面。伪类名是不区分大小写。一些伪类是相互排斥的,而另一些可以同时施加到相同的元素。伪类可能是动态的,在这个意义上,元素可能获得或失去一个伪类当用户与文档进行交互的时候。

3.6.1 动态伪类

动态伪类在特性上分类元素,除了它们的名字、属性或内容,原则上特性不能从文档树中推断出来。

动态伪类不会出现在文档源或文档树中。

3.6.1.1 链接伪类::link:visited

用户代理通常显示未访问的链接不同于之前访问过的。选择器提供了伪类:link:visited来区分它们。

  • :link伪类应用在那些没有被访问过的链接
  • :visited伪类应用在那些已经被用户访问过的链接

经过一定的时间,用户代理可能选择返回一个访问过的链接为:link状态。

这两种状态是互斥的。

实例:

下面的选择器代表了有一个external类的链接,且被访问过:

1
a.external:visited

用户代理可能会因此对待所有的链接为未访问链接,或者采取其他措施以保护用户的隐私,而对访问和未访问链接渲染出不同。

3.6.1.2 用户动作伪类:hover:active:focus

交互式用户代理有时会为了响应用户操作而改变呈现。选择器提供了三个伪类来选择这些用户正在作用的元素。

  • :hover伪类应用在当用户通过定位设备来指定元素,但不一定激活它时。例如,一个视觉用户代理可以应用伪类当光标悬停到元素所生成的盒子上时。用户代理不支持交互式媒体的不需要支持该伪类。支持交互式媒体的一些用户代理可能无法支持这个伪类。
  • :active伪类应用在正被用户激活的元素上。例如,在用户按下鼠标按钮和释放它之间。在多于一个鼠标按钮的系统,:active仅应用在主激活按钮(通常是鼠标左键),以及它们的任意别名。
  • :focus伪类应用在获得焦点的元素

这些伪类不是相互排斥的。一个元素可以在相同的时间匹配的几个伪类。

选择器没有定义当元素的父亲也在:active:hover状态时。

实例:

1
2
3
4
a:link    /* unvisited links */
a:visited /* visited links */
a:hover /* user hovers */
a:active /* active links */

或者结合多个动态伪类:

1
2
a:focus
a:focus:hover

3.6.2 目标伪类:target

一些URIs会引用资源内的一个位置。这种类型的URI是以#紧跟锚标识符结束。

有片段标识浮的URIs链接到文档内的某个元素,被称为目标元素。举例来说,这里给出了一个URI指向文档中一个名为section_2的锚。

1
http://example.com/html/top.html#section_2

一个目标元素可以使用:target伪类来表示。如果文档的URI没有片段标识符,则该文档没有目标元素。

实例:

1
p.note:target

这个选择器代表了一个p标签,且它有一个类note,且它是指定URI的目标元素时。

3.6.3 语言伪类:lang

如果文档语言指定了一个元素的人类语言如何确定,则可以使用选择器来代表基于该语言的元素。例如,在HTML中,语言是由lang属性和从meta元素的信息或HTTP协议联合决定的。XML使用一个叫做xml:lang的属性,并且还可能有其他的文档语言特定的方法,用于确定使用的语言。

伪类:lang(C)代表了在语言C中的元素。一个元素是否通过:lang被代表是完全基于元素的语言值是否和标识符C相等,或者是以标识符C开始并紧跟着-。对C和元素语言值的匹配是不区分大小写的。标识符C不必须是一个有效的语言名称。

C必须是一个有效的CSS标识符,且不能为空。

实例:

1
2
3
4
html:lang(fr-be)
html:lang(de)
:lang(fr-be) > q
:lang(de) > q

3.6.4 UI元素状态伪类

3.6.4.1 :enabled:disabled伪类

:enabled伪类代表了处于激活状态的用户界面元素;这些元素都有相应的禁用状态。

相反地,:disabled伪类代表了处于禁用状态的用户界面元素;这些元素都有相应的激活状态。

什么构成激活状态、禁用状态和用户界面元素是语言决定的。在一个典型的文档中大多数元素即不会是:enabled也不会是:disabled

那什么元素有这种状态呢,inputtextarea等元素。

1
2
3
4
5
6
7
8
9
10
11
<style>
input:disabled {
border: 1px solid blue
;

}
input:enabled {
border: 1px solid red
;

}
</style>


<input type="text" disabled>
<input type="text">
3.6.4.2 :checked伪类

单选框和复选框元素可以被用户切换。一些菜单项被勾选,当用户选择它们的时候。:checked伪类就是应用在这些有selectedchecked属性的元素,这些元素包含checkboxradiooption等。

实例:

1
2
3
4
5
6
7
8
9
10
<style>
input:checked + label {
color: red
;

}
</style>


<input type="checkbox">
<label>checkbox</label>
<input type="radio">
<label>radio</label>
3.6.4.3 :indeterminate伪类

这个是对于radiocheckbox有时处于一种模糊的状态,即不是checked,也不是unchecked

3.6.5 结构伪类

选择器引入了结构伪类的概念,允许基于在文档树中确定的信息来选择,但是不能通过其他简单选择器或连结符来表示。

当在它父亲的孩子列表中计算一个元素的位置时,独立文本和其他非元素节点不计算在内当计算在其父亲的孩子列表中的元素的位置,该指数的编号从1开始。

3.6.5.1 :root伪类

:root伪类代表了文档的根元素。在HTML4中总是html元素。

3.6.5.2 :nth-child()伪类

:nth-child(an+b)伪类可以代表在文档树中在它之前的有an+b-1个兄弟的元素,n可以为任何的正数或0,且有一个父元素。对于大于0的ab,这有效的将元素的孩子分成每组a个元素,然后选择每组中的第b个元素。例如,这使得选择器解决table中每隔一行的问题,并可以用于段落文本中每四个交替颜色。ab的值必须为整数。元素的子元素的索引是从1开始(要注意不是JavaScript等语言的0哟)。

除此之外,:nth-child()还可以接受oddeven作为参数。odd其实等价于2n+1even其实等价于2n

:nth-child()的参数必须匹配以下语法规则,INTEGER匹配[0-9]+,标记的其余部分是由Lexical scanner给出。

1
2
3
4
nth
: S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? |
['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S*
;

实例:

1
2
3
4
5
6
7
8
9
10
tr:nth-child(2n+1) /* represents every odd row of an HTML table */
tr:nth-child(odd) /* same */
tr:nth-child(2n+0) /* represents every even row of an HTML table */
tr:nth-child(even) /* same */

/* Alternate paragraph colours in CSS */
p:nth-child(4n+1) { color: navy
; }

p:nth-child(4n+2) { color: green; }
p:nth-child(4n+3) { color: maroon; }
p:nth-child(4n+4) { color: purple; }

b的值前面有一个负号,则+字符必须从表达式中移除。

实例:

1
2
3
:nth-child(10n-1)  /* represents the 9th, 19th, 29th, etc, element */
:nth-child(10n+9) /* Same */
:nth-child(10n+-1) /* Syntactically invalid, and would be ignored */

a=0,则an部分可以不包含。当an未包含且b为非负数,则在b前面的+字符也可省略。

实例:

1
2
3
foo:nth-child(0n+5)   /* represents an element foo that is the 5th child
of its parent element */

foo:nth-child(5) /* same */

a=1a=-1,数字可以从规则中省略。

实例:

1
2
3
4
bar:nth-child(1n+0)   /* represents all bar elements, specificity (0,1,1) */
bar:nth-child(n+0) /* same */
bar:nth-child(n) /* same */
bar /* same but lower specificity (0,0,1) */

b=0,则每一个第a个元素被选择。在这种情况,+b-b部分可能省略,除非a部分已经被省略。

实例:

1
2
tr:nth-child(2n+0) /* represents every even row of an HTML table */
tr:nth-child(2n) /* same */

空白是允许出现在(之后)之前,也可以出现在+-任何一方以分割anb部分,当它们都没有省略的时候。

有效的实例:

1
2
3
4
:nth-child( 3n + 1 )
:nth-child( +3n - 2 )
:nth-child( -n+ 6)
:nth-child( +6 )

下面是无效的:

1
2
3
:nth-child(3 n)
:nth-child(+ 2n)
:nth-child(+ 2)

ab都为0时,该伪类没有选择文档树中的任何元素。

a的值可能为负数,但是只有在an+b的正数位置才可以被选择。

实例:

1
html|tr:nth-child(-n+6)  /* represents the 6 first rows of XHTML tables */
3.6.5.3 :nth-last-child()伪类

其实这个伪类和前面的:nth-child()是很类似的,它只是从最后一个元素开始计算索引。:nth-last-child(an+b)伪类可以代表在文档树中在它之的有an+b-1个兄弟的元素,n可以为任何的正数或0,且有一个父元素。这个可以参考上面的:nth-child()语法。它同样接受oddeven作为参数。

实例:

1
2
3
4
tr:nth-last-child(-n+2)    /* represents the two last rows of an HTML table */

foo:nth-last-child(odd) /* represents all odd foo elements in their parent element,
counting from the last one */

3.6.5.4 :nth-of-type()伪类

这个伪类其实可以看成对:nth-child()施加了一个限制,那就是元素类型必须相同。:nth-of-type(an+b)伪类可以代表在文档树中在它之前有an+b-1个兄弟,且元素类型必须相同的元素,n可以为任何的正数或0,且有一个父元素。这个可以参考上面的:nth-child()语法。它同样接受oddeven作为参数。

实例:

1
2
img:nth-of-type(2n+1) { float: right; }
img:nth-of-type(2n) { float: left; }

再看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<style>
/*#demo p:nth-of-type(even) {
color: red;
}*/
#demo :nth-child(even) {
color: blue;
}
</style>

<div id="demo">
<p>1</p>
<p>2</p>
<p>3</p>
<a href="">4</a>
<p>5</p>
<p>6</p>
<p>7</p>
</div>

你可以在浏览器中对比以下这两个选择器的效果哟。

3.6.5.5 :nth-last-of-type()伪类

这个伪类和:nth-of-type(),只是从最后一个元素开始计算索引啦。:nth-last-of-type(an+b)伪类可以代表在文档树中在它之an+b-1个兄弟,且元素类型必须相同的元素,n可以为任何的正数或0,且有一个父元素。这个可以参考上面的:nth-child()语法。它同样接受oddeven作为参数。

实例:

1
body > h2:nth-of-type(n+2):nth-last-of-type(n+2)
3.6.5.6 :first-child伪类

:nth-child(1)相同。:first-child伪类代表一个元素为其他元素的第一个子元素。

实例:

下面的例子代表了一个p元素是div中的第一个元素。

1
div > p:first-child

选择器可以匹配下面HTML中div中的p

1
2
3
4
<p> The last P before the note.</p>
<div class="note">
<p> The first P inside the note.</p>
</div>

但是不能匹配下面divp元素,因为p不是div中的第一个子元素。

1
2
3
4
5
<p> The last P before the note.</p>
<div class="note">
<h2> Note </h2>
<p> The first P inside the note.</p>
</div>
3.6.5.7 :last-child伪类

:nth-last-child(1)相同。:last-child伪类代表一个元素为其他元素的最后一个子元素。

实例:

1
ol > li:last-child
3.6.5.8 :first-of-type伪类

:nth-of-type(1)相同。:first-of-type伪类代表一个元素,它是父元素中第一个具有相同元素名的元素。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dl dt:first-of-type {
color: red;
}

<dl>
<dt>gigogne</dt>
<dd>
<dl>
<dt>fusée</dt>
<dd>multistage rocket</dd>
<dt>table</dt>
<dd>nest of tables</dd>
</dl>
</dd>
</dl>
3.6.5.9 :last-of-type伪类

:nth-last-of-type(1)相同。:last-of-type伪类代表一个元素,它是父元素中最后一个具有相同元素名的元素。

实例:

1
tr > td:last-of-type
3.6.5.10 :only-child伪类

该伪类代表了一个元素,它的父元素除了它没有其他元素。其实等价于:first-child:last-child

3.6.5.11 :only-of-type伪类

该伪类代表了一个元素,它的父元素除了它没有其他元素,且和指定的元素类型相同。等价于:first-of-type:last-of-type

3.6.5.12 :empty伪类

:empty伪类代表了一个元素始终没有子元素。

实例:

p:empty可以代表以下html片段:

1
<p></p>

foo:empty不能代表以下片段:

1
2
3
<foo>bar</foo>
<foo><bar>bla</bar></foo>
<foo>this is not <bar>:empty</bar></foo>

3.6.6 空白

本节有意留为空白。(本节之前定义了一个:contains()伪类)

3.6.7 否定伪类

否定伪类,:not(x)是一个功能性的符号,它接受一个简单选择器作为参数。它代表了这些不是参数所代表的元素。

否定不能嵌套,:not(:not(...))是无效的。要注意当伪元素不是简单选择器,所以它们不是:not()的有效参数。

实例:

以下选择器匹配在HTML中没有被禁用的按钮:

1
button:not([DISABLED])

默认的命名空间声明不会影响否定伪类的参数,除非该参数是一个通用选择器或类型选择器。

实例:

假设默认的命名空间为http://example.com/,下面的选择器代表了所有不在该命名空间的元素:

1
*|*:not(*)

4. 伪元素

在文档语言规定之外,伪元素创建了一个关于文档树的抽象引用。例如,文档语言不提供机制来访问的一个元素的内容的第一个字母或第一行。伪元素允许作者引用这个本来无法访问的信息。伪元素还能提供作者一种方式去引用源文档中不存在的内容(::before::after)。

一个伪元素是由::跟着伪元素名称组成的。

::符号在文档中被引入是为了在伪类和伪元素之间建立一个区别。为了与现有的样式表的兼容性,用户代理必须同样接受一个冒号:的写法。

4.1 ::first-line伪元素

::first-line伪元素描述了元素的内容中被格式化的第一行。

CSS实例:

1
p::first-line { text-transform: uppercase }

上面的规则意思为将每个p元素的第一行的每个字母变为大写。

注意,第一行的长度取决于许多因素,包括该页面的宽度,字体大小等。因此,一个普通的HTML段落,如:

1
2
3
4
5
6
<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>

其中折行如下所示:

1
2
3
4
5
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。这个虚构的标签序列有助于说明属性如何继承。

1
2
3
4
5
6
<P><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.</P>

如果伪元素折断了一个真实的元素,所需的效果通常被描述为一个虚构的标签序列关闭,然后重新打开该元素。例如:

1
2
3
4
5
6
<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>

用户代理会像下面这样处理:

1
2
3
4
5
6
7
8
<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>

4.1.1 CSS中格式化的第一行的定义

在CSS中,::first-line伪元素只能在block-like容器上有效果,这些容器有block boxinline-blocktable-captiontable-cell

一个元素的格式化第一行可能发生在相同流的一个block-level后代中(例如,一个block-level后代没有脱离流)。例如,在<DIV><P>This line...</P></DIV>DIV的第一行为p元素的第一行。

table-cellinline-block的第一行不能成为一个祖先元素的格式化的第一行。因此,在<DIV><P STYLE="display: inline-block">Hello<BR>Goodbye</P> etcetera</DIV>中,DIV的格式化第一行不是Hello的那一行。

一个用户代理应当表现的就好像::first-line的虚拟开始标签伪元素被嵌套到最内层的block-level元素中。例如:

1
2
3
4
<DIV>
<P>First paragraph</P>
<P>Second paragraph</P>
</DIV>

加上虚拟标签后:

1
2
3
4
<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伪元素类似于一个inline-level元素,但有一定的限制。以下CSS属性应用到一个::first-line伪元素:字体属性、背景属性、颜色属性、word-spacingletter-spacingtext-decorationvertical-aligntext-transformline-height。用户代理也可能应用其他属性。

在CSS继承时,发生在第一行的子元素的一部分只从::first-line伪元素继承::first-line上可应用的属性。对于所有的其他属性,继承时从第一行伪元素的非鱼伪元素父元素中继承。

4.2 ::first-letter伪元素

::first-letter代表了一个元素的第一个字母,如果在该行中在它前面没有任何其他内容。::first-letter伪元素可能被用于首字母大写等用途。

标点符号,即第一个字母前面或后面也应包括在内。

enter image description here

当第一个字母为数字时,::first-line也同样被应用,例如,在67 million dollars is a lot of money.中的6

4.2.1 在CSS中的应用

在CSS中,::first-letter伪元素只能在block-like容器上有效果,这些容器有blocklist-iteminline-blocktable-captiontable-cell

::first-letter伪元素可和所有这些包含文本的元素或有一个后代包含文本且在相同的流的元素使用。用户代理也应该表现为好像虚拟的标签被加上。

实例:

1
2
<div>
<p>The first text.

表现为:

1
2
<div>
<p><div::first-letter><p::first-letter>T</...></...>he first text.

table-cellinline-block的第一个字母不能成为一个祖先元素的的第一字母。因此,在<DIV><P STYLE="display: inline-block">Hello<BR>Goodbye</P> etcetera</DIV>中,DIV的第一字母不是H。实际上,DIV没有第一个字母。

如果元素是一个list item::first-letter应用在主体框标记后的第一个字母。如果list item设置了list-style-position: inside,用户代理将忽略该列表项的::first-letter。如果一个元素有::before::after内容,::first-letter应用的时候包含了::before::after的内容。

实例:

例如:

1
p::before {content: "Note: "}

p::first-letter匹配Note中的N

在CSS中,::first-letter伪元素类似于一个inline-level元素,如果该元素的floatnone;否则,它和浮动元素相同。

4.3 空白

这里是故意留白的。(之前定义了::selection伪元素)

4.4 ::before::after伪元素

这两个伪元素在CSS21中定义。

本文是Web Animations 1.0的学习和翻译,如有翻译不好的可以看看原文哟。

1 介绍

CSStransition提供了一种在它们基本属性改变时插入CSS属性值的方式。这提供了一种简单的方法来实现一些简单的动画,但动画的开始和结束状态是由现有的属性值来控制,transition在动画如何进行上给作者提供了很少的控制。

该提案中介绍了定义动画,其中作者可以使用keyframe来指定CSS属性随着时间的变化。Animation类似于transition,因为它们随时间改变CSS属性的表象值(presentational value)。主要的区别是,transition是当属性值改变时触发,animation是在animation属性被应用后明确的执行。正因为如此,animations对于正在被动画的属性需要明确的值。这些值是使用动画关键帧(keyframes)来指定的,将在下面描述。

动画的许多方面可以被控制,包括多少次动画迭代,是否交替开始和结束之间的值,动画是否应该运行还是暂停。动画同样可以延迟它的开始时间。

2 取值

该规范遵循CSS21中的CSS属性定义约定。在该规范中没有定义的值的类型被定义在CSS Level 2 Revision 1[CSS21]。其他CSS模块可能扩展这些值类型的定义:例如[CSS3VAL)],当与该模块结合时,扩展<length>值类型的定义将在本规范中使用。

除了在它们的定义中列出的属性的特定值,在该规范中定义的所有属性也接受了initialinherit关键字作为他们的属性值。因为可读性原因,并未明确重复。

3 动画

CSS动画影响属性的计算值。在动画的执行期间,对于属性的计算值是由动画控制。这将会覆盖在正常样式系统中指定的值。动画覆盖所有一般规则,但会被!important规则所覆盖。

如果在一个时间点有多个动画为同一个属性指定了行为,则该动画名出现在animation-name值的最后一个会覆盖其他动画。

一个动画在动画应用程序之前、动画延迟到期前和动画结束后不会影响计算值。


enter image description here

图片1:动画属性值的计算

上图显示了属性值如何计算。本身的样式显示在图的顶部,当动画没有运行和动画被延迟时,计算值是从本身样式衍生而来。在动画运行期间,计算样式是由动画值衍生而来。

动画的开始时间是后面的两个时刻:样式被解析出指定了动画的时间,或文档的load事件被触发。因此,在文档的样式表中指定的动画是在文档加载后开始。通过修改元素样式的指定动画会在文档被加载后且该样式被解析后开始。这可能在伪元素样式规则下立即执行,例如hover,或者是脚本引擎将控制返回给浏览器。

当元素有一个animation-name的值引用了一个有效的keyframes规则时,动画才会应用到元素上。一旦动画开始,它会继续直到结束,或者animation-name被移除。用于关键帧和动画属性的值当动画开始时被快照。在动画执行期间改变它们是没有效果的。另外要注意,改变animation-name的值并不一定会重新启动动画(例如:如果一个动画列表被应用,且其中一个从列表中移除,只有那个动画会暂停,其他动画会继续运行)。为了重新启动动画,它必须被移除,然后重新应用。

动画的结束是由animation-durationanimation-iteration-countanimatioin-fill-mode属性结合一起定义的。

实例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
div {
animation-name: diagonal-slide;
animation-duration: 5s;
animation-iteration-count: 10;
}


@keyframes diagonal-slide {

from {
left: 0;
top: 0;
}


to {
left: 100px;
top: 100px;
}


}

以上会产生用五秒将元素(0, 0)移动到(100px, 100px),并且重复十次。

当设置display属性为none时,会终止任何被应用在元素和它后代的运行中的动画。如果元素的diaplaynone,当更新它的display值不为none的任何值时所有通过animation-name运用到元素的动画会开始运行,也同样包括它后代的display不为none的动画。

虽然作者可以使用动画来创建动态变化的内容,动态变化的内容可以导致在某些用户癫痫。有关如何避免内容导致癫痫发作的信息,可以看Guideline 2.3: Seizures: Do not design content in a way that is known to cause seizures

4 关键帧(keyframes)

关键帧被用于在动画过程中指定用于在各个点的动画属性的值。关键帧指定了动画的一个周期的行为,动画可以迭代一次或多次。

关键帧是使用专门的CSS@规则来指定。一个@keyframes规则包含了关键字@keyframes,然后跟着标识符给出动画的名称(它会被animation-name引用到),最后是一组样式规则(由大括号分隔)。

对于关键帧样式规则的关键帧选择器(keyframe selector)包含了由逗号分隔的百分比值列表或关键字fromto。选择器用于指定沿该关键帧代表的该动画的持续时间的百分比。关键帧本身是通过在选择器声明的属性值块中指定。关键字from等价于0%,关键字to等价于100%

如果0%from没有被指定,那么用户代理会使用将要动画的属性的计算值构造一个0%的关键帧。如果100%to没有被指定,那么用户代理会使用将要动画的属性的计算值构造一个100%的关键帧。如果关键帧选择器指定了一个负的或者是大于100%百分比值,该关键帧将被忽略。

一个关键帧规则的关键帧声明块(keyframe declaration block)包含属性和值,那些不能动画的属性将在规则中被忽略,除了animation-timing-function之外,该属性的行为将在下面说明。此外,关键帧规则声明中想具有!important资格将被忽略(没有!important优先级)。

动画所使用的@keyframes规则将是在被排序后的规则顺序中最后一个遇到的,且匹配在animation-name引用到)属性中指定的动画名称 。@keyframes规则不会层叠;因此,一个动画永远不会从多个@keyframes规则中获得关键帧。

为了确定该组的关键帧,所有的选择器的值按时间递增顺序排序。如果有任何重复,那么@keyframes规则内指定的最后一个关键帧将被用于提供那时关键帧的信息。如果有多个关键帧指定了相同的关键帧选择器值时,在@keyframes规则中不会重叠。

如果一个属性不是为关键帧指定,或者它的指定是无效的,动画的那个属性进行就好像那个关键帧不存在一样。概念上,就好像构造一组关键帧的每个属性存在于任何关键帧,且动画是为每个属性独立运行的。

实例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@keyframes wobble {
0% {
left: 100px;
}


40% {
left: 150px;
}


60% {
left: 75px;
}


100% {
left: 100px;
}

}

四个关键帧在动画名为wobble的动画中指定。在第一个关键帧中,显示了动画周期的开始,left属性的值被动画到100px。在40%时,left150px。以此类推。下面的图展示了动画的状态,如果动画持续时间被指定为10s的话。


enter image description here

下面是关键帧规则的语法:

1
2
3
4
5
6
7
8
9
keyframes_rule: KEYFRAMES_SYM S+ IDENT S* '{' S* keyframes_blocks '}' S*;

keyframes_blocks: [ keyframe_selector '{' S* declaration? [ ';' S* declaration? ]* '}' S* ]* ;

keyframe_selector: [ FROM_SYM | TO_SYM | PERCENTAGE ] S* [ ',' S* [ FROM_SYM | TO_SYM | PERCENTAGE ] S* ]*;

@{K}{E}{Y}{F}{R}{A}{M}{E}{S} {return KEYFRAMES_SYM;}
{F}{R}{O}{M} {return FROM_SYM;}
{T}{O} {return TO_SYM;}

4.1 关键帧的缓动函数

关键帧样式同样可以定义缓动函数,这个缓动函数将用于动画从这个帧运行到下个帧。

实例3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@keyframes bounce {

from {
top: 100px;
animation-timing-function: ease-out;
}


25% {
top: 50px;
animation-timing-function: ease-in;
}


50% {
top: 100px;
animation-timing-function: ease-out;
}


75% {
top: 75px;
animation-timing-function: ease-in;
}


to {
top: 100px;
}


}

动画名为bounce的动画指定了五个关键帧。在第一个关键帧到第二个关键帧之间使用的缓动函数为ease-out(也即0%到25%),25%到50%之间使用的缓动函数为ease-in,以此类推了。

100%to上指定的缓动函数将被忽略。

4.2 animation-name属性

animation-name属性定义了应用的动画列表。每一个名字被用于选择关键帧规则,以提供该动画的属性值。如果该名字没有匹配任何关键帧@规则,没有属性进行动画且动画将不会执行(这里指的是该名字指定的动画,而不是说整个动画不会执行)。此外,如果动画名称为none,那么将不会有动画。这可以用于覆盖层叠而来的任何动画。如果多个动画尝试修改同一个属性,那么靠近列表的最后的动画会胜出。

对于下面列出的其他动画属性的值,按名称列出的每个动画应该有相应的值(简单点说,比如我定义了animation-name: aa bb; 在animation-duration中应该有相应的值,例如animation-name: 2s 4s;或者其他)。如果对于其他动画属性值的列表不具有相同的长度,animation-name列表的长度决定了启动动画时检查每个列表项的数量。列表是从第一个值开始匹配:不使用尾部剩余的值。如果其他属性中的一个没有足够的逗号分隔的值去匹配animation-name属性值的数量时,用户代理必须通过列表中的值计算,直到有足够的值。这些截断和重复不影响属性的计算值。

  • 名称:animation-name
  • 取值:<single-animation-name> [ ‘,’ <single-animation-name> ]*
  • 初始值:none
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:指定的值

其中:

1
<single-animation-name> = none | <IDENT>

4.3 animation-duration属性

animation-duration属性一个动画完成一个周期的时间。

  • 名称:animation-duration
  • 取值:<time> [, <time>]*
  • 初始值:0s
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:指定的值

初始值为0s,这意味着动画不花时间。当持续时间为0s时,animation-fill-mode仍然会被应用,所以一个动画填充为backwards将在一个延迟时间(如果有的话)后显示0%的关键帧,填充为forwards的将显示100%的关键帧,即使动画是瞬时的。同样,动画事件也会被触发。一个负的animation-duration值将导致该声明无效。

4.4 animation-timing-function属性

animation-timing-function属性描述了动画在一个周期内如何进展。更多关于缓动函数:http://www.w3.org/TR/css3-animations/#CSS3-TRANSITIONS

  • 名称:animation-timing-function
  • 取值:<single-timing-function> [ ‘,’ <single-timing-function> ]*
  • 初始值:ease
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:指定的值

4.5 animation-iteration-count属性

这个属性看名字就能看出来了,它定义动画运行周期的次数。初始值为1,意味着动画会从开始到结束运行一次。一个infinite值将会使动画运行无限次。非整数的值将会导致动画运行到一个循环的一部分结束。animation-iteration-count属性值为负值时是无效的。这个属性通常结合animation-direction属性值的alternate使用,这会导致动画交替运行。

  • 名称:animation-iteration-count
  • 取值:<single-animation-iteration-count> [ ‘,’ <single-animation-iteration-count> ]*
  • 初始值:1
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:指定的值

其中:

1
<single-animation-iteration-count> = infinite | <number>

4.6 animation-direction属性

animation-direction属性定义了动画运行的方向。当一个动画运行是reverse(倒着运行)时,缓动函数也将是相反的。例如,当指定的缓动函数为ease-in,倒着运行时缓动函数为ease-out

  • 名称:animation-direction
  • 取值:<single-animation-direction> [ ‘,’ <single-animation-direction> ]*
  • 初始值:normal
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:指定的值

其中:

1
<single-animation-direction> = normal | reverse | alternate | alternate-reverse

属性值的意义:

normal
动画的所有迭代按着指定的运行

reverse
动画的所有迭代按着定义的相反方向来运行

alternate
动画周期在奇数次按着normal方向运行,偶数次按着reverse方向运行。也就是交替运行

alternate-reverse
这个和alternate相反。奇数次按着reverse方向运行,偶数次按着normal方向运行

4.7 animation-play-state属性

animation-play-state属性定义了动画是否运行还是暂停。一个运行中的动画可以通过设置该属性为pasued。为了继续运行这个暂停的动画可以设置该属性为running。一个暂停的动画将继续处于静止状态显示动画的当前值,就好像动画的时间是常数。当已暂停的动画被恢复,它从当前值重新启动,而没必要从动画的开始。

  • 名称:animation-play-state
  • 取值:<single-animation-play-state> [ ‘,’ <single-animation-play-state> ]*
  • 初始值:running
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:指定的值

其中:

1
<single-animation-play-state> = running | paused

4.8 animation-delay属性

animation-delay属性定义了动画什么时候开始。它允许动画开始执行一段时间(就是延迟一段时间执行)后在它被应用之后。当animation-delay的值为0s,意味着动画会在被应用后立即执行。否则,该值指定了从动画被应用时刻的偏移,以及动画将用该偏移延迟执行。

如果animation-delay的值是负的时间偏移,则动画将在它被应用的时刻执行,但是会出现在指定的偏移开始执行。也就是说,动画会出现从运行周期的一部分开始。

  • 名称:animation-delay
  • 取值:<time> [, <time>]*
  • 初始值:0s
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:指定的值

4.9 animation-fill-mode属性

animation-fill-mode属性定义了什么值被应用在动画之外的执行时间。默认情况下,动画不会影响在它被应用的时间和它开始执行的时间之间的属性值。同样,默认情况下动画也不会影响在动画结束后的属性值。animation-fill-mode可以覆盖这种行为。

如果animation-fill-mode的值为backwards,则动画会应用在定义在动画第一个迭代开始的关键帧的属性值,在定义在animation-delay的时间之间。

如果animation-fill-mode的值为forwards,则在动画结束后,动画将应用在动画结束后的属性值。

如果animation-fill-mode的值为both,则动画会遵循backwardsforwards的规则。也就是说,它会扩展两个方向的动画属性。

  • 名称:animation-fill-mode
  • 取值:<single-animation-fill-mode> [ ‘,’ <single-animation-fill-mode> ]*
  • 初始值:none
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:指定的值

其中:

1
<single-animation-fill-mode> = none | forwards | backwards | both

4.10 animation简写属性

animation属性是一个逗号分隔的动画定义列表,其中结合了7个动画属性成单个组件的值。

  • 名称:animation
  • 取值:<single-animation> [ ‘,’ <single-animation> ]*
  • 初始值:看单个属性的初始值
  • 应用于:所有元素,::before::after伪元素
  • 继承:无
  • 可否动画:否
  • 百分比:N/A
  • 媒体:视觉
  • 计算值:看单个属性

其中:

1
<single-animation> = <single-animation-name> || <time> || <single-animation-timing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state>

要注意,在每个动画定义中顺序是非常重要的:第一个<time>值被赋给animation-duration,第二个<time>值赋给animation-delay

5 动画事件

事件相关可以自己看文档啦:http://www.w3.org/TR/css3-animations/#animation-events

这里说下动画的三个事件:

  • animationStart:发生在动画开始
  • animationEnd:发生在动画结束
  • animationiteration:发生在动画每个迭代的结束

本文是CSS Transforms Module Level 1的翻译,翻译主要还是自己去熟悉标准、学习标准,最后再分享出来。文中如有读不通的地方可以移步官方文档哟,英语渣渣呀。

摘要

CSS变换允许元素的样式在二维或三维空间变换。该规范集合了CSS 2D 变换CSS 3D 变换SVG 变换的规范。CSS是一种用于在screenpaper等中描述结构化文档(例如:HTML和XML)的语言。

1 介绍

CSS视觉格式化模型在每一个定位元素里描述了一个坐标系统。在该坐标空间中的位置和大小可以被看作是以像素来表达,

这个坐标空间可以通过transform属性来修改。使用transform,元素可以在二维或三维空间转化,旋转和伸缩。

一些额外到属性使得变换更加简单,且允许作者控制如何与被嵌套的三维变换进行交互。

  • transform-origin属性提供了一种方便的控制被应用变换到元素变换时的原点的方法。
  • perspective属性允许作者使子元素与三维空间变换出现,就好像它们在一个共同的三维空间中一样。perspective-origin属性提供了控制哪个透视被应用的原点,有效的改变了消失点(vanishing point)的位置。
  • transform-style允许3D变换的元素和它们3D变换的后代共享一个共同的三维空间,允许三维对象等级制度的构建。
  • backface-visibility属性

注意:然而transform属性的有些值允许一个元素在三维坐标系统中被变换,该元素自身却不是一个三维对象。作为替代,它们存在于一个两维平面(平坦面),并没有任何深度。

2 模块交互

该模块定义了一组CSS属性,它会影响应用了这些属性元素的视觉渲染;这些影响会在元素根据CSS21视觉格式模型确定尺寸和位置后被应用。这些属性的一些值会导致创建一个包含块,或堆栈上下文

三维变换同样会影响到元素的视觉分层,并且因此会覆盖在CSS21附录 E中描述的从后到前的绘制顺序。

当元素的background-attachment的值为fixed时,变换还会影响到元素背景的渲染,这个在
CSS3BG
中被定义。

3 CSS值

此规范遵循CSS21CSS属性定义约定。值的类型在此规范中没有定义,而是定义在CSS Values and Units Module Level 3中定义。

除了在它们的定义中列出的属性的特定值,在这个规范中定义的所有属性也接受了inherit关键字作为他们的属性值。因为可读性原因,并未明确重复。

4 术语

当在本规范中使用时,术语在本节被分配了含义。

边界框(bounding box)
边界框是一个对于没有关联CSS布局中的所有SVG元素的对象边界框和所有其他元素的边框(border box)。一个table的边界框是table包含框的边框,而不是它的table框。

可变换元素(transformable element)
一个可变换元素是下面一种类型的元素:

用户坐标系(user coordinate system)
局部坐标系(local coordinate system)
在一般情况下,一个坐标系定义了当前画布上的位置和距离。当前局部坐标系(也包含用户坐标系)为当前活动的坐标系,这是用于定义坐标和长度如何被定位和计算,它们各自在当前画布中。

透视矩阵(perspective matrix)
perspectiveperspective-origin属性值中计算出来的矩阵,将在下面讲到。

变换矩阵(transformation matrix)
一个矩阵定义了数学上从一个坐标系映射到另一个。它是从transformtransform-origin属性的值计算而来,将在下面讲到。

当前变换矩阵(current transformation matrix)
一个矩阵定义了从局部坐标系到视口坐标系(viewport coordinate system)的映射。

累计3D变换矩阵(accumulated 3D transformation matrix)
一个矩阵从元素的3D渲染上下文中计算出来,将在下面讲到。

2D矩阵(2D matrix)
一个6个项的32的变换矩阵,或者是16个项的44矩阵且在这些项中m31, m32, m13, m23, m43, m14, m24, m34等于0,m33, m44等于1。

3D矩阵(3D matrix)
一个4*4的矩阵且不履行的2D矩阵的要求。

特性变换函数(identity transform function)
一个变换函数其实等价于一个特性4*4矩阵(看这里:Mathematical Description of Transform Functions)。特性变换函数的例子有translate(0)translate3d(0, 0, 0)translateX(0)translateY(0)translateZ(0)scale(1)scaleX(1)scaleY(1)scaleZ(1)rotate(0)rotate3d(1, 1, 1, 0)rotateX(0)rotateY(0)rotateZ(0)skew(0, 0)skewX(0)skewY(0)matrix(1, 0, 0, 1, 0, 0)matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)。一种特别的情况是透视(perspective):perspective(infinity)M34的值变得无穷小,变换函数因此假定它等于单位矩阵。

3D渲染上下文(3D rendering context)
一个包含块层次结构的一个或多个水平,通过元素的transform-style属性的preserve-3d计算值实例化,其元素有一个共同的三维坐标系。

5 二维子集(Two Dimensional Subset)

用户代理可能不能总是渲染出三维变换,那么它们只支持该规范的一个二维子集。在这种情况下,三维变换transform-styleperspectiveperspective-originbackface-visibility属性将不被支持。3D变换渲染章节也不会应用到。矩阵分解使用从“图形宝石II,由吉姆·阿尔沃编辑”中的unmatrix的方法所采取的技术,简化为2D的情况。Mathematical Description of Transform Functions章节荏苒是有效的,只是它们减少为一个3*3的变换矩阵,其中a等于m11b等于m12c等于m21d等于m22e等于m41f等于m42


enter image description here


图片一:二维变换的3*3矩阵

实例一:

如果用户代理不提供三维变换支持,作者可以很容易地提供一个备用方案。下面的例子中对于transform属性有两条属性定义。第一个定义包含了两个二维的变换函数。第二个包含了一个二维的和一个三维的变换函数。

1
2
3
4
div {
transform: scale(2) rotate(45deg);
transform: scale(2) rotate3d(0, 0, 1, 45deg);
}

有了3D的支持,第二条定义会覆盖第一条。如果没有3D的支持,第二条定义是不合法的,用户代理会退回到第一条定义。

6 变换渲染模型(The Transform Rendering Model)

当指定了一个除none之外的transform属性值时在元素上建立了一个局部坐标系,并且它被应用。映射是从元素已经渲染到的局部坐标系中通过元素的变换矩阵给定。变换是累积的。也就是说,元素在父坐标系中建立自己的局部坐标系。从用户的视角来看,一个元素有效地累积祖先的所有变换属性以及任何的局部变换被应用。这些变换的累积为元素定义了当前变换矩阵(current transformation matrix)(CTM)。

坐标空间是有两个轴的一个坐标系:X轴是水平向右增加,Y轴是垂直向下增加。三维变换函数则扩展了这个坐标空间到三维,添加了垂直于屏幕平面一个Z轴,并且沿着观察者的方向增加。


enter image description here

图片2:初始坐标空间的示范

变换矩阵是通过transformtransform-origin通过以下步骤计算而来:

  1. 通过特性矩阵开始
  2. 通过transform-origin的计算出的XY值来转换
  3. 从左到右乘以在transform属性中的每一个变换函数
  4. 通过transform-origin的负计算XY值来转换

变换应用到可变换元素上。

注意:变换会影响画布上的视觉布局(visual layout),但对CSS布局本身没有影响。这也意味着不会影响在IE浏览器下的getClientRects()和标准浏览器的getBoundingClientRect()函数的值。

实例二:

1
2
3
div {
transform: translate(100px, 100px);
}

上面的代码会将元素在XY方向上移动100px


enter image description here

实例三:

1
2
3
4
5
div {
height: 100px; width: 100px;
transform-origin: 50px 50px;
transform: rotate(45deg);
}

transform-origin属性将变换的原点在XY方向上分别移动了50px。旋转变换将元素以原点顺时针方向旋转45度。在所有的变换函数被应用后,原点的转化被转化为在XY方向上返回-50px


enter image description here

实例四:

1
2
3
4
div {
height: 100px; width: 100px;
transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg);
}

该变换分别将元素在XY方向移动80px,然后将元素缩放150%,然后绕Z轴顺时针旋转45度。可以注意到缩放和旋转是以元素的中心来操作的,由于元素具有50% 50%的默认变换原点。


enter image description here

注意:一个相同的渲染可以通过用等效变换的嵌套元素来获得:

1
2
3
4
5
<div style="transform: translate(80px, 80px)">
<div style="transform: scale(1.5, 1.5)">
<div style="transform: rotate(45deg)"></div>
</div>
</div>

对于布局是由CSS盒模型支配的元素,transform属性不影响变换元素周围的内容的流动。然而,溢出区域的范围考虑到了被变换元素。它的行为类似于元素通过相对定位来偏移时的情况。因此,如果overflow属性的值为scrollauto时,根据需要为了看到内容,滚动条会出现,因为被变换到了可视区域的外面。

对于布局是由CSS盒模型支配的元素,任何非none值的transform会导致创建一个堆栈上下文和包含块。这个对象作为一个包含块,为它固定定位的后代。

在根元素上的固定背景受到任何为那个元素被指定的变换的影响。对于任何其他元素被一个变换所影响(例如,应用一个变换到它们自身或者任何它们的祖先元素),当background-attachment属性的值为fixed时,它会被认为好像值是scrollbackground-attachment的计算值不会受到影响。

6.1 3D变换渲染(3D Transform Rendering)

通常情况下,元素是在平面上渲染,并且作为其包含块会被渲染到同一平面。通常,这个平面就是被页面其他部分共享的平面。二维变换函数可以改变的元素的呈现,但是元素仍然作为其包含块被渲染到同一平面。

三维变换可导致变换矩阵具有非零的Z分量。这会导致元素对于它的包含块渲染到不同到平面,这可能会导致影响那个元素相对于其他元素的从前到后的渲染顺序,以及会导致它与其他元素相交。这种行为取决于元素是否是3D渲染上下文中的一员,将在下面描述。

实例五:

这个例子展示了被应用了三维变换元素的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<style>
div {
height: 150px;
width: 150px;
}

.container {
border: 1px solid black;
background-color: #ccc;
}

.transformed {
transform: rotateY(50deg);
background-color: blue;
}

</style>


<div class="container">
<div class="transformed"></div>
</div>

enter image description here

该变换沿着Y轴旋转了50度。可以注意到这会使蓝色的盒子更窄,但不是立体的。

perspectiveperspective-origin属性可以被用于添加一种深度的感觉到场景中,它是使元素在Z轴更高(更接近观看者),从而会显得更大,那些远的将会显得更小。d缩放成比例于d/(d − Z)perspective的值,是从绘图平面(drawing plane)到观看者的眼睛假定位置的距离。


enter image description here

图片3:示意图展示了缩放如何依赖于perspective属性和Z的位置。在上面的示意图,Zd的一半。为了使其显示的原始圆(实线轮廓)出现在Z(虚线圆),画布上的实体圆将扩大两倍,如浅蓝色的圆。在底部的示意图,圆按比例缩小,致使虚线圆出现在画布后面,并且z的大小是距原始位置三分之一。

通常情况下,观看者的眼睛的假定位置为图的中心。这个位置可以根据需要移动-例如,如果一个网页包含多个图形应该共享一个共同的视角,可以通过设置perspective-origin


enter image description here

图片4:示意图展示了将视角上移的效果。

透视矩阵将按照以下来计算:

  1. 通过特性矩阵开始
  2. 通过perspective-origin的计算XY值来转换
  3. 乘以从perspective变换函数获得的矩阵,其中长度是由perspective属性的值提供
  4. 通过perspective-origin的负计算XY值来转换

实例6:

这个例子说明了perspective如何被用于一个三维变换,使其看起来更加真实。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<style>
div {
height: 150px;
width: 150px;
}

.container {
perspective: 500px;
border: 1px solid black;
}

.transformed {
transform: rotateY(50deg);
background-color: blue;
}

</style>


<div class="container">
<div class="transformed"></div>
</div>

enter image description here

内部的元素和前面的例子中是有着一样的变换,但它的渲染现在被它父元素的perspective属性影响。perspective导致有正的Z坐标(更接近观看者)的顶点在XY轴伸缩,使那些远离的按比例缩小,给人一种深度的感觉。

具有三维变换的元素,当它不包含在3D渲染上下文中,渲染时会有适当变换被应用,但不与任何其他元素相交。三维变换在这种情况下,可以被认为就像一个喷绘效果,就像二维变换。类似地,变换不影响绘制顺序。例如,一个正Z平移变换使元素看起来更大,但不会导致元素渲染到没有Z平移元素的前面。

具有三维变换的元素,当它包含在3D渲染上下文中,它可以明显的与在相同3D渲染上下文中的其他元素进行交互;参与到相同3D渲染上下文的元素集合可能会隐藏彼此或者相交,基于它们计算后的变换。它们被渲染就好像它们全是兄弟元素,定位在一个共同的三维坐标空间。在该三维空间中每个元素的位置由通过是对于给定元素是一个包含块的每个元素建立了3D渲染上下文的元素的变换矩阵的累积决定,将在下面描述。

实例7:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<style>
div {
height: 150px;
width: 150px;
}

.container {
perspective: 500px;
border: 1px solid black;
}

.transformed {
transform: rotateY(50deg);
background-color: blue;
}

.child {
transform-origin: top left;
transform: rotateX(40deg);
background-color: lime;
}

</style>


<div class="container">
<div class="transformed">
<div class="child"></div>
</div>
</div>

这个例子展示了在transform-style: preserve-3d缺席的情况下嵌套的3D变换如何被渲染。蓝色的div就像前面例子中一样被变换,其渲染受到了父元素perspective的影响。绿黄色的元素也有一个3D变换,是一个绕X轴的旋转。然而,绿黄的元素被渲染到父元素到平面上,因为它不是3D渲染上下文的一个成员,父元素是扁平的。


enter image description here

元素建立和参与到3D渲染上下文如下所示:

  • 一个3D渲染上下文transform-style属性的计算值为preserve-3d可变换元素建立,且它自身不是3D渲染上下文的一部分。需要注意的是这样的元素始终是一个包含块。一个建立了3D渲染上下文的元素同样会参与到那个上下文中。(这种就是上面的.container)
  • 一个transform-style属性的计算值为preserve-3d的元素,且它自身也参与到了一个3D渲染上下文,它扩展那个3D渲染上下文,而不是建立一个新的。
  • 如果元素的包含块建立或扩展了3D渲染上下文,该元素则参与到了3D渲染上下文中。

变换的最终值用于元素在3D渲染上下文中的渲染,这个最终值是由累计3D变换矩阵(accumulated 3D transformation matrix)累积计算而来,下面计算步骤:

  1. 通过特性矩阵开始
  2. 对于在3D渲染上下文的根和问题元素之间的任何包含块:
    1. 将被累积的矩阵(accumulated matrix)乘以元素包含块上的透视矩阵(perspective matrix)(如果有包含块的话)。包含块不是必须为一个3D渲染上下文的成员。
    2. 应用被累积矩阵的平移,等价于元素相对于它的包含块在水平和垂直方向的偏移
    3. 将被累积的矩阵乘以变换矩阵

实例8:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
div {
height: 150px;
width: 150px;
}

.container {
perspective: 500px;
border: 1px solid black;
}

.transformed {
transform-style: preserve-3d;
transform: rotateY(50deg);
background-color: blue;
}

.child {
transform-origin: top left;
transform: rotateX(40deg);
background-color: lime;
}

</style>

这个例子和前面的例子是相同的,只是在蓝色元素上额外添加了transform-style: preserve-3d属性。蓝色元素现在建立了一个3D渲染上下文,其中的绿黄元素就是一个成员。现在蓝色和绿黄元素共享共同的三维空间,所以绿黄元素渲染为从其父元素倾斜,是由容器的透视所影响。


enter image description here

在相同的3D渲染上下文元素可以彼此相交。用户代理必须通过细分所描述的纽维尔算法交叉元素的面来渲染交集。

在3D渲染上下文中没有变换的元素在Z=0平面渲染,但仍可能与变换元素相交。

在一个3D渲染上下文内,非相交元素的渲染顺序是基于应用的被累积矩阵在Z轴上的位置。

实例9:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<style>
div {
width: 150px;
height: 150px;
}

.container {
background-color: rgba(0, 0, 0, 0.3);
transform-style: preserve-3d;
perspective: 500px;
}

.container > div {
position: absolute;
left: 0;
}

.container > :first-child {
transform: rotateY(45deg);
background-color: orange;
top: 10px;
height: 135px;
}

.container > :last-child {
transform: translateZ(40px);
background-color: rgba(0, 0, 255, 0.75);
top: 50px;
height: 100px;
}

</style>


<div class="container">
<div></div>
<div></div>
</div>

该例子展示了元素在3D上下文中可以相交,容器元素为它自身和两个孩子建立了3D渲染上下文。孩子互相相交,且橘色多元素与容器相交。(目前浏览器支持还不是很好,可能看不到下面图片的效果)


enter image description here

使用三维变换,有可能将元素变换的反面朝向观看者。3D变换元素在两侧显示相同的内容,所以背面看起来像前面的镜像。通常情况下,元素的反面朝向观看者并保持可见。然而,backface-visibility属性允许作者使元素不可见,当元素的背面朝向观看者的时候。这种行为是生动的;如果一个backface-visibility: hidden的元素正在动画,使得其正面和反面分别交替地可见,此时只有当正面朝向观察者的时候才是可见的。

6.2 透视变换盒的处理(Processing of Perspective-Transformed Boxes)

累计3D变换矩阵(accumulated 3D transformation matrix)是一个4*4的矩阵,而将被变换的对象是二维盒子。要变换盒子的每个脚(a, b)

// todo

7 transform属性

一个变换被应用到坐标系的元素是通过transform属性来渲染。这个属性包含了一个变换函数列表。一个坐标系的最终变换值是将列表中的每个函数转换其相应的矩阵来取得的,就像在变换函数的数学描述中定义的,然后将这些矩阵相乘。

  • 名称:transform
  • 取值:none | <transform-list>
  • 初始值:none
  • 应用于:可变换元素
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值,相对的值会转化成绝对值
  • 百分比:相对于边界框的尺寸

对于变换的结果,任何除了none的计算值会创建一个堆栈上下文和包含块。这个对象会为它固定定位的后代扮演包含块的角色。

上面取值的<transform-list>为:

1
<transform-list> = <transform-function>+

8 transform-origin属性

  • 名称:transform-origin
  • 取值:[ left | center | right | top | bottom | <percentage> | <length> ] | [ left | center | right | <percentage> | <length> ] [ top | center | bottom | <percentage> | <length> ] <length>? | [ center | [ left | right ] ] && [ center | [ top | bottom ] ] <length>?

  • 初始值:50% 50%

  • 应用于:可变换元素
  • 继承:无
  • 媒体:视觉
  • 计算值:对于<length>的取值为绝对值,否则为百分比
  • 百分比:相对于边界框的尺寸
  • 能否动画:一个长度、百分比或计算值简单列表

对于SVG元素没有关联的CSS布局框时该属性默认值为0 0

transformtransform-origin属性的值是被用于计算变换矩阵,像上面描述的一样。

如果只指定了一个值,第二个被假设为center。如果指定了一个或两个值,第三个值被假设为0px

如果定义了两个或多个值时,或者这些值没有一个关键字时,或只使用了center关键字,然后第一个关键字代表水平位置,第二个关键字代表垂直位置。第三个值代表Z轴位置且它必须是<length>类型。

属性值的意义:

<percentage>
对于水平偏移的百分比是相对于边界框的宽度,对于垂直偏移的百分比是相对于边界框的高度。水平和垂直的偏移值代表了从边界框左上角的偏移。

<length>
一个length值给出了固定的长度作为偏移。水平和垂直的偏移值代表了从边界框左上角的偏移。

对于SVG元素没有关联的CSS布局框时水平和垂直的偏移值代表了从元素的局部坐标空间的原点的偏移。

top
计算为垂直位置的0%

right
计算为水平位置的100%

bottom
计算为垂直位置的100%

left
计算为水平位置的0%

center
当水平位置没有指定时计算为水平位置的50%,或垂直位置的50%

9 transform-style属性

  • 名称:transform-style
  • 取值:flat | preserve-3d
  • 初始值:flat
  • 应用于:可变换元素
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值
  • 百分比:N/A
  • 可动画:否

transform-stylepreserve-3d值会创建一个堆栈上下文。

下面的CSS属性值要求用户代理在被应用之前创建后代元素的扁平表示,所以会覆盖transform-style: preserve-3d的行为。

transform-style的计算值不会被影响。

transformtransform-origin属性的值是被用于计算变换矩阵,像上面描述的一样。

10 perspective属性

  • 名称:perspective
  • 取值:none | <length>
  • 初始值:none
  • 应用于:可变换元素
  • 继承:无
  • 媒体:视觉
  • 计算值:绝对长度或none
  • 百分比:N/A
  • 可否动画:同length

<length>的值必须是正数的。

属性值的意义:

<length>
距离投影中心的距离。

none
没有透视变换被应用。它的效果类似于一个无穷大的<length>值。所有的对象在画布上呈平面显示。

使用这个属性的非none值时会建立一个堆栈上下文。它同样建立了一个包含块,就像transform属性一样。

perspectiveperspective-origin属性的值是用于计算透视矩阵,就如上面描述的。

11 perspective-origin属性

  • 名称:perspective-origin
  • 取值:[ left | center | right | top | bottom | <percentage> | <length> ] | [ left | center | right | <percentage> | <length> ] [ top | center | bottom | <percentage> | <length> ] <length>? | [ center | [ left | right ] ] && [ center | [ top | bottom ] ] <length>?

  • 初始值:50% 50%

  • 应用于:可变换元素
  • 继承:无
  • 媒体:视觉
  • 计算值:对于<length>的取值为绝对值,否则为百分比
  • 百分比:相对于边界框的尺寸
  • 能否动画:一个长度、百分比或计算值简单列表

perspectiveperspective-origin属性的值是用于计算透视矩阵,就如上面描述的。

如果只指定了一个值,第二个被假设为center

如果两个值中至少一个不是关键字,第一个关键字代表水平位置,第二个关键字代表垂直位置。

perspective-origin的值代表了从边界框左上角透视原点的一个偏移。

<percentage>
对于水平偏移的百分比是相对于边界框的宽度,对于垂直偏移的百分比是相对于边界框的高度。水平和垂直的偏移值代表了从边界框左上角的偏移。

<length>
一个length值给出了固定的长度作为偏移。水平和垂直的偏移值代表了从边界框左上角的偏移。

top
计算为垂直位置的0%

right
计算为水平位置的100%

bottom
计算为垂直位置的100%

left
计算为水平位置的0%

center
当水平位置没有指定时计算为水平位置的50%,或垂直位置的50%

12 backface-visibility属性

backface-visibility属性决定了当一个被变换元素的背面朝向观看者时背面是否可见。使用特性矩阵,元素的前面是朝向观看者的。当应用了一个绕Y轴旋转180度的变换时背面朝向了观看者。

  • 名称:backface-visibility
  • 取值:visible | hidden
  • 初始值:visible
  • 应用于:可变换元素
  • 继承:无
  • 媒体:视觉
  • 计算值:指定值
  • 百分比:N/A
  • 可否动画:否

一个backface-visibility: hidden的元素的可见性由以下决定:

  1. 对于一个在3D渲染上下文的元素,计算它的累积3D变换矩阵。对于一个不在3D渲染上下文的元素,计算它的变换矩阵
  2. 如果矩阵的第三行第三列是负数的,则元素应该被隐藏。否则它是可见的。

13 SVG的transform属性

14 SVG动画

这两个章节没有翻译,有兴趣的自行研究哟。SVG

15 变换函数

transform属性的值一个<transform-function>的列表。允许的变换函数集合在下面给出了。当在该规范中<angle>被使用时,一个等价于0的<number>是同样被允许的,它被认为是角度0一样。

15.1 2D变换函数

2D Transform Functions

15.2 3D变换函数

3D Transform Functions

这篇文章主要是W3C官方CSS Flexible Box Layout Module Level 1的学习,内容可能有删减。Flex绝对是CSS未来布局的趋势,有了Flex什么垂直居中、水平居中、响应式等都是小菜一碟了。所以把它彻底搞懂还是很有必要的,文章比较长,不过如果能耐心的读完,对Flex肯定会有一个透彻的了解。

摘要

这份规范描述了为用户界面设计而优化的框模型(box model)。在Flex布局模型中,flex容器的孩子可以布置在任何方向,并且能伸缩它们的尺寸,它们可以伸展它们的尺寸以此填充未使用的空间,或者收缩它们的尺寸以避免溢出父元素。对于子元素的水平和垂直对齐将变得非常容易操作。这些框嵌套(水平内垂直或垂直内水平)可用于在两个维度来构建布局。

1 介绍

CSS 2.1定义了四种布局模式-确定它们尺寸以及位置的算法是基于它们与兄弟和祖先盒子的关系:

  • block布局:为文档(document)布局而设计
  • inline布局:为文本布局而设计
  • table布局:为以表格形式的二维数据的布局而设计
  • position布局:为非常明确的定位,且不考虑文档中的其他元素的布局而设计

该模块引入了一个新的布局模式,flex布局,它是为更加复杂的应用和网页而设计的。

1.1 概述

flex布局表面上类似于block布局。它缺少许多在block布局中使用的更复杂的以文本(text-)和文档(document-)为中心的属性,例如floatscolumns。作为回报,它获得了简单和更加强大的工具,使它能以多种方式来分配空间和对齐内容,而这些就是web应用和网页所需要的。以下是flex容器的内容:

  • 它可以在任何方向上布局(向左,向右,向下,甚至向上!)
  • 可以将显示的内容顺序颠倒flex-direction: row-reverse)或者重新安排它们的顺序(order
  • 可以线性布局在单个()轴,也可以沿()轴包裹在多行中
  • 可以伸缩它们的尺寸以响应可用的空间
  • 能够相对于它们的容器对齐,或者彼此对齐
  • 可以动态的沿着主轴折叠或不折叠,同时保持容器的侧轴尺寸

1.2 模块交互

该模块扩展了[CSS21]display属性的定义,添加了新的block-levelinline-leveldisplay类型,并且定义一个新的类型的格式化上下文连同属性来控制其布局。该模块中定义的属性都不能应用在::first-line::first-letter伪元素中。

2 Flex布局盒模型以及术语

一个flex容器是一个元素display属性的计算值为flexinline-flex时,生成的盒子。在flex容器内的常规流子元素,称之为flex items,并且使用flex布局模型来布局。

不同于blockinline布局,它们的布局是基于blockinline流的方向来计算的,而对于flex布局,是基于flex directions(flex方向?)的。为了更容易简单的说明flex布局,本节中定义了一组flex相关的flow-relative术语。flex-flow的值决定了这些术语如何映射到物理方向(上/右/下/左),轴(垂直/水平),以及尺寸(宽/高)。

enter image description here

主轴(main axis)
主轴维度(main dimension)
flex容器的主轴,伸缩项目(flex items)主要沿着这条轴进行排列布局

主轴起点(main-start)
主轴终点(main-end)
伸缩项目放置在flex容器内从主轴起点(main-start)向主轴终点(main-start)方向

主轴尺寸(main size)
主轴尺寸属性(main size property)
一个伸缩项目的宽度或高度,它是在主轴维度(main dimension)里面的,且是项目的主尺寸。伸缩项目的主尺寸属性宽度高度属性,它是在主轴维度(main dimension)里面的。

侧轴(cross axis)
侧轴维度(cross dimension)
垂直于主轴称为侧轴。它的方向主要取决于主轴方向

侧轴起点(cross-start)
侧轴终点(cross-end)
伸缩行的配置从容器的侧轴起点边开始,往侧轴终点边结束

侧轴尺寸(cross size)
侧轴尺寸属性(cross size property)
一个伸缩项目的宽度或高度,它是在侧轴维度(main dimension)里面的,且是项目的主尺寸。伸缩项目的侧轴尺寸属性宽度高度属性,它是在侧轴维度(main dimension)里面的。

3 Flex容器:display属性为flexinline-flex

  • 名称:display
  • 取值:flex | inline-flex

属性取值的意义:

  • flex:该值使元素生成一个block-levelflex容器盒子
  • inline-flex:该值使元素生成一个inline-levelflex容器盒子

一个flex容器为它的内容建立了一个新的flex格式上下文。这和建立块级上下文是相同的,不同之处在于flex布局是用于代替block布局的:浮动不会闯入到flex容器中,并且flex容器到外边距也不会与其内容的外边距折叠Flex容器为它的内容形成一个包含块,就像块容器一样。overflow属性是可以应用于flex容器的。

Flex容器不是块容器(block containers),所以一些假定为block布局而设计的属性是不能应用于flex布局的。特别是:

  • 所有的在多列模块中的column-*属性对flex容器是不起作用的
  • floatclear属性对伸缩项目是不起作用的,也不会使它脱离常规流。然而float属性仍然会影响盒子的display属性的计算值。具体怎么影响Relationships between ‘display’, ‘position’, and ‘float’
  • vertical-align对伸缩项目是不起作用的
  • ::first-line::first-letter伪元素是不可以应用于flex容器的,并且flex容器也不会为它的祖先贡献第一格式化行或首字母

如果一个元素的display属性指定为inline-flex时,在某些情况下,它的display属性会被计算为flexCSS 2.1 章节9.7中的Table会被修改为包含一个附加行,当它指定值为inline-flex时,会被计算为flex

4 伸缩项目(flex items)

不严格地说,伸缩容器(flex containers)的伸缩项目是从元素内容生成的常规流盒子,从而进一步生成了伸缩容器。

每一个伸缩容器的常规流子元素会变成一个伸缩项目,并且包含在伸缩容器中的每个连续运行的文本会被包裹在一个匿名的伸缩项目中。然而,一个匿名的伸缩项目仅仅只包含空白时,它并不会被渲染出来,就好像它被设置了display: none一样。

一个伸缩项目为它的内容建立了一个新的格式上下文,像通常一样,它的格式上下文的类型是由它的display属性决定的。然而,伸缩项目是flex-level盒子,而不是block-level盒子:它们参与到了它们容器到flex格式上下文中,而不是块级格式上下文。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div style="display:flex">

<!-- flex item: block child -->
<div id="item1">block</div>

<!-- flex item: floated element; floating is ignored -->
<div id="item2" style="float: left;">float</div>

<!-- flex item: anonymous block box around inline content -->
anonymous item 3

<!-- flex item: inline child -->
<span>
item 4
<!-- flex items do not split around blocks -->
<div id=not-an-item>item 4</div>
item 4
</span>
</div>

如果一个元素的常规流子元素指定的display-outside生成的伸缩容器是inline-level,它将会计算成block-level

在一个设置了display: table的伸缩项目上,该table的包装盒子会变成一个伸缩项目,并且orderalign-self属性可以应用到它。任何标题框的内容会贡献到table包装盒的最小含量和最大内容尺寸的计算。然而,像widthheight属性,flex的普通写法可以应用于table,如下所示:伸缩项目的最终尺寸是通过执行布局来计算的,就好像计算table包装盒边缘之间的距离。table盒子的内容边缘是table盒子的padding + border区域,并且table盒子是伸缩项目。

4.1 绝对定位的Flex儿子

一个伸缩容器的绝对定位的子元素不参与到flex布局中。然而,它会参与到重新排序中(详细见:order),会对他们的绘制顺序有一个影响。

一个伸缩容器的绝对定位的子元素的静态位置被确定为使得子元素就好像是 伸缩容器的唯一伸缩项目那样去定位,这会假设子元素和伸缩容器的使用尺寸(used size)为固定大小的盒子。

换句话说,一个伸缩容器的绝对定位的子元素的静态位置被确定为:当将子元素的静态位置矩形设置到伸缩容器的内容盒子后,然后再将绝对定位的儿子在这个矩形中通过在伸缩容器上设置的justify-content值和设置在伸缩项目上的align-self值来进行对齐。

静态位置矩形:
静态位置矩形是对齐容器用于决定绝对定位元素的静态位置偏移。在block布局中它对应了 CSS2.1§10.3.7中描述的假想盒子的位置。

4.2 伸缩容器的外边距和内边距

毗邻的伸缩项目的margin是不会折叠的。自动外边距则在相应的维度吸收额外的空间,并且可以用于对齐和相邻伸缩项目之间的距离。可以看auto外边距的对齐

在伸缩项目上设置的百分比的外边距和内边距总是相对于它们自身的尺寸来解析,而不像blocks,它们并不总是相对于他们的包含块的行内尺寸来解析。

4.3 伸缩项目的Z轴顺序

伸缩项目的绘制和行内块是相同的,只是order会修改文档的顺序,从而代替原始文档的顺序,并且z-index设置了除auto值之外的其他值是会创建一个层叠上下文,即使position被设置为static

4.4 被折叠的项目(Collapsed Items)

当在一个伸缩容器上指定了visibility:collapse,此时伸缩项目成为了一个被折叠的项目,产生了一种类似于在table-rowtable-column元素上设置visibility:collapse的效果:被折叠的伸缩项目完全从渲染中移除,但是它留下了一个支柱,以此保持伸缩线侧轴尺寸的稳定。因此,如果一个伸缩容器只有一个伸缩行(flex line),动态折叠和未折叠的项目会保证对伸缩容器的侧轴没有影响,并且不会造成页面布局的其余部分摆动。伸缩行换行会在折叠后重新做,然而,一个有着多行的伸缩容器的侧轴尺寸可能改变,也可能不改变。

尽管被折叠的项目不会重新渲染,但是它们出现在格式化结构中。所以,它不像display: none项目,影响是依赖的盒子出现在格式化结构中,并且仍然作用在折叠的元素上。

实例:

在下面的例子中,一个侧栏被设置以适应其内容的尺寸。visibility: collapse被用于动态对隐藏导航栏部分,且不影响他们的宽度,即使最宽的部分是一个折叠部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<style>
@media (min-width: 60em) {
/* two column layout only when enough room (relative to default text size) */
header + div { display: flex; }
#main {
flex: 1; /* Main takes up all remaining space */
order: 1; /* Place it after (to the right of) the navigation */
min-width: 12em; /* Optimize main content area sizing */
}

}
/* menu items use flex layout so that visibility:collapse will work */
nav > ul > li {
display: flex;
flex-flow: column;
}

/* dynamically collapse submenus when not targetted */
nav > ul > li:not(:target):not(:hover) > ul {
visibility: collapse
;

}
</style>


</header>
<div>
<article id="main">
Interesting Stuff to Read
</article>
<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>
</div>

为了计算支柱的尺寸,flex布局首先以所有项目未折叠来处理,然后重新运行使所有的折叠项目用支柱来替换,且维持该项目原始行的原始侧轴。可以看Flex布局算法visibility: collapse的相互作用。

在任何伸缩项目上使用visibility: collapse会导致flex布局算法会重复中途部分,并且运行最昂贵的步骤。所以建议作者继续使用display: none,如果不需要动态的折叠或不折叠项目时,因为它对于布局引擎更加高效。

4.5 伸缩项目隐含的最小尺寸

为了给伸缩项目提供更合理的默认最小尺寸,规范中引入了一个新的值auto作为min-widthmin-height属性的初始值(在CSS2.1中定义)。

  • 名称:min-widthmin-height
  • 取值:auto
  • 新的计算值:指定的百分比或绝对长度或关键字
  • 新的初始值:auto

auto
主轴上,在一个overflowvisible的伸缩项目上,当在伸缩项目当主轴上指定了最小尺寸属性,下面的表格给出了最小尺寸:

5 排序和方向(Ordering and Orientation)

一个伸缩容器的内容可以布置在任何方向或者任何排序。这使得作者很容易达到的效果,而在之前这些需要复杂或者易碎的方法才能达到,例如使用floatclear属性的hacks。这些功能是通过flex-directionflex-wraporder属性来暴露。

flex布局的重排序功能只会影响视觉到渲染。

作者不可以使用orderflex-flowflex-direction*-reverse值来替代正确源排序,因为这会破坏文档的可访问性。

5.1 伸缩流方向:flex-direction属性

  • 名称:flex-direction
  • 取值:row | row-reverse | column | column-reverse
  • 初始值:row
  • 应用于:伸缩容器
  • 媒体:视觉
  • 计算值:指定的值

flex-direction属性指定了伸缩项目如何在伸缩容器中放置,是通过设置伸缩容器的主轴的方向。这决定了伸缩项目在布局中的方向。

属性值的意义:

reverse的取值不是反转了盒子的排序:就像书写模式direction,它只是改变了流的方向。

5.2 伸缩行换行:flex-wrap属性

  • 名称:flex-wrap
  • 取值:nowrap | wrap | wrap-reverse
  • 初始值:nowrap
  • 应用于:伸缩容器
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值

flex-wrap属性控制了伸缩容器是否在单行显示还是在多行显示,并且侧轴的方向,决定了新的行层叠的方向。

属性值的意义:

5.3 伸缩方向和换行:flex-flow属性

  • 名称:flex-flow
  • 取值:<flex-direction> || <flex-wrap>
  • 初始值:取决于flex-directionflex-wrap的初始值
  • 应用于:伸缩容器
  • 继承:取决于flex-directionflex-wrap的初始值
  • 媒体:视觉
  • 计算值:取决于flex-directionflex-wrap的初始值

flex-flow属性是flex-directionflex-wrap的简写。它一起定义了伸缩容器的主轴和侧轴。

实例:

1
2
3
div { flex-flow: row; }
/* Initial value. Main-axis is
inline, no wrap. */

enter image description here

1
2
3
div { flex-flow: column wrap; }
/* Main-axis is block-direction (top to bottom)
and lines wrap in the inline direction (rightwards). */

enter image description here

1
2
3
div { flex-flow: row-reverse wrap-reverse; }
/* Main-axis is the opposite of inline direction
(right to left). New lines wrap upwards. */

enter image description here

5.4 显示顺序:order属性

伸缩项目在默认情况下是按着它们源文档中出现的顺序来布局的。order属性可以被用于改变这些顺序。

  • 名称:order
  • 取值:<integer>
  • 初始值:0
  • 应用于:伸缩项目和伸缩容器的绝对定位儿子
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值
  • 是否可以动画:是

order属性控制在伸缩容器内子元素在伸缩容器中的顺序,通过将它们分配到有序组。它只接受单一的<integer>作为属性值,并且指定的就是伸缩项目属于的有序组。

一个伸缩容器把它的内容布局在被修改的文档顺序,从最小数字的有序组开始,并以此类推。当项目具有相同的值时,它们就按照他们在源文档中的顺序来布局。这个会影响绘制顺序,就好像伸缩项目在源文档中被重排序。

实例:

下图显示了一个简单的标签式界面,标签中的活动窗格永远是第一个:

enter image description here

这可以通过以下CSS代码来实现:

1
2
3
4
5
6
7
8
9
10
.tabs {
display: flex;
}

.tabs > * {
min-width: min-content;
/* Prevent tabs from getting too small for their content. */
}

.tabs > .current {
order: -1; /* Lower than the default of 0 */
}

5.4.1 重排序和可访问性

order属性不会影响非视觉媒体的排序。同样的,order不影响连续导航模式的默认遍历顺序。作者只能在视觉媒体中使用order属性。

实例:

许多网页在标记上具有类似的形状,在顶部的头部,在底部的页脚,然后一个内容区域和一个或在中间的两个附加列。一般情况下,内容最好首先出现在页面的源代码中,在其他列之前。然而,这是非常常见的设计,例如简单的将附加列放在左边而内容区域放在右边,这是难以实现的。这在许多方面已经得到解决,这经常被命名为“圣杯布局”,它有两个附加列。例如,利用网页代码和以下草图实现所需的布局:

1
2
3
4
5
6
7
8
<!DOCTYPE html>
<header>...</header>
<div id='main'>
<article>...</article>
<nav>...</nav>
<aside>...</aside>
</div>
<footer>...</footer>

enter image description here

这种布局可以轻松的通过Flex布局来实现:

1
2
3
4
#main { display: flex; }
#main > article { order: 2; min-width: 12em; flex:1; }
#main > nav { order: 1; width: 200px; }
#main > aside { order: 3; width: 200px; }

作为一个额外的奖励,我们是所有的列默认情况下等高的,主内容则尽可能宽的填充屏幕。此外,这可以结合media queries来实现在窄屏幕下将所有的列垂直布局。

1
2
3
4
5
6
7
8
@media all and (max-width: 600px) {
/* Too narrow to support three columns */
#main { flex-flow: column; }
#main > article, #main > nav, #main > aside {
/* Return them to document order */
order: 0; width: auto;
}

}

6 伸缩行(Flex Lines)

伸缩项目在伸缩容器内被布局,并通过伸缩行来对齐。假设容器(hypothetical containers)则被布局算法用于分组和对齐。一个伸缩容器可以是单行,也可以是多行的,这取决于flex-wrap属性:

  • 一个单行的伸缩容器将它的所有儿子布局在单行,即使这会导致它的内容溢出。
  • 一个多行的伸缩容器将伸缩项目跨越多行,这类似于当文本太宽时折行出新行以适应现有行。当附加的行被创建时,它们通过flex-wrap属性并沿着侧轴堆栈在伸缩容器内。每一行至少包含一个伸缩项目,除非伸缩容器本身是空的。

实例:

这个例子显示了四个按钮,并且在水平方向不能完全适应(容不下四个):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
#flex {
display: flex;
flex-flow: row wrap;
width: 300px;
}

.item {
width: 80px;
}

</style>


<div id="flex">
<div class='item'>1</div>
<div class='item'>2</div>
<div class='item'>3</div>
<div class='item'>4</div>
</div>

因为容器只有300px,只有三个的项目适应到单行。它们占了240px,并且剩下了60px的剩余空间。因为伸缩容器的flex-flow属性指定了这是一个多行的,所以伸缩容器会创建一个附加的行来包含最后一个项目。

enter image description here

一旦内容被分成多行,每行都是独立布局的;伸缩尺寸和justify-contentalign-self属性仅仅将项目认为是单行的。

当一个伸缩容器有多行时,侧轴尺寸的每一行是该行包含的伸缩项目的最小必须尺寸,并且所有的行在伸缩容器内的对齐是通过align-content属性来对齐的。当一个伸缩容器(即使是一个多行的伸缩容器,flex-wrap: wrap)只有一行时,该行 的侧轴尺寸是伸缩容器侧轴的尺寸,此时应用align-content没有效果。一行的主轴尺寸总是和伸缩容器的内容盒子的主轴尺寸的大小一样。

实例:

这里是一个和前面相同的例子,只是我们在伸缩项目上设置了flex: auto。第一行有剩余的60px,所有的项目具有相同的伸缩性,所以三个项目中的每一个都会得到额外的20px。最后一个项目则会伸缩到整行。

enter image description here

7 伸缩性

flex布局的定义方面是使伸缩项目可伸缩的能力,改变它们的宽度/高度,以填补在主轴维度中的可用空间。这是通过flex属性来完成的。伸缩容器将它的可用空间成比例的分配到它的伸缩项目中,这个比例通过伸缩项目的伸缩增长因素决定,或者成比例缩小它们以防止溢出,这个比例是通过伸缩项目的伸缩缩小因素决定。

7.1 flex简写

  • 名称:flex
  • 取值:none | auto | [ <‘flex-grow’> <‘flex-shrink’>? || <‘flex-basis’> ]
  • 应用于:伸缩项目
  • 初始值:单个属性决定
  • 媒体:视觉
  • 计算值:单个属性决定

flex属性指定了组件的伸缩长度:伸缩增长因素伸缩缩小因素伸缩基础。当一个盒子是伸缩项目时,flex属性被咨询并代替主轴尺寸属性去决定盒子的主轴尺寸。如果一个盒子不是伸缩项目,flex属性对其没有效果。

下面是各取值组件的意义:

  • flex-grow:这个<number>组件是flex-grow的普通写法,它指定了伸缩增长因素,它决定了该伸缩项目相对于有正的可用空间的伸缩容器中其他伸缩项目的增长比例。当省略时,它被设置为1
  • flex-shrink:这个<number>组件是flex-shrink的普通写法,它指定了伸缩缩小因素,它决定了该伸缩项目相对于有负的可用空间的伸缩容器中其他伸缩项目的缩小比例。当省略时,它被设置为1。当分发负的空间时,伸缩缩小因素是乘以伸缩基础的。
  • flex-basis:该组件,具有和width属性相同的属性值,是设置flex-basis的普通写法,指定了伸缩基础:是伸缩项目的初始主轴尺寸,它是在根据伸缩因素分发可用空间之前设置的。当在flex简写中省略了它,它的指定值为0%

enter image description here

上面这个图片展示了绝对和相对的flex

  • auto:关键字auto相当于1 1 main-size
  • none:关键字none相当于0 0 main-size

flex属性的组件的初始值是等价于0 1 main-size的。

7.2 flex的常用值

下面的列表总结了最常见的flex值的效果:

flex: 0 main-size
flex: initial
等价于flex: 0 1 main-size(这个是初始值)。当有正当可用空间时,这会使得当伸缩项目是不可伸缩的,但是当空间不足时允许伸缩项目收缩到它的最小尺寸。

flex: auto
等价于flex: 1 1 main-size

flex: none
等价于flex: 0 0 main-size

flex: <position-number>
等价于flex: <position-number> 1 0%

7.3 伸缩性的组件

伸缩性的各个组件可以通过独立的普通写法属性来控制。

作者被建议使用flex简写法来设置,而不是通过各个组件来设置,因为简写法可以正确的重置任何未指定的组件以适应常见的用途。

7.3.1 flex-grow属性

  • 名称:flex-grow
  • 取值:<number>
  • 应用于:伸缩项目
  • 初始值:0
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值
  • 是否能动画:是

flex-grow属性用<number>来设置伸缩增长因素,负值是不允许的。

7.3.2 flex-shrink属性

  • 名称:flex-shrink
  • 取值:<number>
  • 应用于:伸缩项目
  • 初始值:1
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值
  • 是否能动画:是

flex-shrink属性用<number>来设置伸缩缩小因素,负值是不允许的。

7.3.2 flex-basis属性

  • 名称:flex-basis
  • 取值:main-size | <‘width’>
  • 应用于:伸缩项目
  • 初始值:main-size
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值,长度将被转换为绝对值
  • 百分比:相对于伸缩容器的内部主尺寸(inner main size)
  • 是否能动画:是

flex-basis属性设置伸缩基础,它接受和widthheight属性相同的属性值。

当在伸缩项目上设置了main-size关键字,会去检索主轴尺寸属性的值。

flex-basis是和width在水平书写模式解析一样:百分比的值是相对于伸缩项目的包含块,例如,它的伸缩容器,如果包含块的尺寸是不确定的,其结果和auto的主尺寸一样。类似的,flex-basis决定了内容盒子的尺寸,除非指定了box-sizing等。

8 对齐(Alignment)

当一个伸缩容器的内容完成了伸缩后,并且所有的伸缩项目的尺寸都最后确定了,它们可以在伸缩容器中对齐。

margin属性可以以一种类似的方式来对齐项目,但是更强大。

8.1 用auto的margin来对齐

在伸缩项目上的auto margins和块级流中的auto margins在效果上是非常类似的:

  • 在计算伸缩基础和伸缩的长度期间,auto margins被当作为0
  • 优先于通过justify-contentalign-self的对齐,在相应维度中任何正的可用空间被分配到auto margins
  • 溢出的盒子会忽略它们的auto margins,且溢出会在end方向

要注意:如果可用空间被分发到auto margins,则对齐属性在这个维度上没有效果,因为在伸缩后margins偷走了所有到可用空间。

实例:

一种automargins是在主轴上将伸缩项目清晰的分成组。下面的例子展示了如何使用它去模仿一个通用的UI图案-一个有许多动作的单一栏有一些左对齐,另外的右对齐。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
nav > ul {
display: flex;
}

nav > ul > li {
min-width: min-content;
/* Prevent items from getting too small for their content. */
}

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>

8.2 轴对齐:justify-content属性

  • 名称:justify-content
  • 取值:flex-start | flex-end | center | space-between | space-around
  • 初始值:flex-start
  • 应用于:伸缩容器
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值

justify-content属性沿着伸缩容器当前行的主轴来对齐项目。当任何伸缩长度和任何auto margins被解析后,会被执行。通常情况下,当在一行中的任何伸缩项目都是不可伸缩的或者是可伸缩但达到了它们的最大尺寸时,它会帮助分配剩余的额外空间。当项目溢出行时,它也施加了一些控制在项目对对齐上。

属性取值就不翻译了,看个图片就明白了:

enter image description here

8.3 侧轴对齐:align-itemsalign-self属性

align-items:

  • 名称:align-items
  • 取值:flex-start | flex-end | center | baseline | stretch
  • 初始值:stretch
  • 应用于:伸缩容器
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值

align-self:

  • 名称:align-self
  • 取值:auto | flex-start | flex-end | center | baseline | stretch
  • 初始值:auto
  • 应用于:伸缩项目
  • 继承:无
  • 媒体:视觉
  • 计算值:auto的计算值是父亲的align-items属性值,否则为指定的值

伸缩项目可以在伸缩容器当前行的侧轴上对齐,类似于justify-content,只是在垂直方向上。align-items为伸缩容器的项目设置了默认的对齐方式,包括匿名的伸缩项目。在单独的伸缩项目上align-self则允许默认的对齐方式被覆盖。

如果任何伸缩项目的侧轴的marginsauto,则align-self的设置没有效果。

下面还是用一个图片来看看各属性值的意义:

enter image description here

8.4 align-content属性

  • 名称:align-content
  • 取值:flex-start | flex-end | center | space-between | space-around | stretch
  • 初始值:stretch
  • 应用于:多行的伸缩容器
  • 继承:无
  • 媒体:视觉
  • 计算值:指定的值

当在侧轴上有额外的空间时,align-content属性是对齐在伸缩容器中的伸缩行,类似于justify-content在主轴上对齐单个的伸缩项目。要注意的是,当伸缩容器只有一行时,该属性是没有效果的。

属性值的意义看下图啦:

enter image description here

8.5 Flex基线(Flex Baselines)

伸缩容器的基线由以下来决定:

主轴基线

  1. 如果伸缩项目中的任何一个伸缩项目的第一行参与到了基线对齐,伸缩容器的主轴基线是这些项目的伸缩基线
  2. 否则,如果伸缩容器有至少一个伸缩项目,它的第一个伸缩项目有一个平行于伸缩容器主轴的基线,则伸缩容器的主轴基线就是那个基线
  3. 否则,伸缩容器的主轴基线由第一个项目的内容盒子来合成,或者如果那个失败了,则由伸缩容器的内容盒子来合成

侧轴基线

  1. 如果伸缩容器至少有一个伸缩项目,且它的第一个伸缩项目有一个平行于伸缩容器侧轴的基线,则伸缩容器的侧轴基线就是那个基线
  2. 否则,伸缩容器的侧轴基线由第一个项目的内容盒子来合成,或者如果那个失败了,则由伸缩容器的内容盒子来合成

当根据上面的规则来计算基线时,如果盒子贡献了基线且它有一个overflow的值允许滚动时,这个盒子在决定基线时必须认为它在初始的滚动位置。

当决定一个table cell的基线时,一个伸缩容器提供了类似于行框(line box)或table-row所做的那样的基线。

9 Flex布局算法

10 分割Flex布局

// todo

2015年的第一篇文章,新的一年更加努力的学习前端,重新开始,之前翻译的文章以及自己写的和一些笔记都放在了这里2014‘s Blog

下面就进入正题了,这篇文章主要是W3C官方 Media Query的一个学习和翻译。主要还是为了以后脑子不好使,可以回过头来看看复习复习。

摘要和背景

HTML4CSS2只支持对于不同的媒体类型来设置样式,例如一个文档在屏幕(screen)上显示时使用sans-serif字体,而在打印(print)时使用serif字体,这里的screenprint是定义好的两种媒体类型。而Media Query扩充了Media Type的功能,并且使我们能够更精准的应用样式表。

例如,在HTML4中:

实例一

1
2
<link rel="stylesheet" type="text/css" media="screen" href="sans-serif.css">
<link rel="stylesheet" type="text/css" media="print" href="serif.css">

或者:

实例二

1
2
3
@media screen {
* { font-family: sans-serif }
}

一个Media Query包含了一个Media Type以及0个或多个来检查特定的媒体特性条件的表达式。在这些媒体特性中能在Media Query中被使用的是widthheightcolor。通过使用Media Query,页面的呈现可以在特定的终端中显示,而不需要去改变内容。

兼容性

在了解Media Query之前需要了解浏览器对它的支持情况,以便在项目中更好的使用。可以在这里看到Media Query对于浏览器的一个支持情况。对于IE永远是坑爹的,它只有在IE8+才支持Media Query

那么在不支持的情况下有什么办法呢,社区的大牛给我们提供了Respond.js,它可以支持IE8及以下的浏览器。

Media Queries

就如上面摘要提到的,一个Media Query包含了一个Media Type以及0个或多个来检查特定的媒体特性条件的表达式。

在本节中有关媒体Media Query的声明我们假设遵循了下面的语法章节。没有遵循语法的Media Query将在错误处理章节讲到。

实例三:

1
<link rel="stylesheet" media="screen and (color)" href="example.css" />

这个实例表达了一个确定的样式表(example.css)应用于一个确定的媒体类型(screen)以及确定的特性(必须为彩色屏幕)

实例四:

对于上面的实例三,我们也可以用@import语句:

1
@import url(color.css) screen and (color);

一个media queries是一个逻辑表达式,它可能为真也可能为假。media queries为真当媒体类型匹配当前正在运行的用户代理所在设备的媒体类型,且在media queries中所有表达式为真时,我们的media queries就为真。

对于媒体类型为allmedia queries有一种简写法,也就是只有@media and ()...

实例五:

1
2
3
4
5
6
7
/* 以下两个样式表是等价的 */
@media all and (min-width:500px) { … }
@media (min-width:500px) { … }

/* 以下两个样式表是等价的 */
@media (orientation: portrait) { … }
@media all and (orientation: portrait) { … }

许多的media queries可以构成一个媒体查询列表。对于以逗号分隔的media queries,只要其中一个或多个为true时我们的列表就为真,否则为false,在media queries语法中,逗号代表了逻辑或,而and关键字代表了逻辑与。

实例六:

1
@media screen and (color), projection and (color) { … }

如果媒体查询列表为空(或者说为空字符串或空白),它将被认为为真:

实例七:

1
2
@media all { … }
@media { … }

逻辑否可以通过not关键字。其实就是和编程一样啦,大家懂的,加上了not,假就是真,真就是假。

实例八:

1
<link rel="stylesheet" media="not screen and (color)" href="example.css" />

关键字only是用于隐藏老的用户代理的样式表。它的功能仅仅在于此了。而对于其他用户代理,处理以only开头的media queries时,要像only不存在一样。

实例九:

1
<link rel="stylesheet" media="only screen and (color)" href="example.css" />

media queries语法可以用于HTMLXHTMLXMLCSS规则等@media@import中。

实例十:

1
2
3
4
5
6
7
8
9
<link rel="stylesheet" media="screen and (color), projection and (color)" rel="stylesheet" href="example.css">

<link rel="stylesheet" media="screen and (color), projection and (color)" rel="stylesheet" href="example.css" />

<?xml-stylesheet media="screen and (color), projection and (color)" rel="stylesheet" href="example.css" ?>

@import url(example.css) screen and (color), projection and (color);

@media screen and (color), projection and (color) { … }

如果有一个媒体特性没有应用到当前正在运行的用户代理的设备上时,包含该表达式的媒体特性讲为假。

实例十一:

媒体特性device-aspect-ratio只应用于视觉设备,所以对于音频设备该表达式将永远为false

1
<link rel="stylesheet" media="aural and (device-aspect-ratio: 16/9)" href="example.css" />

如果衡量单位没有应用于当前设备,表达式也将永远为false

实例十二:

px没有应用于speech媒体类型,所以下面的媒体查询将永远为false

1
<link rel="stylesheet" media="speech and (min-device-width: 800px)" href="example.css" />

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
media_query_list
: S* [media_query [ ',' S* media_query ]* ]?
;
media_query
: [ONLY | NOT]? S* media_type S* [ AND S* expression ]*
| expression [ AND S* expression ]*
;
media_type
: IDENT
;
expression
: '(' S* media_feature S* [ ':' S* expr ]? ')' S*
;
media_feature
: IDENT
;

错误处理

对于不遵循用户代理的media queries需要遵守本节中描述的规则。

  • 未知媒体类型:未知媒体类型被计算为false。它可以有效的被认为是不匹配当前设备类型的媒体类型。
  • 未知媒体特性:当某个指定的媒体特性不知道时,用户代理将媒体查询相当于not all

实例十五:

在这个例子中,第一个媒体查询将相当于not all,并且计算为false,第二个媒体查询计算时就好像第一个媒体查询不存在。

1
<link rel="stylesheet" media="screen and (max-weight: 3kg) and (color), (color)" href="example.css" />
  • 未知媒体特性值:和未知媒体特性一样,用户代理会将媒体查询相当于not all,当某个媒体特性值不知道时。

实例:

因为在max-width中负值是不允许的,所以相当于not all

1
@media (min-width: -100px) { … }
  • 畸形的媒体查询:具有意外的token的媒体查询相当于not all

实例:

1
2
@media (example, all,), speech { /* only applicable to speech devices */ }
@media &test, screen { /* only applicable to screen devices */ }

媒体特性

在句法上,媒体特性类似于CSS属性:它们有名字并且接受确定的值。然而,属性和媒体特性之间也有几点重要到不同:

  • 属性被用于声明给文档提供信息从而如何呈现文档。而媒体特性则是一些表达式用于描述对于输出设备的要求。
  • 许多的媒体特性能够接受可选的min-max-前缀来表达大于等于小于等于。这种语法的使用是为了阻止<>字符与HTMLXML冲突。这些媒体特性经常使用前缀来使用,当然也会单独使用了。
  • 属性总是需要一个值才能形成一个声明,另一方面,媒体特性也能不需要值。对于一个媒体特性,如果(feature: x)有一个值x,且x是除了0或0加上一个单位的值时,则(feature)会计算为true。而对于使用min-max-前缀的媒体特性则必须使用一个值。当一个媒体特性用到了min-max-前缀时,这会被认为是一个畸形的媒体查询。
  • 属性可以接收更多复杂的值,例如,通过其他值计算出来的值。而媒体特性只能接受单一的值:一个关键字、一个数字或者一个数字带有一个单位。

width

  • 取值:<length>
  • 应用于:视觉或触觉媒体类型
  • 接受min/max前缀:是

width媒体特性描述了输出设备目标显示区域的宽度。对于一个连续媒体,这个就是视口(viewport)的宽度,并且包含了滚动条的宽度(如果有的话)。对于分页媒体,这是页框的宽度。

需要注意的是,<length>不能为负值。

实例:

下面的实例说明样式表只能应用于打印输出大于25cm的设备。

1
<link rel="stylesheet" media="print and (min-width: 25cm)" href="http://…" />

实例:

这个实例说明样式表只能应用于视口宽度在400px700px之间的设备。

1
@media screen and (min-width: 400px) and (max-width: 700px) { … }

实例:

这个实例说明样式应用于handheldscreen媒体类型,且最小宽度为20emem是相对于初始的font-size值。

1
2
@media handheld and (min-width: 20em), 
screen and (min-width: 20em) { … }

height

  • 取值:<length>
  • 应用于:视觉或触觉媒体类型
  • 接受min/max前缀:是

height媒体特性和width几乎一样(但是height不常用),只是宽度与高度的区别,它同样包含了页面的水平方向滚动条的高度(如果有的话)。

负值也是不允许对。

device-width

  • 取值:<length>
  • 应用于:视觉或触觉媒体类型
  • 接受min/max前缀:是

device-width媒体特性描述的是输出设备呈现表面的宽度(和width还是有很大区别的,对于连续媒体,width是指视口的宽度)。对于连续媒体,device-width指的是屏幕的宽度,对于分页媒体,这是页面纸张尺寸的宽度。

负值是不允许的。

device-width一般是用于移动端。

实例:

下面的例子表明样式表应用于媒体类型为screen,且水平宽度为800px的设备。

1
@media screen and (device-width: 800px) { … }

device-height

  • 取值:<length>
  • 应用于:视觉或触觉媒体类型
  • 接受min/max前缀:是

device-height媒体特性描述的是输出设备呈现表面的高度。对于连续的媒体,这是屏幕的高度。对于分页媒体,这是页面纸张尺寸的高度。

负值是不允许的。

实例:

1
<link rel="stylesheet" media="screen and (device-height: 600px)" />

orientation

  • 取值:portrait | landscape
  • 应用于:位图媒体类型
  • 接受min/max前缀:否

orientation一般是用于检测移动端是横向还是竖向的。当height的值大于等于width的媒体特性值时,orientation的值为portrait,否则为landscape

实例:

1
2
@media all and (orientation:portrait) { … }
@media all and (orientation:landscape) { … }

aspect-ratio

  • 取值:<value>
  • 应用于:位图媒体类型
  • 接受min/max前缀:是

aspect-ratio描述了输出设备目标显示区域的宽高比。该值包含两个以/分隔的正整数。代表了水平像素数(第一个值)与垂直像素数(第二个值)的比例。

实例:

下面为显示区域宽高至少为一比一的设备选择了一个特殊的样式表。

1
@media screen and (min-aspect-ratio: 1/1) { ... }

device-aspect-ratio

  • 取值:<value>
  • 应用于:位图媒体类型
  • 接受min/max前缀:是

这个和aspect-ratio很类似,描述的是输出设备的宽高比。该值包含两个以/分隔的正整数。代表了水平像素数(第一个值)与垂直像素数(第二个值)的比例。

实例:

例如,如果一个设备的屏幕媒体特性中,宽度为1280px,高度为720px,也就是等于16/9,则以下的所有媒体查询将匹配它:

1
2
3
4
@media screen and (device-aspect-ratio: 16/9) { … }
@media screen and (device-aspect-ratio: 32/18) { … }
@media screen and (device-aspect-ratio: 1280/720) { … }
@media screen and (device-aspect-ratio: 2560/1440) { … }

color

  • 取值:<integer>
  • 应用于:视觉媒体类型
  • 接受min/max前缀:是

color指定输出设备每个像素单元的比特值。如果设备不支持输出颜色,则该值为0。

<integet>不能为负值。

这个媒体特性用的也是比较少的。

实例:

1
2
@media all and (color) { … }
@media all and (min-color: 1) { … }

color-index

  • 取值:<integer>
  • 应用于:视觉媒体类型
  • 接受min/max前缀:是

color-index指定了输出设备中颜色查询表中的条目数量。

实例:

向所有使用至少256个索引颜色的设备应用样式表:

1
<link rel="stylesheet" media="all and (min-color-index: 256)" href="http://foo.bar.com/stylesheet.css" />

monochrome

  • 取值:<integer>
  • 应用于:视觉媒体类型
  • 接受min/max前缀:是

指定了一个黑白(灰度)设备每个像素的比特数。如果不是黑白设备,值为0。

实例:

向每个像素至少8比特的黑白设备应用样式表:

1
@media all and (min-monochrome: 8) { ... }

resolution

  • 取值:<resolution>
  • 应用于:位图媒体类型
  • 接受min/max前缀:是

resolution指定输出设备的分辨率(像素密度)。分辨率可以用每英寸(dpi)或每厘米(dpcm)的点数来表示。

实例:

为每英寸至多300点的打印机应用样式:

1
@media print and (min-resolution: 300dpi) { ... }

scan

  • 取值:progressive | interlace
  • 应用于:tv媒体类型
  • 接受min/max前缀:否

scan描述了电视输出设备的扫描过程。

实例:

向以顺序方式扫描的电视机上应用样式表:

1
@media tv and (scan: progressive) { ... }

grid

  • 取值:<integer>
  • 应用于:视觉或触觉媒体类型
  • 接受min/max前缀:否

grid判断输出设备是网格设备还是位图设备。如果设备是基于网格的(例如电传打字机终端或只能显示一种字形的电话),该值为1,否则为0。

对于grid,有效的值只有10。其他一切都会创建一个畸形都媒体查询。

实例:

向一个15字符宽度或更窄的手持设备应用样式:

1
@media handheld and (grid) and (max-width: 15em) { ... }

标准中还包括了一些值、单位的介绍,这里就不一一说了,具体还是点我吧

需要看媒体查询的一些例子,可以看看这里:http://mediaqueri.es/

还可以看看W3Cplus的文章:http://www.w3cplus.com/content/css3-media-queries