HTML&CSS面試高頻考點(三)
11. CSS隱藏元素的方式
/*佔據空間,無法點選*/ visibility: hidden; position: relative; top: -999em; /* 不佔據空間,無法點選 */ position: absolute; top: -999em; display: none; position: absolute; visibility: hidden; height: 0; overflow: hidden; /*可以點選*/ opacity: 0; filter:Alpha(opacity=0); /* 佔據空間,可以點選 */ position: absolute; opacity: 0; filter:Alpha(opacity=0); /* 不佔據空間,可以點選 */
=> display: none; 和 visibility: hidden; 的區別?
- display: none; 元素消失,也不再佔據空間;visibility: hidden; 元素消失但仍然佔據空間;
- visibility具有繼承性,其子元素也會繼承此屬性,若給子元素設定visibility:visible,則子元素會顯示;
- visibility不會影響計數器的計算,雖然隱藏掉了,但是計數器依然繼續執行著;
- 在css3的transition中支援visibility屬性,但是不支援display,因為transition可以延遲執行,因此配合visibility使用純css實現hover延時顯示效果可以提高使用者體驗;
- display:none會引起迴流(重排)和重繪 visibility:hidden只會引起重繪。
opacity:0 只是讓內容不可見,透明度為0,在渲染樹中,在dom文件中仍舊佔領位置,子元素也不會展示,而且子元素不能通過設定opacity:1來展示,元素的點選事件可用。
重繪重排
重繪重排是由於瀏覽器再次渲染引起的,首先了解瀏覽器的渲染過程。
渲染引擎會解析HTML文件來構建DOM樹,同時用CSS解析器解析CSS文件構建CSSOM樹。接下來將兩者關聯起來構成渲染樹(RenderTree),這一過程稱為Attachment。然後瀏覽器按照渲染樹進行佈局(Layout),最後一步通過繪製顯示出整個頁面。
- 重排(迴流):render tree中的一部分因元素的規模尺寸、佈局、隱藏等改變需要重新構建。頁面第一次載入的時候必須進行一次迴流。迴流的時候,瀏覽器會使渲染樹中受到影響的部分失效,並重新構造這部分樹。
- 重繪:完成迴流後,瀏覽器重新繪製受影響的部分到螢幕中。
迴流必定引起重繪,而重繪不一定引起迴流。
迴流導致渲染樹需要重新計算,開銷較大,所以要儘量避免迴流。
重繪的產生:更新隻影響元素的外觀、風格,而不影響佈局的屬性。eg: visibility, outline, 背景顏色等。
避免迴流的方法:
- 樣式集中改變(老版本才有的問題,現代瀏覽器已有Flush佇列進行渲染佇列優化);
- 快取佈局資訊;
- position屬性為absolute或fixed的元素,迴流開銷比較小;
- 使用DocumentFragment,讓要操作的元素進行“離線處理”。
12. Flex佈局
♥前文介紹
13. 雙欄佈局 三欄佈局
♥兩列布局
三列布局:
(1)浮動解決方案
.layout1 .left{ float: left; } .layout1 .right{ float: right; }
(2)絕對定位解決方案
.layout2 .left-center-right>div{ position: absolute; } .layout2 .left{ left: 0; width: 300px; } .layout2 .center{ left: 300px; right: 300px; //定左右欄的寬度 } .layout2 .right{ right: 0; width: 300px; }
(3)Flex佈局
.layout3 .left-center-right{ display: flex; } .layout3 .left{ width: 300px; } .layout3 .center{ flex:1; } .layout3 .right{ width: 300px; }
(4)表格佈局
.layout4 .left-center-right{ width: 100%; display: table; height: 100px; //高度會跟著變 } .layout4 .left-center-right>div{ display: table-cell; } .layout4 .left{ width: 300px; } .layout4 .right{ width: 300px; }
在高度不已知的情況下3,4仍能使用(會自動撐開)。
14. 重排和重繪
*前面有提到喲~
觸發重排的機制:
- 新增或刪除可見的DOM元素
- 元素位置改變
- 元素本身的尺寸發生改變
- 內容改變
- 頁面渲染器初始化
- 瀏覽器視窗大小發生改變
效能優化:
下面這段程式碼,會使瀏覽器發生三次重排:
var el = document.querySelector('.el'); el.style.borderLeft = '1px'; el.style.borderRight = '2px'; el.style.padding = '5px';
如果能夠合併為一次處理,這樣DOM就只修改節點一次。這樣最小化的方式有兩種:
(1)使用cssText屬性
var el = document.querySelector('.el'); el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px';
(2)改變類名
// css .active { padding: 5px; border-left: 1px; border-right: 2px; } // javascript var el = document.querySelector('.el'); el.className = 'active';
最小化的方式適合修改單個節點的情況。當需要批量修改節點的時候,則需要換一種方式:
(1)隱藏元素,進行修改後,然後再顯示該元素
let ul = document.querySelector('#mylist'); ul.style.display = 'none'; appendNode(ul, data); ul.style.display = 'block';
發生了兩次重排,分別是隱藏和顯示的時候。
(2)使用文件片段建立一個子樹,然後再拷貝到文件中
let fragment = document.createDocumentFragment(); appendNode(fragment, data); ul.appendChild(fragment);
只在將文件片段的子節點群插入的時候發生了一次重排。且不會造成元素短暫消失的邏輯問題。
(3)將原始元素拷貝到一個獨立的節點中,操作這個節點,然後覆蓋原始元素
let old = document.querySelector('#mylist'); let clone = old.cloneNode(true); appendNode(clone, data); old.parentNode.replaceChild(clone, old);
這種方法也只發生了一次重排(將操作完的複製節點插入的時候),但相較於文件片段的方式,更多的操作了DOM。
快取佈局資訊
當訪問諸如offsetLeft
,clientTop
這種屬性時,會衝破瀏覽器自有的優化——通過佇列化修改和批量執行的方法,減少重排/重繪版次。所以我們應該儘量減少對佈局資訊的查詢次數,查詢時,將其賦值給區域性變數,使用區域性變數參與計算。
//bad div.style.left = 1 + div.offsetLeft + 'px'; div.style.top = 1 + div.offsetTop + 'px'; //good current = div.offsetLeft; div.style.left = 1 + ++current + 'px'; div.style.top = 1 + ++current + 'px';
每次都會訪問div的offsetLeft,造成瀏覽器強制重新整理渲染佇列以獲取最新的offsetLeft值。更好的辦法就是,將這個值儲存下來,避免重複取值。
15. CSS選擇器
♥前文
(一)基本選擇器
1. 標籤選擇器
2. ID選擇器 “#”
ID的命名要求:
- 只能有字母、數字、下劃線。
- 必須以字母開頭。
- 不能和標籤同名。比如id不能叫做body、img、a。
- 大小寫嚴格區分,也就是說aa,和AA是兩個不同的ID
HTML頁面,不能出現相同的id,哪怕他們不是一個型別。比如頁面上有一個id為pp的p,一個id為pp的div,是非法的!
3. 類選擇器 “.”
-
特性1:類選擇器可以被多種標籤使用。
-
特性2:同一個標籤可以使用多個類選擇器。用空格隔開。
4. 通配選擇器 => 屬性選擇器
屬性名選擇器:
[attribute],用於選擇所有帶有特定屬性的元素,例如 [title]
,選擇所有帶有 title 屬性的元素。
屬性值選擇器:
*[title(="...")]{...},匹配所有帶有title標籤的
a[href(="...")][title(="...")]{color:red}將同時有 href(="...")和 title(="...")屬性的 HTML 超連結的文字設定為紅色
(二)高階選擇器
1. 後代選擇器
空格隔開 後代不一定是子元素,只要有祖先後代的關係就可以。
子元素選擇器: >(直接的子元素)
同級元素選擇器: a~b (與a元素同級的b元素)
相鄰元素選擇器:eg: h3+p 意思是h3後面的第一個p。
2. 交集選擇器
不空格!(空格的就是後代選擇器了)
一般不會連交,IE低版本不支援。
3. 並集選擇器
逗號隔開。
4. 偽類選擇器
<a>
標籤對應幾種不同的狀態:
link
:超連結點選之前visited
:超連結點選之後focus
:是某個標籤獲得焦點的時候(比如某個輸入框獲得焦點)hover
:滑鼠放到某個標籤上的時候active
:點選某個標籤沒有松鼠標時
(1)靜態偽類:只能用於超連結
a{}
和a:link{}
的區別:
a{}
定義的樣式針對所有的超連結(包括錨點)a:link{}
定義的樣式針對所有寫了href屬性的超連結(不包括錨點)
(2)動態偽類:針對所有標籤都適用
focus(聚焦,點選某個文字框後輸入文字,可以定義文字框和文字的屬性)
:是某個標籤獲得焦點的時候(比如某個輸入框獲得焦點)hover(盤旋,滑鼠停留在上面)
:滑鼠放到某個標籤上的時候active(長按狀態)
:點選某個標籤沒有松鼠標時
(3)結構偽類選擇器
:nth-child(n),選擇同級元素中的第 n 個元素(元素下標是從1開始的)
也可以使用 even(偶數), odd(奇數) 關鍵字
:nth-last-child(n)
:first-child
:last-child
:only-child
:nth-of-type(n),選擇同級元素中的第 n 個同類元素
eg:.box > :nth-of-type(2)
<div class="box"> <p>第一個 p 子元素,不會被選中</p> <span>第一個 span 子元素,不會被選中</span> <p>第二個 p 子元素,會被選中</p> <span>第二個 span 子元素,會被選中</span> </div>
:nth-last-of-type
:first-of-type
:last-of-type
:only-of-type
(4):root 選擇器
選擇文件的根元素,對於 HTML 文件就是 html 元素。
(5):empty 偽類選擇器
選擇沒有子元素的元素(包括文字節點)
5. 偽元素選擇器
::first-letter,選擇元素的第一個字母
::first-line,選擇元素的第一行
::before/::after
::before,選擇在元素之前插入的生成內容
::after,選擇在元素之後插入的生成內容
::selection,選擇使用者選取的