1. 程式人生 > >CSS佈局總結及實際應用中產生的問題

CSS佈局總結及實際應用中產生的問題

佈局初步

所謂佈局,其實是指的將網頁內容以一定的方式放到合適的位置上去。
佈局的基本步驟:
1, 將“當前版面”以視覺上界限明顯的方式進行劃分若干個區塊,劃分只用兩種方式:
a) 上下結構:此時,只要使用若干個盒子,自然就是上下結構,無需其他設定。
b) 左右結構:此時使用若干個盒子,並進行相應的浮動,通常的模式:
i. 2個盒子:一左一右
ii. 3個盒子:兩左一右或兩右一左,或一邊倒。
iii. 更多盒子:通常一邊倒。

浮動解釋

浮動就像水中的氣泡,會“網上浮” 更形象的比喻:大家(所有標籤)都在“地面上平鋪著”,各自佔據著一定的面積,浮動元素卻“浮”到天花板上去了,其並佔據大家通常的“地面面積”

浮動除了表現上不跟別的元素搶佔地盤之外,其最主要的特性(也就是破壞效果)其實是:使其父盒子失去合理高度——父盒子已經包不住其這些浮動的內部盒子了!這在佈局中基本上是不允許的!那麼我們就必須使用補充的做法來實現合理包含——父盒子包住子盒子。

總結:佈局需要左右排列,左右排列需要浮動,浮動需要修正其破壞效果——讓父盒子合理包住其子盒子。

複習文件流

文件流 首先我們先了解一個概念,文件流“Normal flow”是css中定位的一種預設情況,平時我們所說的BFC、IFC等都是“Normal flow”的情況下的規則。

常規情況下脫離文件流的是float,absolute,fixed。

英文文件解釋的意思,當元素浮動的時候,會先遵循“Normal flow”的規則,然後儘可能的向倆邊靠。

所以float並不是會脫離文件流,反而是依賴於文件流。position中的absolute和fixed的情況下,官方文件解釋說會完全脫離“Normal flow”。

在“Normal flow”中,BFC規則中,文字會圍繞在浮動元素旁邊。出現了這種現象,可能國人就自定義了“文字流”這種東西。

總結:表面上看,float脫離了“文件流”,沒有脫離“文字流”;position中的absolute和fixed全部脫離。這種解釋也合情合理,是標準答案。

浮動和浮動的清除定位和定位的常用方法fixed和absolute:兩者的效果在沒有滾動條的時候是一樣的區別:fixed是固定定位,absolute是絕對定位。Fixed塊有滾動條之後不顯示。 relative和absolute:absolute塊脫離文件流,relative會保留定位塊原來的位置 static是預設的定位

注意:absolute相對於父元素定位,父元素必須是absolute和relative定位 脫離文件流的定位:absolute,fixed,浮動

複習常用標籤及盒模型

HTML元素分類 HTML元素分類

1,塊級元素 block 如:div、p、h1-h6、li、ul、ol、dl
特點: ①獨佔一行顯示; ②可以設定寬度、高度、行高和上下邊距; ③不設寬度,則和父元素的寬度一致

2,行內元素 inline 如:a、span
特點: ①可以和其他行內元素在一行上顯示 ②不可以設定寬度、高度、行高和上下邊距 ③元素的寬度就是它包含的文字或圖片的寬度

3,行內塊元素 inline-block 如:img、input
特點: ①可以和其他行內塊元素或行內元素在一行上顯示 ②可以設定寬度、高度、行高和上下邊距 不同型別元素可以相互轉換: display:block; display:inline-block;

盒模型

在CSS看來,任何元素都是一個盒子。

CSS框模型:

1,基礎知識點

①width和height不能應用於行內元素(行內非替換元素)②width、height預設值為auto;padding、border、margin預設寬度為0; margin可取值auto,padding和border不可以! 背景會延伸到內邊距中,但不會延伸到外邊距③margin、border、padding取值方式:四個值(上、右、下、左) top right bottom left三個值(上、左右、下)兩個值(上下 、左右)一個值(上右下左)

2,margin

①不僅是左右margin,還有上下margin,其百分數取值都是相對於父元素的width計算的

