在前端开发中,我们往往需要一套网页同时支持适配 不同分辨率屏幕WEB端 (PC端和移动端),而我们将同时能够自适配不同分辨率屏幕的网页称为响应式网页。在最初方案中我们通过 JS 监听浏览器视区宽度变化来实现响应式布局 (onresize) ,但当我们监听浏览器视区宽度 resize,卸载当前样式文件,然后加载新的样式文件。以此往复网页不断卸载样式、加载新样式,此时我们就会看到明显网页抖动。可见 JS 来触发响应式布局,并不是一种好的方式。
所以为了实现平滑、顺畅、无抖动的响应式布局,CSS3 推出了 媒体查询 @media。
简介
媒体查询 可以让我们根据设备显示器的特性(如视口宽度、屏幕比例、设备方向:横向或纵向)为其应用特定的 CSS 样式,媒体查询由媒体类型或检测媒体特性的条件表达式组成。
媒体类型: 媒体类型描述了给定设备的一般类别
媒体特性: 媒体功能描述了给定的的输出设备或环境的特定特征
语法定义
在 @media 语法中,定义待应用样式的媒体
/* 堆代码 duidaima.com */
/* 适配所有媒体 */
@media { /* css code */ }
@media all { /* css code */ }
/* 仅适配打印媒体 */
@media print {
/* css code */
}
/* 仅适配手机设备 */
@media (max-width: 768px) {
/* css code */
}
/* 仅适配竖屏设备 */
@media (orientation: portrait) {
/* css code */
}
在 style 元素的 media 属性中,定义待应用样式的媒体
<!-- 适配所有媒体 -->
<style type="text/css"></style>
<!-- 仅适配打印媒体 -->
<style type="text/css" media="print"></style>
<!-- 仅适配手机设备 -->
<style type="text/css" media="(max-width: 768px)"></style>
<!-- 仅适配竖屏设备 -->
<style type="text/css" media="(orientation: portrait)"></style>
@import url语法中,定义待应用样式的媒体
/* 适配所有媒体 */
@import url('./index.css');
/* 仅适配打印媒体 */
@import url('./index.css') print;
/* 仅适配手机设备 */
@import url('./index.css') (max-width: 768px);
/* 仅适配竖屏设备 */
@import url('./index.css') (orientation: portrait);
在 <link> 元素的 media 属性中,定义了待应用链接资源(通常是 CSS)的媒体
<!-- 适配所有媒体 -->
<link rel="stylesheet" href="./index.css">
<!-- 仅适配打印媒体 -->
<link rel="stylesheet" href="./index.css" media="print">
<!-- 仅适配手机设备 -->
<link rel="stylesheet" href="./index.css" media="(max-width: 768px)">
<!-- 仅适配竖屏设备 -->
<link rel="stylesheet" href="./index.css" media="(orientation: portrait)">
在 <picture> 之内 <source> 元素的 media 属性中,定义不同的显示/设备场景提供图像版本
<picture>
<source srcset="./lower.jpg" media="(max-width: 768px)" />
<source srcset="./higher.jpg" media="(min-width: 960px)" />
<img src="./normal.png" alt="photo" />
</picture>
在媒体查询中,有这么一些注意事项:
1.媒体类型是必要条件,但 all 可以省略
2.媒体特性是次要条件,可以不定义。如果定义必须用小括号括起来且只能定义一个
3.媒体类型、媒体特性,他们彼此之间需使用 逻辑运算符 关联, 即“与”、“或”、“非”
逻辑运算符
当创建一个取决于多个条件的复杂媒体查询时, 这就是需要 逻辑运算符 的配合使用。具体如下:
and: 将媒体功能与媒体类型或其他媒体功能组合一起, 用户设备完全匹配时应用样式,例如
/* 仅适配横向的手机设备 */
@media (max-width: 768px) and (orientation: landscape) {
/* css code */
}
,: 用户设备与各种媒体类型或特性中任何一种匹配时,可以用逗号分隔来应用样式,例如
/* 适配用户设备的最小宽度为 768px 或 纵向模式的屏幕设备 */
@media (min-width: 768px), screen and (orientation: portrait) {
/* css code */
}
not: 会反转整个媒体查询的含义。它只会否定要应用的特定媒体查询。例如
/* 下面两者等价 */
@media not all and (monochrome) {}
@media not (all and (monochrome)) {}
/* 下面两者等价 */
@media not screen and (color), print and (color) {}
@media (not (screen and (color))), print and (color) {}
only: 防止不支持带有媒体功能的媒体查询的旧版浏览器应用给定的样式。对现代浏览器没有影响
/* 适配屏幕媒体 */
@media only screen {}
媒体查询的应用
例如常见的 Bootstrap 响应式栅格系统设计
/* Small devices (landscape phones, 576px and up) */
@media (min-width: 576px) { ... }
/* Medium devices (tablets, 768px and up) */
@media (min-width: 768px) { ... }
/* Large devices (desktops, 992px and up) */
@media (min-width: 992px) { ... }
/* X-Large devices (large desktops, 1200px and up) */
@media (min-width: 1200px) { ... }
/* XX-Large devices (larger desktops, 1400px and up) */
@media (min-width: 1400px) { ... }
媒体查询单位
相关 JS API
JavaScript 中可以使用 Window.matchMedia() 方法根据媒体查询进行测试。还可以使用 MediaQueryList.addListener() 在查询状态发生变化时收到通知。借助此功能,你的应用动态响应设备配置,方向或状态的更改。
matchMedia() 方法返回一个新的 MediaQueryList 对象,用于判定 document 是否匹配媒体查询,或者监控 document 来判定它匹配了或者停止匹配了此媒体查询。
window.matchMedia('(min-width: 600px)')
// result:
// {
// matches: true,
// media: "(min-width: 600px)",
// onchange: null
// }
addListener() 方法向 MediaQueryListener添加一个侦听器,该侦听器将运行自定义回调函数以响应媒体查询状态的更改。
const mql = window.matchMedia("(min-width: 600px)")
mql.addListener(function(e) {
if (e.matches) {
/* 视口宽度 >= 600像素 */
} else {
/* 视口宽度 < 600像素 */
}
})
与容器查询区别 ?
媒体查询 @media 关注匹配的是浏览器窗口尺寸
容器查询 @container 关注匹配的是父容器元素尺寸