1. 程式人生 > >HTML&CSS面試高頻考點(三)

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; 的區別?

  1. display: none; 元素消失,也不再佔據空間;visibility: hidden; 元素消失但仍然佔據空間;
  2. visibility具有繼承性,其子元素也會繼承此屬性,若給子元素設定visibility:visible,則子元素會顯示;
  3. visibility不會影響計數器的計算,雖然隱藏掉了,但是計數器依然繼續執行著;
  4. 在css3的transition中支援visibility屬性,但是不支援display,因為transition可以延遲執行,因此配合visibility使用純css實現hover延時顯示效果可以提高使用者體驗;
  5. display:none會引起迴流(重排)和重繪 visibility:hidden只會引起重繪。

opacity:0 只是讓內容不可見,透明度為0,在渲染樹中,在dom文件中仍舊佔領位置,子元素也不會展示,而且子元素不能通過設定opacity:1來展示,元素的點選事件可用。

重繪重排

重繪重排是由於瀏覽器再次渲染引起的,首先了解瀏覽器的渲染過程。

渲染引擎會解析HTML文件來構建DOM樹,同時用CSS解析器解析CSS文件構建CSSOM樹。接下來將兩者關聯起來構成渲染樹(RenderTree),這一過程稱為Attachment。然後瀏覽器按照渲染樹進行佈局(Layout),最後一步通過繪製顯示出整個頁面。

  • 重排(迴流):render tree中的一部分因元素的規模尺寸、佈局、隱藏等改變需要重新構建。頁面第一次載入的時候必須進行一次迴流。迴流的時候,瀏覽器會使渲染樹中受到影響的部分失效,並重新構造這部分樹。
  • 重繪:完成迴流後,瀏覽器重新繪製受影響的部分到螢幕中。

迴流必定引起重繪,而重繪不一定引起迴流。

迴流導致渲染樹需要重新計算,開銷較大,所以要儘量避免迴流。

重繪的產生:更新隻影響元素的外觀、風格,而不影響佈局的屬性。eg: visibility, outline, 背景顏色等。

避免迴流的方法:

  1. 樣式集中改變(老版本才有的問題,現代瀏覽器已有Flush佇列進行渲染佇列優化);
  2. 快取佈局資訊;
  3. position屬性為absolute或fixed的元素,迴流開銷比較小;
  4. 使用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. 重排和重繪

*前面有提到喲~

觸發重排的機制:

  1. 新增或刪除可見的DOM元素
  2. 元素位置改變
  3. 元素本身的尺寸發生改變
  4. 內容改變
  5. 頁面渲染器初始化
  6. 瀏覽器視窗大小發生改變

效能優化:

下面這段程式碼,會使瀏覽器發生三次重排:

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。

快取佈局資訊

當訪問諸如offsetLeftclientTop這種屬性時,會衝破瀏覽器自有的優化——通過佇列化修改和批量執行的方法,減少重排/重繪版次。所以我們應該儘量減少對佈局資訊的查詢次數,查詢時,將其賦值給區域性變數,使用區域性變數參與計算。

//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,選擇使用者選取的