②正常流中的塊級元素垂直相鄰外邊距會合並

③對於行內非替換元素(行內元素):上下外邊距無效果(因為它對行高沒有任何影響?),左右外邊距有效

④對於行內替換元素(行內塊元素):上下外邊距會影響行高,所以有效果,左右外邊距也有效

⑤width、margin-left、margin-right這三個屬性都設定非auto的某個值,此時,總會把margin-right強制為auto

⑥width:100px;margin-left:auto;margin-right:auto;這會將兩個外邊距設定為相等的長度,從而將元素居中

⑦將某個外邊距及width設定為auto,該外邊距會減為0;將width、margin-left、margin-right三個都設定為auto,則兩個外邊距都會重置為0,而width儘可能寬

⑧正常流中一個塊級元素的margin-top或margin-bottom設定為auto,它會自動計算為0

⑨標準流中,第一個子元素的margin-top會作用在父元素身上原因:根據規範,一個盒子如果沒有上補白(padding-top)和上邊框(border-top),那麼這個盒子的上邊距會和其內部文件流中的第一個子元素的上邊距重疊解決辦法:給父元素加個padding-top或border-top或overflow:hidden⑩標準流元素、浮動元素可以相互佔對方類的margin,但不可佔其同類的margin;絕對定位與固定定位,誰的margin都可以佔,即使是同類,然而,任意的元素也可以佔它們的margin

3,border/padding

①對於行內非替換元素(行內元素):上下邊框(或內邊距)對行高沒有任何影響,所以有可能覆蓋上下內容;左右邊框(或內邊距)正常顯示,相鄰文字會在其旁邊顯示②對於行內替換元素(行內塊元素):上下邊框(或內邊距)會影響行高,所以不會覆蓋上下內容,左右邊框(或內邊距)也正常顯示/* 屬性型別寫法舉例 */margin: 10px;margin-top: 10px; padding: 10px;padding-top: 10px; border: 1px red solid;border-top: 1px red solid;border-top-width: 1px;border-width: 1px;border-style: solid;border-color: red;

4,行內塊元素顯示多餘空白問題行內塊元素的盒子之間會存在一定的空隙(4px);是由於盒子間的空白字元造成的解決辦法:

①可以把程式碼首尾相連寫在一起,不留空白字元(不能消除底部空白),不推薦使用

②設定其父元素 font-size:0;/* 要使高度不同,有內容的inline-block盒子以底部整齊排列 */

/* 方式一: */vertical-align: bottom;

/* 方式二: */overflow: hidden;

去除圖片底部4px空白:

①給其父元素設定font-size:0; 或 line-height:0;

②給圖片設定display:block; 或 vertical-align:bottom;

浮動CSS允許浮動任何元素

float: left | right | none

①浮動元素會從文件的正常流中刪除,不佔原來的位置;即元素浮動後會脫離標準流

②一個元素浮動時,其他內容會“環繞”該元素(不僅對於浮動影象)

③要浮動一個非替換元素,則必須為該元素宣告一個width

④元素浮動後就具有了行內塊元素的特性,浮動元素會生成一個塊級框浮動

規則(部分):

①浮動元素只能在其包含塊內容區內浮動(除了設定負外邊距和浮動元素比其包含塊更寬)

②浮動元素互相貼靠,不會相互重疊

③浮動元素的頂端應當與其標記所在行框(源文件中)的頂端對齊

④行內框與浮動元素重疊時,其所有都在浮動元素“之上”顯示;

塊框與浮動元素重疊時,僅內容在浮動元素“之上”顯示

邊框和背景在浮動元素“之下”顯示

浮動元素的包含塊是其最近的塊級祖先元素

定位position

定位靜態定位 static:預設值 元素標準流的顯示方式相對定位

relative:相對其原位置定位,仍佔原來的空間絕對定位

absolute:①不佔原來的空間,元素框從文件流完全刪除;②能將行內元素轉化為行內塊元素; ③相對於其包含塊定位,其包含塊為最近的position值不是static的祖先元素。

