深入理解CSS絕對定位

CSS中有3種定位機制:普通流,浮動和絕對定位。除非專門指定,否則所有框都在普通流中定位。顧名思義,普通流中元素框的位置由HTML元素的位置決定。塊級框一個接一個地垂直排列,框之間的垂直距離由框的垂直外邊距計算出。在本文中,我們主要講解3種定位機制之一的絕對定位,這就需要深入瞭解relative(相對定位),absolute(絕對定位)兩種position屬性值。

position的所有屬性值如下所示:

  • absolute,生成絕對定位的元素,相對於 static 定位以外的第一個父元素進行定位。
  • relative,生成相對定位的元素,相對於其正常位置進行定位。
  • fixed, 生成固定定位的元素,相對於瀏覽器窗口進行定位。 Fixed 定位在 IE7 和 IE8 下需要描述 !DOCTYPE 才能支持。Fixed定位使元素的位置與文檔流無關,因此不佔據空間。
  • static,默認值。沒有定位,元素出現在正常的流中(忽略 top, bottom, left, right 或者 z-index 聲明)。粘性定位的元素是依賴於用戶的滾動,在 position:relativeposition:fixed 定位之間切換。元素定位表現爲在跨越特定閾值前爲相對定位,之後爲固定定位。( Internet Explorer, Edge 15 及更早 IE 版本不支持 sticky 定位。 Safari 需要使用 -webkit-sticky)。
  • sticky,粘性定位,該定位基於用戶滾動的位置。
  • inherit,規定應該從父元素繼承 position 屬性的值。

1. 相對定位(relative)

相對定位是一個比較容易的概念,如果對一個元素設置相對定位,它將相對於自己本身在文檔流的位置,通過top/left/right/bottom設置定位。例如設置元素爲相對定位,然後設置top:20px;left:20px;則框將會出現在原位置頂部下面20px,左邊20px的位置,如下所示:

在使用相對定位時,無論是否移動,元素仍佔據原來的空間,即上圖框1與框3中間的那個虛框佔據的空間。因此,移動元素會導致它覆蓋其他框。

那麼問題來了,爲什麼它會覆蓋其他框呢

原因在於\(position:relative;\)可以提高元素的層疊上下文,而且提升很大,按照張鑫旭大神說的提升級別屬於鬼畜,本文實驗,將被覆蓋的元素框z-index屬性值設置爲999都還是被覆蓋掉了。

前面我們講過,可以通過設置top,left等屬性調整元素框的位置,那麼問題來了,當top和bottom或者left與right對立屬性同時存在,會發生什麼呢?

答案是:兩者會相互看不順眼,導致只能存在一方。top與bottom同時存在,top屬性生效,而bottom會被幹掉。同樣,left與right同時存在,left將幹掉right,只有left生效。

可能到這裏有讀者想問了,不是說好的講絕對定位這種定位機制嗎?怎麼還要先講一下relative(相對定位)了?

不要着急,答案馬上揭曉~

這裏當然不得不說相對定位與絕對定位的關係了!

相對定位對於絕對定位,能夠

  • 限制絕對定位的定位
  • 限制絕對定位的層級
  • 限制超越overflow

1.爲什麼說能夠限制絕對定位的定位呢

因爲絕對定位相對於最近的已定位(非static)以外的父元素,如果元素沒有已定位的父元素,那麼它的位置相對於html。

2.爲什麼說相對定位能夠限制絕對定位的層級呢

舉例,兩個absolute定位元素A和B,A的z-index屬性值爲3,B的爲2;A的relative父級元素存在z-index值(非auto),並且z-index爲2;B也一樣,但其相對於定位的父元素的z-index值爲3.這時候,A和B兩個元素的層級就不是由自身的z-index值決定了,而是由相對於定位的relative的父元素的z-index值決定。A的層級這時候也就低於B的層級。

3.爲什麼說能夠限制超越overflow呢

