作者:ACGTOFE
原文地址:http://acgtofe.com/posts/2015/10/xyz-in-css/
位置是個(gè)怎樣的概念
哎涌献,這個(gè)元素怎么跑那里去了屯断?
回想一下氛堕,在我們覺(jué)得“樣式崩了”,“頁(yè)面出bug了”的時(shí)候尼斧,是不是會(huì)有相當(dāng)一部分情況都可以描述成上面這句話呢竣稽?
我們?cè)趯?xiě)css的時(shí)候,就會(huì)經(jīng)彻σǎ考慮“位置”這個(gè)事萍倡。理念就是,所有的頁(yè)面元素都應(yīng)該被安排在為它預(yù)定的位置上辟汰。畢竟按照計(jì)劃預(yù)定的來(lái)列敲,才能有條不紊,不容易出錯(cuò)帖汞。
就像一本雜志的編輯戴而,即便文稿都已準(zhǔn)備好,但具體哪篇放在第幾頁(yè)的哪里翩蘸,是要認(rèn)真考慮的所意。好的雜志應(yīng)該有好的排版。
下面催首,本文將介紹一些會(huì)影響到“位置”扶踊,但一般不太會(huì)知道的要點(diǎn)。
盒模型的再認(rèn)識(shí)
盒模型你一定很熟悉:
在content
郎任、padding
秧耗、border
、margin
這些區(qū)域之外涝滴,請(qǐng)注意圖中的edge绣版,也就是分隔盒模型各區(qū)域的邊。在確定頁(yè)面元素的準(zhǔn)確位置時(shí)歼疮,需要細(xì)致地參考這些邊杂抽。它們按照范圍從小到大分別是:
-
content edge,也叫做inneredge(注意和JavaScript的
innerWidth
等區(qū)別開(kāi))韩脏。它圍成的區(qū)域代表內(nèi)容區(qū)缩麸,一般由元素內(nèi)的具體內(nèi)容決定。它確定的范圍叫做contentbox
赡矢,也是css屬性box-sizing
的默認(rèn)值content-box
的范圍杭朱。 -
padding edge。它確定
padding box
的范圍吹散。盡管w3c規(guī)范已經(jīng)從box-sizing
移除了這個(gè)值弧械,但很容易類(lèi)比理解。 -
border edge空民。它確定
border box
的范圍刃唐。 -
margin edge羞迷,也叫做outer edge。它確定
margin box
的范圍画饥。box-sizing
也沒(méi)有這個(gè)值衔瓮。
為什么需要了解這些邊呢?想象一下你想要放置一個(gè)元素到你為它安排的位置上抖甘,但是热鞍,你拿的元素并不是一個(gè)點(diǎn)(比如物理學(xué)里的質(zhì)點(diǎn)),而是一個(gè)盒子衔彻。一個(gè)占據(jù)一定空間的盒子薇宠,如果沒(méi)有邊作為參照,你能清楚地知道應(yīng)該怎樣去對(duì)齊嗎艰额?
背景的位置
背景是很常用的樣式昼接,但有好多地方可能不太會(huì)注意。
背景分為背景圖(background-image
)和背景色(background-color
)悴晰,漸變(css gradients)也屬于背景圖慢睡。其中,背景圖位于背景色之上铡溪。如果使用多個(gè)背景圖(multiple backgrounds)漂辐,聲明靠前的位于上方。
除background-clip
之外的其他背景屬性棕硫,如background-position
髓涯、background-size
等,都只作用于背景圖哈扮,對(duì)背景色沒(méi)有作用纬纪。這是可以理解的,因?yàn)楸尘吧軉渭兓猓鼪](méi)有起點(diǎn)和終點(diǎn)包各,總是鋪滿整個(gè)空間,要么有靶庙,要么沒(méi)有问畅。
現(xiàn)在,一個(gè)元素div.bg-element
定義了這樣的css:
.bg-element{
width: 100px;
height: 100px;
margin: 20px;
padding: 20px;
border: 5px dashed #386365;
background: #2aace9 url(pattern.png) no-repeat;
}
這是一個(gè)同時(shí)有背景圖和背景色的元素六荒,而且有內(nèi)外邊距及邊框护姆,其效果是:
可以看出,在默認(rèn)情況下掏击,背景圖的起始點(diǎn)為padding box的左上角卵皂,而背景色沒(méi)有起始點(diǎn),將鋪滿整個(gè)border box(為了看到這一點(diǎn)砚亭,特意用了dashed
邊框)灯变。雖然這個(gè)例子中的背景圖好像限制在padding box范圍內(nèi)豺旬,但實(shí)際上,它和背景色的可見(jiàn)范圍是一樣的柒凉,都是border box,用background-position
或background-repeat
稍作修改即可驗(yàn)證:
這個(gè)背景可見(jiàn)范圍的概念篓跛,對(duì)應(yīng)了css3新增屬性background-clip
膝捞。這個(gè)屬性的默認(rèn)值就是border-box
。如果更改它愧沟,會(huì)是這樣:
無(wú)論怎么修改可見(jiàn)范圍蔬咬,這個(gè)例子中的背景圖的起始點(diǎn)都是padding box左上角,這就是背景圖起始點(diǎn)的概念沐寺。它對(duì)應(yīng)的是css3中新增的background-origin
林艘,其默認(rèn)值正是padding-box
。如果修改了background-origin
混坞,那么屬性background-position
產(chǎn)生的位置偏移狐援,包括right
、bottom
等關(guān)鍵字的情況究孕,都會(huì)對(duì)應(yīng)地改變參考的邊啥酱。
外邊距區(qū)域不會(huì)有背景。前文的盒模型的圖里厨诸,margin
和transparent
一起也是這個(gè)意思镶殷。
自設(shè)容器進(jìn)行定位
你一定用過(guò)這樣的定位搭配:position: relative;
的父元素,加上position: absolute;
的子元素微酬。
這比較像建立一個(gè)xy平面坐標(biāo)系绘趋,然后把元素放置在自己想要的坐標(biāo)位置上。但是颗管,x軸陷遮、y軸、原點(diǎn)垦江、坐標(biāo)點(diǎn)拷呆,它們分別在哪里呢?
請(qǐng)看這個(gè)例子:
<div class="pos-container">
<div class="pos-element"></div>
</div>
.pos-container{
position: relative;
width: 140px;
height: 140px;
margin: 20px;
padding: 20px;
border: 5px dashed #789;
}
.pos-element{
position: absolute;
width: 70px;
height: 70px;
margin: 10px;
padding: 20px;
border: 5px dashed #a74;
background: #e5c5a5;
left: 0;
top: 0;
}
得到的結(jié)果是:
由于邊框是明顯的有視覺(jué)效果的部分疫粥,因此border edge的位置很容易確定茬斧。注意兩個(gè)元素都有完整的內(nèi)外邊距和邊框,而此時(shí)div.pos-element
的坐標(biāo)是(0, 0)梗逮,圖中間距為10px项秉。經(jīng)過(guò)分析可以得知,這個(gè)10px間距來(lái)自div.pos-element
的margin
慷彤。所以可以得到什么結(jié)論呢娄蔼?結(jié)論如下:
首先怖喻,網(wǎng)頁(yè)的平面坐標(biāo)系和通常的數(shù)學(xué)平面直角坐標(biāo)系不同,y軸的正方向是朝下的岁诉。事實(shí)上锚沸,包括Photoshop、Flash等平面設(shè)計(jì)在內(nèi)的界面涕癣,都使用這樣的坐標(biāo)系哗蜈。
這種搭配的情況下,構(gòu)成坐標(biāo)系xy軸的是用作容器的元素的padding edge坠韩。其中padding edge的左上角即為坐標(biāo)系的原點(diǎn)距潘。
絕對(duì)定位的元素設(shè)置的left、top所形成的坐標(biāo)位置點(diǎn)只搁,位于該元素的margin edge的左上角音比。也就是,定位元素是用margin edge的左上角這個(gè)點(diǎn)來(lái)對(duì)齊坐標(biāo)的氢惋。
此外洞翩,構(gòu)成定位參考坐標(biāo)系的是包含塊,而不一定是直接父元素焰望。
包含塊
包含塊(containing block)是css規(guī)范的視覺(jué)格式化模型(visual formatting model)中的概念菱农,它是一個(gè)邏輯的矩形框,用于css的定位及尺寸的計(jì)算柿估,并不限制內(nèi)部元素的位置循未,可以溢出。它和盒模型的關(guān)系可以這樣描述:一個(gè)DOM元素對(duì)應(yīng)一個(gè)盒模型秫舌,盒模型的某一條邊(這不是固定的)將標(biāo)明該DOM元素創(chuàng)建的包含塊范圍的妖。
一般情況下,一個(gè)DOM元素的子元素(以及這些子元素的盒模型)以這個(gè)DOM元素的content edge作為包含塊的邊界足陨。
特別地嫂粟,在這種position: relative;
的父元素及position: absolute;
的子元素的搭配中,絕對(duì)定位的子元素以父元素的padding edge作為自己的包含塊的邊界墨缘。
更具體的包含塊的邊界判定可以參考W3C的說(shuō)明星虹。
普通流、浮動(dòng)與絕對(duì)定位的三方糾葛
在確定一個(gè)DOM元素的位置時(shí)镊讼,我們需要考慮它的定位方案(positioning schemes)宽涌。一個(gè)DOM元素可以選擇以下三個(gè)方案:
- 普通流(normal flow):如果你對(duì)這個(gè)元素什么也沒(méi)干,那就是它了蝶棋。
- 浮動(dòng)(floats):當(dāng)元素的float屬性設(shè)置了left或right后卸亮。
-
絕對(duì)定位(absolute positioning):當(dāng)元素的position屬性設(shè)置了
absolute
或fixed
后。
如果一個(gè)DOM元素既設(shè)置了浮動(dòng)又設(shè)置了絕對(duì)定位玩裙,那么它是絕對(duì)定位(float會(huì)被重置為none的計(jì)算值)兼贸。
你也許聽(tīng)說(shuō)過(guò)“脫離文檔流”這樣的詞匯段直,它在css里是確實(shí)存在的概念,原詞是out of flow溶诞。如果一個(gè)元素的定位方案是浮動(dòng)或絕對(duì)定位鸯檬,又或者這個(gè)元素是根元素(root element),就稱(chēng)這個(gè)元素是脫離文檔流(out of flow)的螺垢。
文檔流的問(wèn)題
同一層級(jí)的兄弟元素喧务,同時(shí)有普通流、浮動(dòng)甩苛、絕對(duì)定位這三種定位方案時(shí),它們之間的相互關(guān)系是怎樣的俏站?
要理清這個(gè)相互關(guān)系讯蒲,需要理解脫離文檔流具體是什么意思。
css規(guī)范中這樣描述絕對(duì)定位:
In the absolute positioning model, a box is removed from the normalflow entirely and assigned a position with respect to a containingblock.
請(qǐng)注意這里的entirely肄扎,這是在說(shuō)墨林,絕對(duì)定位是完全脫離文檔流的。為什么要強(qiáng)調(diào)完全呢犯祠?
因?yàn)樾竦龋撾x文檔流是一個(gè)比較曖昧的概念,還有不完全的衡载。請(qǐng)看浮動(dòng)的描述:
In the float model, a box is first laid out according to the normalflow, then taken out of the flow and shifted to the left or right asfar as possible.
前文已經(jīng)說(shuō)過(guò)搔耕,浮動(dòng)被歸類(lèi)為out of flow,也就是脫離文檔流痰娱,但這里卻提到了先基于文檔流取得一次位置弃榨,然后再向左或向右移動(dòng)。所以梨睁,浮動(dòng)不是完全脫離文檔流的鲸睛。
浮動(dòng)的特性
之前看到過(guò)別人的這樣一個(gè)提問(wèn):
對(duì)應(yīng)html代碼(css省略):
<div class="scheme-container">
<div class="scheme-element-normal">normal</div>
<div class="scheme-element-float">float</div>
</div>
按照傳統(tǒng)的“浮動(dòng)元素是脫離文檔流的”的理解,為什么這個(gè)右浮動(dòng)元素只是浮動(dòng)到了它所在行的右邊坡贺,而不是整個(gè)容器的右上角呢官辈?
答案就是,浮動(dòng)不是完全脫離文檔流的遍坟。這有兩方面的意思拳亿。
一方面,浮動(dòng)可以影響文檔流愿伴。你一定見(jiàn)過(guò)把一段文字里的某一個(gè)圖片浮動(dòng)风瘦,來(lái)制造文字環(huán)繞圖片效果的用法:
這些位于文檔流內(nèi)的文字,仍然會(huì)為浮動(dòng)元素留出空間公般,而并非互不相干万搔。這其實(shí)是浮動(dòng)元素影響行框(line box)的寬度的結(jié)果胡桨。
另一方面,浮動(dòng)會(huì)受到文檔流的影響瞬雹。規(guī)范里列出的浮動(dòng)元素的精確特性規(guī)則中有這樣一條:
The outer top of a floating box may not be higher than the outer top of any block or floated box generated by an element earlier in the source document.
這里的outer top就是margin edge (outer edge)的top edge昧谊。意思是,浮動(dòng)元素不可以高于任何在源文檔之前的塊元素或浮動(dòng)元素酗捌。我們很熟悉浮動(dòng)元素是會(huì)一個(gè)接一個(gè)地尋找空間排列的呢诬,但這一條卻告訴我們,如果前面還有塊元素胖缤,那么它們也會(huì)影響浮動(dòng)元素的上邊緣位置尚镰。
請(qǐng)看這個(gè)例子:
如果一個(gè)浮動(dòng)元素之前還有其他的浮動(dòng)元素,那么會(huì)考慮到它們哪廓,而可能排列到一個(gè)更靠下的位置狗唉。那么,如果之前還有塊元素涡真,而且占據(jù)了更大的位置呢分俯?從上圖可以看到,浮動(dòng)元素同樣會(huì)將其考慮在內(nèi)哆料。
這就是前面的提問(wèn)的詳細(xì)解釋了缸剪。
絕對(duì)定位
絕對(duì)定位大部分時(shí)候并不像浮動(dòng)這樣讓人困惑。顯然东亦,它被定義為“完全脫離文檔流”杏节,就是說(shuō)它和文檔流的關(guān)聯(lián)很弱,一般只根據(jù)包含塊和坐標(biāo)來(lái)確定位置就可以了典阵。
完全脫離文檔流拢锹,也仍然不是說(shuō)和文檔流毫不相干,各自為政萄喳。它的意思是:這個(gè)元素在參與布局時(shí)卒稳,不會(huì)影響在它之后的兄弟元素。絕對(duì)定位元素他巨,在left充坑、top等定位屬性取值auto的時(shí)候,仍然會(huì)根據(jù)文檔流取得一個(gè)可用的計(jì)算值染突。
三者的覆蓋關(guān)系
如果有重疊捻爷,就要考慮覆蓋關(guān)系了。它們的位置從下到上依次是:
-
z-index
為負(fù)的定位元素份企。 - 普通流(normal flow)的非行內(nèi)元素也榄。
- 浮動(dòng)元素。
- 普通流的行內(nèi)元素。
-
z-index
為auto
或0
的定位元素甜紫。 -
z-index
為正值的定位元素降宅。
結(jié)語(yǔ)
想要讓元素穩(wěn)定地待在為它預(yù)定的位置上,還是有很多功課要做的囚霸。本文只介紹了一部分有關(guān)位置的細(xì)節(jié)知識(shí)腰根,如果你也曾對(duì)這些內(nèi)容有所困惑,那么希望能有所幫助拓型。