固定定位 fixed:①不佔原來的空間,元素框從文件流完全刪除;②能將行內元素轉化為行內塊元素; ③相對於其包含塊定位,其包含塊為視窗絕對定位元素的包含塊為最近的position值不是static的祖先元素,祖先是塊級元素,包含塊則為由邊框界定的區域;祖先是行內元素,包含塊則為該祖先元素的內容邊界定位需使用到偏移屬性;

偏移屬性:left right top bottom (可取正值也可取負值)

z-index:應用於定位元素,可以改變元素相互覆蓋的順序; 取值越高的元素離使用者越近,並覆蓋值低的元素;可以取所有整數,包括負數

分析脫離文字流產生的css層級問題

什麼是CSS規則之層疊上下文

若兩條規則具有相同的權值、起源及特殊性,那在樣式表中最後出現的規則優先。
任何位於文件中的規則都比引入的規則優先 

注意點

元素設定了position屬性後,這個定位元素的z-index就會自動生效,此時它的z-index值就是預設的auto,也就是0。

層級不取小數

層級一樣,後面的盒子比前面的盒子的層級高

浮動或者標準流的盒子,後面的盒子比前面的層級高

解決子級物件使用css float浮動 而父級div不能自適應高度,不能被父級內容撐開解決方法,父級div沒有高度解決方法

最外層的父級DIV不能自適應高度-不能隨物件撐開沒有高度

當在物件內的盒子使用了float後,導致物件本身不能被撐開自適應高度,這個是由於浮動產生原因。

