定位
利用定位,可以准确地定义元素框相对于其正常位置应该出现在哪里,或者相对于父元素、另一个元素甚至浏览器窗口本身的位置。
基本概念
定位的类型
/* 关键字值 */
position: static;
position: relative;
position: absolute;
position: fixed;
position: sticky;
- static:元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中。
- relative:元素框相对于其原本的位置进行定位。元素仍保持其未定位前的形状,它原本所占的空间仍保留,也不会强制转换成块级框。
- absolute:元素框从文档流中完全删除,相对于其包含块定位。元素定位后生成一个块级框,而不论它在正常流中生成何种类型的框。
- fixed:元素框的表现类似于absolute,但是相对于视窗定位。
- sticky:元素先按照普通文档流定位,然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。
包含块
之前讨论浮动的时候,对于浮动元素,其包含块定义为最近的块级祖先元素。但是对于定位则没有这么简单:
- 初始包含块:一个视窗大小的矩形
- 如果一个元素的position值是relative或static,包含块由最近的块级框、表单元格或行内块祖先框的内容边界构成。
- 如果一个元素的position值是absolute,包含块设置为最近的position值不是static的祖先元素:
- 如果这个祖先元素是块级元素,包含块就设置为该元素的内边距边界;也就是由边框界定的区域。
- 如果这个元素是行内元素,包含块则设置为该祖先元素的内容边界。
在从左到右的语言中,包含块的上边界和左边界是第一个行框内容的上边界和左边界,包含块的下边界和右边界是最后一个框的下边界和右边界。 - 如果没有祖先,元素的包含块定义为初始包含块
这里有一点很重要,元素可以定位到其包含块的外面。这与浮动元素使用负外边距浮动到其父元素内容区外面很类似。这也说明,包含块实际上应该是“定位上下文”。
偏移属性
以下四种定位机制:relative、absolute、fixed、sticky(除了static),使用了4个属性来描述定位元素各边相对于其包含块的偏移。我们将这4个属性成为偏移属性。
- 应用于定位元素(非static)
百分数
- 对于top和bottom,相对于包含块的高度计算
- 对于left和right,相对于包含块的宽度计算
正值会导致向内偏移,使边界朝着包含块的中心移动
- 负值会导致向外偏移,可以将一个元素定位到其包含块之外
除了长度和百分数,偏移属性还可以设置auto,这是默认值,auto的具体行为会根据所用的定位类型改变。
宽度和高度
设置宽度和高度
如果想为定位元素指定一个特定的宽度,显然要用width属性。类似地,利用height可以为定位元素声明特定的高度。
尽管有时设置一个元素的宽度和高度很重要,但对于定位元素来说则不一定必要:如果使用了那四个偏移属性,那么元素的高度和宽度将由这些偏移隐含确定。
假如你希望一个绝对定位元素从上到下填充其包含块的左半部分,可以使用以下值:
top:0; bottom:0; left:0; right:50%;
由于width和height的默认值都是auto,因此在这个例子中会根据偏移属性定义其宽度和高度。
限制宽度和高度
如果有必要,可以用最小最大属性来限制元素的宽度和高度:min-wdith、max-width、min-height、max-height
- 应用于除了非替换行内元素和表元素以外的所有元素
- 百分数:相对于包含块的宽度或高度计算
- 属性的值不能为负
例子:
top:10%;
bottom:auto;
left:50%;
right:10%;
height:auto;
min-width:15em;
根据偏移属性,元素的宽度应该是包含块的40%,但是不能小于15em。
使用最大最小属性的一个好处是,可以相对安全地混合使用不同的单位,比如使用百分数大小的同时,再设置基于长度值的限制。
最小最大属性结合浮动元素使用时也会非常有用:比如可以允许一个浮动元素的宽度相对于其父元素的宽度,同时确保该浮动元素的宽度不小于某个值。
内容溢出和剪裁
如果一个元素内容相对于元素大小来说过大,就有可能溢出元素本身。
溢出
当内容在元素中放不下时,就可以利用overflow属性来控制这种情况。
/* 默认值。内容不会被修剪,会呈现在元素框之外 */
overflow: visible;
/* 内容会被修剪,并且其余内容不可见 */
overflow: hidden;
/* 内容会被修剪,浏览器会显示滚动条以便查看其余内容,打印机会打印溢出的内容*/
overflow: scroll;
/* 由浏览器定夺,如果内容被修剪,就会显示滚动条 */
overflow: auto;
内容剪裁
如果一个绝对定位元素的内容溢出其内容框,而且overflow设置为要求剪裁该内容,使用clip属性可以改变剪裁区域的形状。
clip: rect(1px, 10em, 3rem, 2ch)
clip: auto
- 默认值auto表示元素的内容不应剪裁。
- 可以相对于元素内容区定义一个剪裁形状,这不会改变内容区的形状,只会改变将显示内容的区域形状。
这是利用形状值 rect(< top>, < right>, < bottom>, < left>)实现的。
< top> 和 < bottom> 指定相对于盒子上边框边界 的偏移,< right> 和 < left> 指定了相对于盒子左边框边界 的偏移。
也就是说,不是边偏移,而是距元素左上角的距离。
rect(0,20px,20px,0); //涵盖元素左上角20*20正方形的剪裁区域
rect(…)只允许长度值和auto。
但是可以设置负长度值,这会使剪裁区域延伸到元素框之外。但是尽管剪裁区向外延伸,但是延伸区内不会出现任何内容,因此也没有多大作用。
另一方面,完全可以超越下边界和右边界,这会扩展可以看到内容的区域。但是内容流并没有改变,唯一的视觉效果就是元素下面可以看到更多内容。
元素可见性
除了剪裁和溢出,还可以控制整个元素的可见性
visibility: visible | hidden | collapse
- visible:初始值,元素可见
- hidden:元素不可见,但其位置还保留,元素还是会影响布局。
这与display:none有区别,后者令元素不仅不显示,还会从文档中删除,所以对文档布局没有任何影响。
有可能将一个hidden元素的后代元素置为visible。这会使该后代元素正常出现,尽管其祖先元素是不可见的。为此,必须显式声明后代元素为visible,因为visibility属性可以继承。 - collapse:在表中显示使用,如果用于非表元素,collapse与hidden相同。
绝对定位
包含块和绝对定位元素
- 元素绝对定位时,会从文档流中完全删除。然后相对于其包含块定位,其边界根据偏移属性放置。
- 绝对定位元素可能覆盖其他元素,或者被其他元素覆盖。
- 绝对定位元素的包含块是最近的position值不为static的祖先元素。通常选择一个元素作为绝对定位的包含块,将其position置为relative而且没有偏移。
- 元素绝对定位时,还会为其后代元素建立一个包含块。
自动边偏移
元素绝对定位时,如果除bottom外某个任意偏移属性设置为auto,会有一种特殊的行为。
下面以top为例:
span{
position:absolute;
top:auto;
left:0;
color:red;
background-color:blue;
}
对于left:0,元素的左边界会和包含块的左边界对齐。
但是对于auto的top,定位元素的顶端要相对于其未定位之前本来的顶端位置对齐。
如果left和right设置为auto,也适用同样的基本规则:
在这些情况下,定位元素的左或右边界与元素未定位时该边界原本的位置对齐。
我们把上个例子中的left改为auto:
span{
position:absolute;
top:auto;
left:auto;
color:red;
background-color:blue;
}
定位元素现在就位于其本来的位置,但是由于它已经定位,它原来所占的空间已经消失,因此现在定位元素和正常流内容重叠。
但是这种自动放置只在某些情况下可行,就是对定位元素的其他尺寸没有什么限制的时候。如果确实又增加了许多限制该怎么办呢?
非替换元素的放置和大小
一般地,元素的大小和位置取决于其包含块。
考虑一个定位元素的宽度和水平放置:
left+margin-left+border-left-width+padding-left+width+padding-right+border-right-width+margin-right+right
= 包含块的width
那么所有这些属性之间有什么关系呢?
- 如果left、width、right都设置为auto,会得到上一小节的结果:左边界置于静态位置(从左向右读的语言),width恰好包围元素。
span{
position:absolute;
top:0;
left:0;
right:auto;
color:red;
background-color:blue;
}
此时元素的width为auto,宽度恰好足够包含内容。
而从元素右边界到包含块右边界之间的距离是right的计算值。
- 如果左右外边距都设为auto,而left、right和width不是auto
span{
position:absolute;
top:0;
left:1em;
right:5em;
width:10em;
margin:0 auto;
color:red;
background-color:blue;
}
1.首先,left和right会设置好整个元素框的偏移位置
2.其次,左右外边距会设置为相等的值。这会让元素居中。
- 如果外边距也不为auto呢
p{
position:relative;
width:30em;
}
span{
position:absolute;
top:0;
left:1em;
right:5em;
width:10em;
margin:0 1em 0 2em;
color:red;
background-color:blue;
}
现在,定位元素的总宽度是1+2+10+1+5 = 19em;而整个包含块的宽度是30em,中间还差11em,必须从某个地方弥补。
规则指出,在这种情况下,用户代理会重置right的值(从左向右读)。
可以发现。此时right被重置为了16em,这样整个元素的水平宽度就等于包含块的宽度了。
但是这种情况下如果某个外边距保持为auto,则会改变这个外边距。
span{
position:absolute;
top:0;
left:1em;
right:5em;
width:10em;
margin:0 auto 0 2em;
color:red;
background-color:blue;
}
定位元素的位置和上面的相同,但是这次是重置了右外边距为12em的结果。
同样的,如果左外边距为auto,就会重置左外边距:
span{
position:absolute;
top:0;
left:1em;
right:5em;
width:10em;
margin:0 1em 0 auto;
color:red;
background-color:blue;
}
一般地,如果只有一个属性设置为auto,就会修改这个属性来满足宽度需求,但如果没有为auto的属性,就会重置right属性。
width为auto也是同理:
span{
position:absolute;
top:0;
left:1em;
right:5em;
width:auto;
margin:0 1em 0 2em;
color:red;
background-color:blue;
}
此时,width被扩展成了必要的宽度来满足宽度的需求。
在垂直方向上,规则非常类似:
<div id = container>
<div>元素1</div>
<div>元素2</div>
<div>元素3</div>
</div>
#container{
position:relative;
width:30em;
height:10em;
}
#container div{
position:absolute;
width:30%;
background-color:aqua;
}
#container div:nth-child(1){
left:0;
top:0;
}
#container div:nth-child(2){
left:35%;
top:0;
height:50%;
}
#container div:nth-child(3){
left:70%;
height:50%;
bottom:0;
}
1.对于元素1,元素的高度收缩为内容的高度
2.对于元素2,未指定的属性(bottom)设置为适当的值,来弥补元素底端与包含块底端之间的距离
3.对于元素3,未指定的属性是top,所以由top弥补定位元素顶端与其包含块顶端之间的距离。
此外,外边距为auto可以得到垂直居中的效果:
#container div{
position:absolute;
left:0;
top:0;
bottom:0;
height:5em;
margin:auto 0;
width:100%;
background-color:aqua;
}
这里必须显式声明top与bottom都为0,元素才会垂直居中。因为若不显式声明top与bottom为0,它们就是auto,就会调整它们来满足垂直宽度,那么元素也不会垂直居中了。
还有两个小变化:
- 在水平布局中,如果值为auto,right或left都可以根据其静态位置放置。但在垂直布局中,只有top可以取静态位置,bottom不可以。
- 如果一个绝对定位元素在垂直方向上过度受限,将重置bottom。
#container div{
position:absolute;
left:0;
top:0;
bottom:0;
height:5em;
margin:0;
width:100%;
background-color:aqua;
}
这种情况下会重置bottom为5em。
替换元素的放置和大小
与非替换元素基本相同,只是替换元素有固定的宽度和高度,也就是说将width和height设置为auto时,其计算值由元素的固有宽度和高度决定。
z轴上的放置
利用z-index,可以改变元素相互覆盖的顺序。
/* Keyword value */
z-index: auto;
/* <integer> values */
z-index: 0;
z-index: 3;
z-index: 289;
z-index: -1; /* 使用负值降低优先级 */
一般来说,z-index值较大的元素能覆盖z-index值较小的元素。
所有整数(包括负数)都可以作为z-index的值。如果指定了一个负z-index值,元素会移到较底层的位置。
但要注意,一旦为元素指定了一个z-index值(不是auto),该元素就会建立自己的局部层叠上下文。这意味着元素的所有后代相对于该祖先元素都有自己的叠放顺序。也就是说,后代元素不会和别的元素比较,而是在自己祖先元素的基础上和祖先元素的其他后代元素们比较。
也可以理解为,如果一个元素为后代元素建立了叠放上下文,那么该元素初始就是位于此上下文z轴的0位置上。
而z-index为auto的元素不会建立一个新的本地堆叠上下文。当前堆叠上下文中新生成的元素和父元素堆叠层级相同。
固定定位
固定定位与绝对定位很类似,只不过固定定位的包含块是视窗。固定定位时,元素会完全从文档流中去除。
相对定位
采用相对定位时,将通过使用偏移属性来移动定位元素。
但是,采用相对定位时,元素会从正常位置移走,但其原来占据的空间并不会消失。
如果一个相对定位元素过度受限会怎么样呢?
strong{
position:relative;
top:10px;
bottom:20px;
}
这里指定的值要求两种完全不同的行为,top:10px要求元素向下移10px,而bottom:20px要求元素向上移20px。
CSS2.1规定,如果出现过度受限情况,一个值会重置为另一个值的相反数。
因此,bottom总是等于-top,为-10px,那么上面例子中的元素最终会向下移10px。
同理,在相对定位中,right=-left(从左到右的语言)。