一个常见的问题是如何使用它window.matchMedia()
来对多个CSS媒体查询做出反应。在JavaScript中的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阶段完成的操作。