如何解決父div物件自適應高度,方法有三種

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8" /> 
<title>父div不自適應高度例項</title> 
<style> 
	.divcss5{ width:500px; border:1px solid #000; padding:10px} 
	.divcss5-lf{ float:left; width:220px; height:100px; background:#000} 
	.divcss5-rt{ float:right; width:230px; height:100px; background:#06F} 
</style> 
</head> 
<body> 
	<div class="divcss5"> 
		<div class="divcss5-lf"></div> 
		<div class="divcss5-rt"></div> 
	</div> 
</body> 
</html>  

問題截圖:

方法一:對父級設定固定高度

<!DOCTYPE html> 
<html> 
<head> 
	<meta charset="utf-8" /> 
	<title>父div不自適應高度例項</title> 
	<style> 
		.divcss5{width:500px;border:1px solid #000;padding:10px; height:100px} 
		.divcss5-lf{ float:left; width:220px; height:100px; background:#000} 
		.divcss5-rt{ float:right; width:230px; height:100px; background:#06F} 
	</style> 
</head> 
<body> 
	<div class="divcss5"> 
		<div class="divcss5-lf"></div> 
		<div class="divcss5-rt"></div> 
	</div> 
</body> 
</html> 

對父加高度100px 解決外層父div自適應高度截圖

此方法缺點,父級是固定高度,而不隨內容高度自適應高度,沒高度。此方法針對能確定父div內的內容高度情況下使用。

使用css clear清除浮動

對父級div標籤閉合</div>前加一個clear清除浮動物件

<!DOCTYPE html> 
<html> 
<head> 
	<meta charset="utf-8" /> 
	<title>父div不自適應高度例項</title> 
	<style> 
		.divcss5{width:500px;border:1px solid #000;padding:10px} 
		.divcss5-lf{ float:left; width:220px; height:100px; background:#000} 
		.divcss5-rt{ float:right; width:230px; height:100px; background:#06F} 
		.clear{ clear:both} 
	</style> 
</head> 
<body> 
	<div class="divcss5"> 
	<div class="divcss5-lf"></div> 
	<div class="divcss5-rt"></div> 
	<div class="clear"></div> 
	</div> 
</body> 
</html> 

使用clear:both清除父級內子物件產生浮動

此方法需要注意是clear:both加的位置,不是對父級直接加clear樣式,而是在父級</div>前加帶clear物件盒子

方法三:對父級樣式加overflow樣式

此方法非常簡單,也可以作為推薦解決父級不能被撐開自適應高度的方法,可以不增加div盒子物件,只需要對父級加一個overflow:hidden樣式即可

<!DOCTYPE html> 
<html> 
<head> 
	<meta charset="utf-8" /> 
	<title>父div不自適應高度例項</title> 
	<style> 
		.divcss5{width:500px;border:1px solid #000;padding:10px;overflow:hidden} 

		.divcss5-lf{ float:left; width:220px; height:100px; background:#000} 
		.divcss5-rt{ float:right; width:230px; height:100px; background:#06F} 
	</style> 
	</head> 
<body> 
	<div class="divcss5"> 
		<div class="divcss5-lf"></div> 
		<div class="divcss5-rt"></div> 
	</div> 
</body> 
</html> 

父div加overflow樣式解決父自適應高度

推薦。此方法為非常簡單解決子用float,父div不能自適應高度,不能隨父內容多少而自適應高度沒有高度,但是要注意一旦子元素的大小超過父容器的大小,就會出顯示問題

 

方法四:浮動的父容器

另一種思路是,索性將父容器也改成浮動定位,這樣它就可以帶著子元素一起浮動了

<div style="float:left;">
<div style="float:left;width:45%;"></div>
<div style="float:right;width:45%;"></div>
</div>

這種方法不用修改HTML程式碼,但是缺點在於父容器變成浮動以後,會影響到後面元素的定位,而且有時候,父容器是定位死的,無法變成浮動

方法五:After偽類清除浮動(最推薦)

<!DOCTYPE html> 
<html> 
<head> 
	<meta charset="utf-8" /> 
	<title>父div不自適應高度例項</title> 
	<style> 
		.clearfix{width:500px;border:1px solid #000;padding:10px;} 

		.divcss5-lf{ float:left; width:220px; height:100px; background:#000} 
		.divcss5-rt{ float:right; width:230px; height:100px; background:#06F}
		.clearfix:after{
			content:"";
			display:block;
			visibility:hidden;
			clear:both;
			height:0;}
		.clearfix{ /* 為了照顧ie6瀏覽器*/
			zoom:1;}
	</style> 
	</head> 
<body> 
	<div class="clearfix"> 
		<div class="divcss5-lf"></div> 
		<div class="divcss5-rt"></div> 
	</div> 
</body> 
</html> 

最完整的清浮動操作

/* slightly enhanced, universal clearfix hack */
.clearfix:after {
     visibility: hidden;
     display: block;
     font-size: 0;
     content: " ";
     clear: both;
     height: 0;
}
.clearfix { display: inline-block; }
/* start commented backslash hack \*/
* html .clearfix { height: 1%; }
.clearfix { display: block; }
/* close commented backslash hack */

一個國外大佬的最牛清浮動https://perishablepress.com/lessons-learned-concerning-the-clearfix-css-hack/

.clearfix:before,.clearfix:after{
content:"";
display:table;
}
.clearfix:after{
clear:both;
}
.clearfix{ /*照顧ie6*/
zoom:1;
}
使用:
<div class="box clearfix">

After before偽類清除浮動是大部分大型網站常用的,比如新浪 淘寶 的清除浮動的效果

浮動產生負作用

背景不能顯示
由於浮動產生,如果對父級設定了(CSS background背景)CSS背景顏色或CSS背景圖片,而父級不能被撐開,所以導致CSS背景不能顯示。

邊框不能撐開
如上圖中,如果父級設定了CSS邊框屬性(css border),由於子級裡使用了float屬性,產生浮動,父級不能被撐開,導致邊框不能隨內容而被撐開。

margin padding設定值不能正確顯示
由於浮動導致父級子級之間設定了css padding、css margin屬性的值不能正確表達。特別是上下邊的padding和margin不能正確顯示

vw與vh的使用

響應式佈局的單位我們第一時間會想到通過rem單位來實現適配,但是它還需要內嵌一段指令碼去動態計算跟元素大小。 
比如:

(function (doc, win) {

 let docEl = doc.documentElement

 let resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'

 let recalc = function () {

   var clientWidth = docEl.clientWidth

   if (!clientWidth) return

   docEl.style.fontSize = 14 * (clientWidth / 320) + 'px'

 }

 if (!doc.addEventListener) return

 win.addEventListener(resizeEvt, recalc, false)

 doc.addEventListener('DOMContentLoaded', recalc, false)

})(document, window)

那有沒有一個單位不需要JS和CSS耦合在一起的單位?答案是有的,那就是vw/vh

vw = view width

vh = view height

這兩個單位是CSS3引入的,以上稱為視口單位允許我們更接近瀏覽器視窗定義大小。

視口單位(Viewport units)

什麼是視口
A:Peter-Paul Koch(”PPK大神”)提出視口的解釋是:在桌面端,視口指的是在桌面端,指的是瀏覽器的可視區域;而在移動端,它涉及3個視口:Layout Viewport(佈局視口),Visual Viewport(視覺視口),Ideal Viewport(理想視口)。

視口單位中的“視口”,桌面端指的是瀏覽器的可視區域;移動端指的就是Viewport中的Layout Viewport。

vh/vw與%區別

 

單位 解釋
vw 1vw = 視口寬度的1%
vh 1vh = 視口高度的1%
vmin 選取vw和vh中最小的那個
vmax 選取vw和vh中最大的那個

 

比如:瀏覽器視口尺寸為370px,那麼 1vw = 370px * 1% = 6.5px(瀏覽器會四捨五入向下取7)

vh/vw與%區別在於

單位 依賴於
% 元素的祖先元素
vh/vw 視口的尺寸

相容性問題

在移動端 iOS 8 以上以及 Android 4.4 以上獲得支援,並且在微信 x5 核心中也得到完美的全面支援。

僅使用vw作為CSS單位

使用 vw 單位作為唯一應用的一種 CSS 單位的這種做法下

1.根據設計稿的尺寸轉換為vw單位(SASS函式編譯)

//iPhone 6尺寸作為設計稿基準
$vm_base: 375;
@function vm($px) {
   @return ($px / 375) * 100vw;
}

2.無論是文字還是佈局高寬、間距等都使用 vw

<div class="mod_nav">

 <nav class="mod_nav_list" v-for="n in 5">

   <a href="#" class="mod_nav_list_item">

     <span class="mod_nav_list_item_logo">

       <img src="http://jdc.jd.com/img/80">

     </span>

     <p class="mod_nav_list_item_name">導航入口</p>

   </a>

 </nav>

</div>

.mod_nav {

   background: #fff;

   &_list {

       display: flex;

       padding: vm(15) vm(10) vm(10);

       &_item {

           flex: 1;

           text-align: center;

           font-size: vm(10);

           &_logo {

               display: block;

               margin: 0 auto;

               width: vm(40);

               height: vm(40);

               img {

                   display: block;

                   margin: 0 auto;

                   max-width: 100%;

               }

           }

           &_name {

               margin-top: vm(2);

           }
       }
   }
}

會得到這樣的效果

 

不同的手機型號都可以正常顯示,這一點非常棒

最優做法——搭配vw和rem

使用vm作為css單位程式碼量確實減少很多,但是你會發現它是利用視口單位實現,依賴於視口大小而自動縮放,失去了最大最小寬度的限制。

所以,我們需要結合rem單位來實現佈局,而rem正好可以動態改變根元素大小,做法是:

  1. 給根元素大小設定vw–動態改變大小。

  2. 限制根元素font-size的最大最小值,配合bosy加上最大最小寬度。

// rem 單位換算:定為 75px 只是方便運算,750px-75px、640-64px、1080px-108px,如此類推

$vm_fontsize: 75; // iPhone 6尺寸的根元素大小基準值
@function rem($px) {
    @return ($px / $vm_fontsize ) * 1rem;

}

// 根元素大小使用 vw 單位

$vm_design: 750;
html {
   font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw;
   // 同時,通過Media Queries 限制根元素最大最小值
   @media screen and (max-width: 320px) {
       font-size: 64px;

   }
   @media screen and (min-width: 540px) {
       font-size: 108px;
   }

}

// body 也增加最大最小寬度限制,避免預設100%寬度的 block 元素跟隨 body 而過大過小
body {
   max-width: 540px;
   min-width: 320px;

} 

另外要注意一點:width:100%是相對你上層的標籤而言,基本上跟你上層便籤一樣的寬度,但是width:auto是根據你這個標籤裡面的元素的寬度來自動調節本身的寬度 

html、css、js檔案載入順序及執行情況

HTML頁面載入和解析流程 

使用者輸入網址(假設是個html頁面,並且是第一次訪問),瀏覽器向伺服器發出請求,伺服器返回html檔案。 
瀏覽器開始載入html程式碼,發現<head>標籤內有一個<link>標籤引用外部CSS檔案。 
瀏覽器又發出CSS檔案的請求,伺服器返回這個CSS檔案。 
瀏覽器繼續載入html中<body>部分的程式碼,並且CSS檔案已經拿到手了,可以開始渲染頁面了。 
瀏覽器在程式碼中發現一個<img>標籤引用了一張圖片,向伺服器發出請求。此時瀏覽器不會等到圖片下載完,而是繼續渲染後面的程式碼。 
伺服器返回圖片檔案,由於圖片佔用了一定面積,影響了後面段落的排布,因此瀏覽器需要回過頭來重新渲染這部分程式碼。 
瀏覽器發現了一個包含一行Javascript程式碼的<script>標籤,趕快執行它。 
Javascript指令碼執行了這條語句,它命令瀏覽器隱藏掉程式碼中的某個<style>(style.display=”none”)。杯具啊,突然就少了這麼一個元素,瀏覽器不得不重新渲染這部分程式碼。 
終於等到了</html>的到來,瀏覽器淚流滿面…… 
等等,還沒完,使用者點了一下介面中的“換膚”按鈕,Javascript讓瀏覽器換了一下<link>標籤的CSS路徑。 
瀏覽器召集了在座的各位<div><span><ul><li>們,“大夥兒收拾收拾行李,咱得重新來過……”,瀏覽器向伺服器請求了新的CSS檔案,重新渲染頁面。

總結:1.總的來說就是按照html文件的順序載入

   2.還有就是最好將無論內部或是外部JS檔案放到所有html內容之後,這樣會令使用者感覺頁面載入速度變快了,否則如果將所有外部檔案(包括css和JS)引用都放到<head>中,意味著必須等到全部的JS程式碼都被下載解析和執行完畢後,才能開始呈現頁面的內容(當瀏覽器遇到<body>),這樣會導致呈現頁面時出現明顯的延遲,二延遲期間的瀏覽器視窗將是一片空白。

 

補充

<head lang="en">
    <meta charset="utf-8">
    <title></title>
    <link rel="stylesheet" href="css/*.css">
    <script src="js/*.js></script>
</head>

DOM文件的載入順序是由上而下的順序載入;

1、DOM載入到link標籤

css檔案的載入是與DOM的載入並行的,也就是說,css在載入時Dom還在繼續載入構建,而過程中遇到的css樣式或者img,則會向伺服器傳送一個請求,待資源返回後,將其新增到dom中的相對應位置中;

2、DOM載入到script標籤

由於js檔案不會與DOM並行載入,因此需要等待js整個檔案載入完之後才能繼續DOM的載入,倘若js指令碼檔案過大,則可能導致瀏覽器頁面顯示滯後,出現“假死”狀態,這種效應稱之為“阻塞效應”;會導致出現非常不好的使用者體驗;

而這個特性也是為什麼在js檔案中開頭需要$(document).ready(function(){})或者(function(){})或者window.onload,即是讓DOM文件載入完成之後才執行js檔案,這樣才不會出現查詢不到DOM節點等問題;

js阻塞其他資源的載入的原因是:瀏覽器為了防止js修改DOM樹,需要重新構建DOM樹的情況出現;

3、解決方法

前提,js是外部指令碼;

在script標籤中新增 defer=“ture”,則會讓js與DOM並行載入,待頁面載入完成後再執行js檔案,這樣則不存在阻塞;

在scirpt標籤中新增 async=“ture”,這個屬性告訴瀏覽器該js檔案是非同步載入執行的,也就是不依賴於其他js和css,也就是說無法保證js檔案的載入順序,但是同樣有與DOM並行載入的效果;

同時使用defer和async屬性時,defer屬性會失效;

可以將scirpt標籤放在body標籤之後,這樣就不會出現載入的衝突了。