這是由於在沒有relative的父元素時,絕對定位的元素能夠通過top等屬性值超越自身所在的容器框,”飛出來“(在容器外顯示)。並且容器設置overflow值爲hidden,也不管用,這時候,只需要在容器上設置屬性position值爲relative,那麼該元素超越出容器外的部分就會被掩蓋(看不到容器外的那一部分)。

前面我們說了相對定位與絕對定位的關係,那麼相對定位還和別的定位存在某種關係(除同源外)嗎?

噹噹噹當~,當然啦!相對定位除了與絕對定位關係匪淺外,它和fixed定位關係似乎也不錯。不過,相對定位僅僅能夠限制fixed定位的z-index層級

不知道大家發現沒有,相對定位對於絕對定位和fixed定位都有講到層級。那麼相對定位與層級的關係是什麼呢

前面有講述到的(1)相對定位能夠大大提高元素的層疊上下文;(2)能夠限制absolute定位於fixed定位的層級

那麼爲什麼能夠限制absolute定位於fixed定位的層級,大家有想過嗎?答案是,當relative的元素存在z-index(非auto),那麼就會重建層疊上下文,這時就使得其下面的(相對於它定位的absolute/fixed元素)更新了z-index變成relative的值。那麼,當relative父元素的z-index值爲auto時呢

這時候,其下的(相對於它定位的absolute/fixed元素)層級就不受限制了,因爲不會發生重建層疊上下文(不包括IE 6/IE 7,IE 6/IE 7也會創建層疊上下文)。

這時候我們就要想了,爲auto時,該如何避免在IE 6/IE 7下創建層疊上下文呢?

這裏就需要了解relative的最小化影響原則了。

relative 最小化影響原則

所謂relative最小化影響原則,即指儘量降低realtive屬性對其他元素或佈局的潛在影響。具體來說可以總結爲兩點:

  1. 儘量避免使用relative原則
    • absolute定位不依賴relative(通過margin定位)
  2. relative最小化原則
    • 引入額外的空div包裹要絕對定位的元素,設置relative(不具備尺寸,不影響別的元素佈局,並且不會增加多的受relative影響的元素)進行定位。

2. 絕對定位(absolute)

相對定位實際上被看作普通流定位模型的一部分,因爲元素的位置是相對於它在普通流中的位置。與之相反,絕對定位使元素的位置與文檔流無關。因此不佔據空間,普通文檔流中其他元素的佈局就好像絕對定位元素不存在一樣。

絕對定位的元素的位置是相對於距離它最近的那個已定位的祖先元素確定的。如果元素沒有已定位的祖先元素,那麼它的位置是相對於初始包含塊的。根據用戶代理不同,初始包含塊可能是畫布或HTML元素。

同時,由於絕對定位與文檔流無關,所以它可以覆蓋頁面上其他元素。通過設置z-index屬性控制這些框的疊放次序。z-index值越高,框在棧中的位置越高。

2.1 absolute和float

相同特性:

  • 包裹性
  • 破壞性

兩者頁面佈局可相互代替。

破壞性

容器未設置height相關屬性(非max-height),則包裹元素設置absolute,容器高度塌陷。

包裹性

容器未設置高寬,則將容器設置absolute,將會包裹其內元素。

2.2 無依賴的absolute

絕對定位可以不與relative一起使用,功能更強大。

1.圖標定位

body {
    font: 14px/1.4 "Microsoft YaHei";
    background-color: #EDEFF0;
}

body,
 h3,
 h5 { margin: 0; }

img {
    border: 0 none;
    vertical-align: bottom;
}
.l { float: left; }
.r { float: right; }
.constr {
    width: 1200px;
    margin-left: auto;
    margin-right: auto;
 }

