使用window.matchMedia()匹配多個CSS媒體查詢
一個常見的問題是如何使用它window.matchMedia()
來對多個CSS媒體查詢做出反應。在教程中,我們快速概述 並使用它來響應單個CSS媒體查詢更改:window.matchMedia()
1 2 3 4 五 6 7 8 9 10 11 12 13 |
|
在這裡,我們只監視一個CSS媒體查詢window.matchMedia()
,即“ screen and (max-width: 800px)
”,並在瀏覽器跨越該閾值時作出反應。
響應多個CSS媒體查詢
為了響應使用多個CSS媒體查詢window.matchMedia()
,我們基本上只是多次重複上述一個媒體查詢的藍圖。為了簡化程式碼,我們可以先使用陣列儲存所有window.matchMedia()
查詢,然後使用for
迴圈來呼叫處理所有查詢的單個函式。讓我們看看現在:
1 2 3 4 五 6 7 8 9 10 11 12 13 14 15 16 |
|
單擊此處檢視上述例項示例 - 在水平和垂直調整瀏覽器視窗大小時,將顯示不同的布林值,以反映當前匹配的媒體查詢。
我們現在有了連線多個媒體查詢的基本模式window.matchMedia()
,雖然像很多東西一樣,魔鬼在細節中。當我們有一個響應所有媒體查詢的處理函式時,它意味著將多次呼叫此函式。這本身不是問題,實際上是設計的。在上面的示例中,處理函式window.matchMedia()
連線到3個不同的window.matchMedia()
查詢,因此稱為以下次數:
-
頁面首次載入時三次,每次處理頁面首次載入時可能匹配的每個查詢
-
每次滿足輸入查詢之一的閾值時。如果使用者將瀏覽器的大小從900px調整為860px,然後調整為700px,則
(max-width: 860px)
當瀏覽器超過860px閾值時,將觸發一次查詢“ ”。將視窗大小調整為900px會再次觸發相同的查詢。
雖然多次呼叫我們的處理函式是為了處理我們的所有window.matchMedia()
查詢,但您可能不希望在每次呼叫期間執行此函式內的所有內容,至少為了提高效率。在上面的示例中,當匹配“ (max-width: 860px)
”時,執行函式內的所有3行,而不是僅將“ #match1”元素設定為相應的布林值的行。這可以通過基於觸發函式的媒體查詢選擇性地執行程式碼來避免,這是我們接下來要看的。
- 找出window.matchMedia()
觸發處理函式的查詢
使用單個函式處理所有window.matchMedia()
查詢匹配,有用 - 如果不是必要的話 - 有時可以確定哪個確切的查詢觸發了該函式。這與簡單地確定查詢是否成功匹配不同,我們可以使用matches
儲存在陣列中的每個查詢的屬性輕鬆找出:
1 2 3 4 五 6 7 8 9 10 11 |
|
為了確定哪個window.matchMedia()
查詢實際觸發了處理函式,我們需要不僅檢查matches
屬性,還要檢視media
傳入MediaQueryList
物件的屬性,它返回觸發查詢列表的序列化字串。在處理函式中,MediaQueryList
物件作為函式的第一個引數傳遞,或者在本例中為紅色引數:
1 2 3 |
|
為了使事情稍微複雜化media
,MediaQueryList
物件屬性的返回值 在非IE(IE11)和IE瀏覽器之間略有不同。鑑於以下window.matchMedia()
查詢,例如:
1 |
|
在非IE瀏覽器中,mql.media
返回完全“ (max-width: 860px)
”,而在IE中,它返回“ all and (max-width:860px)"
而不是。所以IE返回不同的是以下內容:
-
all
在缺少查詢中指定的媒體的情況下,在字串前面新增“ ”的媒體 -
刪除每個屬性和屬性值之間的任何空格,因此“
max-width:860px
”中沒有空格。
當media
用一些正則表示式探測屬性時,我們可以均衡這些差異。以下window.matchMedia()
處理函式根據匹配window.matchMedia()
的mqls
陣列中的哪個查詢列表 有選擇地執行不同的程式碼:
1 2 3 4 五 6 7 8 9 10 11 12 13 14 15 16 17 |
|
media
首先在處理函式內檢查屬性,確保只根據觸發處理程式的媒體查詢執行函式體的特定部分。結果類似於為每個window.matchMedia()
查詢定義單獨的函式,具有更易於管理的單個函式。然而,它沒有缺點。CSS媒體查詢很多時候會在範圍上重疊,因此針對一個查詢的程式碼也會針對另一個查詢進行測試。通過基於傳入window.matchMedia()
查詢對功能程式碼進行分段,每個塊都成為互斥區域,無法同時將自身應用於其他區域,這取決於您正在使用的媒體查詢集。在那種情況下,使用 mql.matches
相反,因為您的主邏輯交換機是更好的路由,即使它意味著相同的程式碼可能會執行多次。
示例 - 對響應式佈局做出反應
讓我們看一個更精細的例子,現在使用JavaScript來響應3列響應式佈局,其中一個CSS媒體查詢的範圍與另一個CSS媒體查詢重疊,以及如何在我們的JavaScript處理函式中處理它。當瀏覽器寬度為840px或更低時,以下3列布局使用普通CSS媒體查詢更改為2列,而當600px或更低時,更改為單列。這是我們將首先使用的示例頁面:
通過860px和600px斷點調整頁面大小,以檢視結構中的佈局偏移。現在,我們在每個列中都有靜態文字,分別顯示列的原始寬度 - “ 180px,固定和 190px ”。我們將使用JavaScript在840px和600px斷點處動態更改此文字,以相應地反映列寬的變化。結果如下:
通過860px和600px斷點調整新頁面的大小,以檢視文字更新以反映當前列狀態。為此,我們的JavaScript必須對頁面CSS中使用的相同兩個媒體查詢做出反應:
-
@media(最大寬度:840px){}
-
@media(最大寬度:600px){}
並考慮以下3種情況:
-
佈局為840px或更低時
-
當佈局為600px時低於
-
當佈局既不是860px或更低也不是600px或更低(無響應)
這是完整的JavaScript:
1 2 3 4 五 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
我們處理函式內部的邏輯被設定,因此程式碼的每個部分彼此不相互排斥 - (max-width: 600px)
例如,當查詢匹配“ ” 時,“ ”也是如此(max-width: 840px)
,反之亦然,所以我們不應該使用“ else
”宣告跟隨每個“ if
”宣告以捕捉“對立”狀態,這可能是眾多之一。相反,只需逐步執行我們的程式碼,並最終測試何時兩個查詢都不匹配,以檢測何時佈局既不是840px也不是600px寬。
現在,看看這一行:
1 |
|
在if
佈局為840px或更低時匹配的“ ”子句內部。它可能看起來多餘 - 畢竟,leftcolumn
當螢幕寬度超過840px時,我們已經設定“ ”顯示“180px”,所以進入840px,為什麼重複相同的動作?原因是我們還需要考慮在相反方向發生的事件 - 即,從窄螢幕(即:640px或更小)到更寬螢幕(即:840px或更高)。在640px階段,“ leftcolumn
”文字被替換為“Fluid(響應佈局觸發)”。當用戶將瀏覽器的大小調整回840px或更高時,需要程式碼撤消在640px階段完成的操作。