.header { background-color: #2A2C2E; }
.nav { height: 60px; }
.nav-list {
    float: left;
    font-size: 14px;
    font-weight: 400; }
.nav-a {
    display: inline-block;
    line-height: 20px;
    padding: 20px 35px;
    color: #B5BDC0;
    text-decoration: none; }
.nav-a:hover { color: #fff; }

.course { padding-top: 10px; }
.course-list {
    float: left;
    width: 280px;
    height: 240px;
    margin: 5px 10px 15px;
    border-radius: 0 0 1px 1px;
    background-color: #F7FAF9;
    background-color: rgba(255,255,255,1);
    box-shadow: 0 1px 2px #c5c5c5;
    text-decoration: none; }
.course-list-img { background-color: #6396F1;
}
.course-list-h {
    line-height: 50px;
    font-size: 14px;
    font-weight: 400;
    color: #363d40;
    text-align: center;
}
.course-list-tips {
    margin: 0 14px;
    font-size: 12px;
    color: #b4bbbf;
    overflow: hidden;
}

.icon-hot {
    position: absolute;
    width: 28px;
    height: 11px;
    margin: -6px 0 0 2px;
    background: url(http://img.mukewang.com/545304730001307300280011.gif);
}
.icon-recom {
    position: absolute;
    line-height: 20px;
    padding: 0 5px;
    background-color: #f60;
    color: #fff;
    font-size: 12px;
}
.icon-vip {
    position: absolute;
    width: 36px;
    height: 36px;
    margin-left: -36px;
    background: url(http://img.mukewang.com/5453048000015d8800360036.gif);
    text-indent: -9em;
    overflow: hidden;
}

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>圖標定位二三事</title>
<link rel="stylesheet" href="index.css">
</head>

<body>
<div class="header">
    <div class="constr">
        <div class="nav">
            <h3 class="nav-list">
            	<a href="http://www.imooc.com/course/list" class="nav-a">課程</a>
            </h3>
            <h3 class="nav-list">
            	<a href="http://www.imooc.com/wenda" class="nav-a">問答</a>
            </h3>
            <h3 class="nav-list">
            	<a href="http://www.imooc.com/seek/index" class="nav-a">
                	求課<i class="icon-hot"></i>
                </a>
            </h3>
        </div>
    </div>
</div>

<div class="main">
	<div class="constr">
    	<div class="course">
            <a href="http://www.imooc.com/view/121" class="course-list">
                <div class="course-list-img">
                	<span class="icon-recom">推薦</span>
                    <img width="280" height="160" alt="分享:CSS深入理解之float浮動" src="http://img.mukewang.com/53d74f960001ae9d06000338-300-170.jpg"><!--
                    --><i class="icon-vip">vip</i>
                </div>
                <h5 class="course-list-h">分享:CSS深入理解之float浮動</h5>
                <div class="course-list-tips">
                    <span class="l">已完結</span>
                    <span class="r">3514人學習</span>
                </div>
            </a>
        </div>
    </div>
</div>
</body>
</html>

2.下拉框定位最佳實踐

html:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>下拉框定位二三事</title>
<link rel="stylesheet" href="select.css">
</head>

<body>
<div class="constr">
    <div class="course-sidebar">
    	<div class="course-sidebar-type"></div>
        <div class="course-sidebar-search">
        	<ul id="result" class="course-sidebar-result">
            	<li><a href="http://www.imooc.com/view/121">分享:CSS深入理解之float浮動</a></li>
                <li><a href="http://www.imooc.com/view/118">案例:CSS圓角進化論</a></li>
                <li><a href="http://www.imooc.com/view/93">案例:CSS Sprite雪碧圖應用</a></li>
                <li><a href="http://www.imooc.com/view/77">案例:CSS3 3D 特效</a></li>
                <li><a href="http://www.imooc.com/view/57">案例:如何用CSS進行網頁佈局</a></li>
            </ul>
        	<input class="course-search-input" placeholder="課程搜索">
            <a href="javascript:" class="course-search-btn">搜索</a>
        </div>
    </div>
</div>
<script>
(function() {
	var input = document.getElementsByTagName("input")[0],
	    result = document.getElementById("result");

	if (input && result) {
		input.onfocus = function() {
			this.parentNode.className = "course-sidebar-search focus";
			if (this.value != "") {
				// show datalist
				result.style.display = "block";
			}
		};
		input.onblur = function() {
			if (this.value == "") {
				this.parentNode.className = "course-sidebar-search";
			}
			// hide datalist
			result.style.display = "none";
		};

		// IE7 that wrap a DIV for avoid bad effect from float
		if (!document.querySelector) {
			var div = document.createElement("div");
			input.parentNode.insertBefore(div, input);
			div.appendChild(result);
		}
		// events of datalist
		if ("oninput" in input) {
			input.addEventListener("input", function() {
				if (this.value.trim() != "") {
					result.style.display = "block";
				} else {
					result.style.display = "none";
				}
			});
		} else {
		    // IE6-IE8
			input.onpropertychange = function(event) {
				event = event || window.event;
				if (event.propertyName == "value" && /focus/.test(this.parentNode.className)) {
					if (this.value != "") {
						result.style.display = "block";
					} else {
						result.style.display = "none";
					}
				}
			}
		}
	}

})();
</script>
</body>
</html>

CSS:

body {
    margin: 0;
    font: 14px/1.4 "Microsoft YaHei";
    background-color: #EDEFF0;
}
.constr {
    width: 1200px;
    max-width: 80%;
    margin-left: auto;
    margin-right: auto;
    padding-bottom: 300px;
    overflow: hidden;
}
.course-sidebar {
    width: 262px;
    float: left;
}
.course-sidebar > div {
    border: 1px solid #e6e8e9;
    box-shadow: 0px 1px 2px #d5d7d8;
    background-color: #fff;
}
.course-sidebar-type { height: 380px; }
.course-sidebar-search {
    margin-top: 20px;
    overflow: hidden;
}
.course-search-input {
    width: 200px;
    line-height: 18px;
    padding: 10px;
    margin: 0;
    border: 0 none;
    font-size: 12px;
    font-family: inherit;
    float: left;
}
.course-sidebar-search.focus { border-color: #2ea7e0; }
.course-search-input:focus { outline: 0 none; }
.course-search-input::-ms-clear { display: none; }
.course-search-btn {
    width: 38px;
    height: 38px;
    float: right;
    background: url(http://img.mukewang.com/545305ba0001f3f600380076.png);
    text-indent: -9em;
    overflow: hidden;
}
.focus .course-search-btn { background-position: 0 -38px; }

.course-sidebar-result {
    display: none;
    position:
    absolute;
    width: 260px;
    margin: 39px 0 0 -1px;
    padding-left: 0;
    list-style-type: none;
    border: 1px solid #e6e8e9;
    background-color: #fff;
    box-shadow: 0px 1px 2px #d5d7d8;
    font-size: 12px;
}
.course-sidebar-result > li {
    line-height: 30px;
    padding-left: 12px;
}
.course-sidebar-result > li:hover { background-color: #f9f9f9; }
.course-sidebar-result a {
    display: block;
    color: #5e5e5e;
    text-decoration: none;
}
.course-sidebar-result a:hover { color: #000; }

3.居中以及邊緣定位最佳實踐

html:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>居中、邊緣定位二三事</title>
<link rel="stylesheet" href="center.css">
</head>

<body>
<div class="constr">
    <div class="course-content">
        <div class="course-list-x">
        	<div class="course-list"></div>
            <div class="course-list"></div>
            <div class="course-list"></div>
            <div class="course-list"></div>
            <div class="course-list"></div>
            <div class="course-list"></div>
        </div>
        <div class="course-loading-x">
        	&nbsp;<img src="http://img.mukewang.com/5453077400015bba00010001.gif" class="course-loading" alt="加載中...">
        </div>
        <div class="course-fixed-x">
        	&nbsp;<div class="course-fixed">
                <a href="http://www.imooc.com/activity/diaocha" class="goto_top_diaocha"></a>
                <a href="http://www.imooc.com/mobile/app" class="goto_top_app"></a>
                <a href="http://www.imooc.com/user/feedback" class="goto_top_feed"></a>
            </div>
        </div>
    </div>
</div>
</body>
</html>

css:

body {
    margin: 0;
    font: 14px/1.4 "Microsoft YaHei";
    background-color: #EDEFF0;
}
.constr {
    width: 1200px;
    max-width: 80%;
    margin-left: auto;
    margin-right: auto;
}
.course-content {
    float: right;
    position: relative;
    width: 920px;
    min-height: 1200px;
    background: #fff;
}
.course-list-x {
    padding: 20px 10px;
    overflow: hidden;
}
.course-list {
    float: left;
    width: 280px;
    height: 240px;
    margin: 5px 10px 15px;
    border-radius: 0 0 1px 1px;
    background-color: #F7FAF9;
    background-color: rgba(255,255,255,1);
    box-shadow: 0 1px 2px #c5c5c5;
    text-decoration: none;
}

.goto_top_diaocha,
.goto_top_app,
.goto_top_feed {
    display: block;
    width: 48px;
    height: 48px;
    margin-top: 10px;
    background: url(http://img.mukewang.com/5453076e0001869c01920098.png) no-repeat;
}
.goto_top_diaocha { background-position: -48px 0; }
.goto_top_diaocha:hover { background-position: -48px -50px; }
.goto_top_app { background-position: -96px 0; }
.goto_top_app:hover { background-position: -96px -50px; }
.goto_top_feed { background-position: -144px 0; }
.goto_top_feed:hover { background-position: -144px -50px; }

.course-loading-x {
    height: 0;
    margin-top: 20px;
    text-align: center;
    letter-spacing: -.25em;
    overflow: hidden;
}
.course-loading {
    position: absolute;
    margin-left: -26px;
}

.course-fixed-x {
    height: 0;
    text-align: right;
    overflow: hidden;
}
.course-fixed {
    display: inline;
    position: fixed;
     margin-left: 20px;
     bottom: 100px;
}

4.對齊溢出技巧

html:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>文本圖標對齊與定位二三事</title>
<link rel="stylesheet" href="tip.css">
</head>

<body>
<div class="constr">
    <div class="regist-head">註冊</div>
    <div class="regist-body">
    	<div class="regist-main">
        	<div class="regist-group">
            	<label class="regist-label"><span class="regist-star">*</span>登錄郵箱</label>
                <div class="regist-cell">
                	<input type="email" class="regist-input"><span class="regist-remark regist-warn">
                    	<i class="icon-warn"></i>郵箱格式不準確(演示)
                    </span>
                </div>
            </div>
            <div class="regist-group">
            	<label class="regist-label"><span class="regist-star">*</span>登錄密碼</label>
                <div class="regist-cell">
                	<input type="password" class="regist-input"><span class="regist-remark">
                    	請輸入6-16位密碼,區分大小寫,不能使用空格
                    </span>
                </div>
            </div>
            <div class="regist-group">
            	<label class="regist-label"><span class="regist-star">*</span>用戶暱稱</label>
                <div class="regist-cell">
                	<input type="password" class="regist-input">
                </div>
            </div>
            <div class="regist-group">
            	<label class="regist-label">手機號碼</label>
                <div class="regist-cell">
                	<input type="tel" class="regist-input">
                </div>
            </div>
            <div class="regist-group">
            	<label class="regist-label"><span class="regist-star">*</span>驗 證 碼</label>
                <div class="regist-cell">
                	<input class="regist-input regist-code-input"><img src="http://img.mukewang.com/545308540001678401500040.jpg">
                </div>
            </div>
            <div class="regist-group">
            	<label class="regist-label">&nbsp;</label>
                <div class="regist-cell">
                	<input type="checkbox" checked><label>我已閱讀並同意<a href="##">慕課協議</a>。</label>
                    <p>
                    	<a href="javascript:" class="regist-btn">立即註冊</a>
                    </p>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

css:

body {
    margin: 0;
    font: 14px/1.4 "Microsoft YaHei";
    background-color: #EDEFF0;
}
a { color: #50B6E5; }
.constr {
    width: 1200px;
    margin-left: auto;
    margin-right: auto;
}
.regist-head {
    height: 60px;
    line-height: 60px;
    padding-left: 30px;
    background-color: #be3948;
    color: #fff;
    font-size: 18px;
}
.regist-body {
    min-height: 400px;
    padding: 100px 0;
    background-color: #fff;
}
.regist-main {
    width: 600px;
    margin-left: auto;
    margin-right: auto;
}
.regist-group {
    margin-top: 20px;
    overflow: hidden;
}
.regist-label {
    width: 70px;
    padding-top: 10px;
    float: left;
}
.regist-cell {
    display: table-cell;
    *display: inline-block;
}
.regist-input {
    height: 18px;
    line-height: 18px;
    width: 260px;
    padding: 10px 5px;
    margin: 0 10px 0 0;
    border: 1px solid #d0d6d9;
    vertical-align: top;
}
.regist-code-input { width: 130px; }
.regist-btn {
    display: inline-block;
    width: 160px;
    line-height: 40px;
    background-color: #39b94e;
    color: #fff;
    text-align: center;
    text-decoration: none;
}
.regist-btn:hover { background-color: #33a646; }
.icon-warn {
    display: inline-block;
    width: 20px;
    height: 21px;
    background: url(http://img.mukewang.com/5453084a00016ae300120012.gif) no-repeat center;
}

.regist-star {
    position: absolute;
     margin-left: -1em;
     font-family: simsun;
     color: #f30;
}
.regist-remark {
    position: absolute;
    line-height: 21px;
    padding-top: 9px;
    color: #666;
}
.regist-warn {
    padding-left: 20px;
    color: #be3948;
}
.regist-warn > .icon-warn {
    position: absolute;
    margin-left: -20px;
}

2.3 脫離文檔流

使用absolute,元素會脫離文檔流,並且層級在普通元素之上(故,動畫儘可能使用在絕對定位元素上)。很多時候,我們會有這樣的誤區:”絕對定位元素都需要z-index控制層及,確定其顯示的垂直位置“。

然而,絕對定位與z-index層級是無依賴的。通常我們有這樣的準則:

  1. 若只有一個絕對定位元素,不需要z-index,自動覆蓋普通元素
  2. 如果兩個絕對定位元素,控制DOM流的前後順序,達到覆蓋效果,依然無z-index
  3. 如果多個絕對定位交錯(極其少見),z-index:1 控制
  4. 如果非彈框類的絕對定位元素z-index>2,必定z-index冗餘

2.4 定位與width/height

2.4.1 相互替代性

絕對定位的方向是對立的,結果會造成自身拉伸(IE7+)。很多情況下,absolute的定位的拉伸可以和width/height相互替代的。

滿屏自適應的50%的遮罩層:

{
	position: absolute;
	left: 0;
	top: 0;
	width: 50%;
	...
}
 <==等同於==>
{
	position: absolute;
	left: 0;
	top: 0;
	right: 50%;
	...
}

實現一個距離右側200像素的全屏自適應的容器層:

/* 推薦 直接使用拉伸 */
{
    position: absolute;
	left: 0;
	right:200px;
}
/* 否則,只能使用css3 calc計算 */
{
    position: absolute;
	left: 0;
	width: calc(100%-200px);
}

2.4.2 相互支持性

  • 容器無需固定width/height值,內部元素亦可拉伸;

  • 容器拉伸,內部元素支持百分比width/height值;

    通常情況下,元素百分比height要想起作用,需要父級容器的height值不是auto。但是在絕對定位的拉伸下,即使父級容器的height值是auto,只要容器絕對定位拉伸形成,百分比高度值也是支持的。

2.4.3 相互合作性

當尺寸限制,拉伸以及margin:auto同時出現的時候,就會有絕對定位元素的絕對居中效果。(IE8+)

3. 固定定位(fixed)

固定定位是絕對定位的一種。差異在於固定元素的包含塊是視口(viewport),這使得我們能夠創建總是出現在窗口中相同位置的浮動元素。(IE6和更低版本不支持該固定定位,IE7部分支持這個屬性,但是有許多bug。一些fixed定位可以通過absolute實現。)

參考:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章