0x00 简介
前文 📚 Layout 拾遗 提到了栅格布局系统中响应式布局的实现方式媒体查询
,本文将对其深入分析, 耐心读完,相信会对您有所帮助。
0x01 媒体查询
媒体查询 (Media queries )是实现响应式设计的最常见方法,它可以让我们根据设备的大致类型(如打印、手机、平板或电脑等)或者特定的特征和设备参数(例如屏幕分辨率和浏览器视口宽度)来调整网站或应用。 例如,缩小小型设备上的字体大小,判断手机朝向(横屏或竖屏)等。
CSS 语法
媒体查询语法通常使用 @media
(@规则
), 可用于基于一个或多个媒体查询的结果来应用样式表。
通过指定的媒体类型与正在显示文档的设备类型匹配,并且媒体查询中的所有表达式均为 true
,将应用样式规则。
复制 // 媒体类型 媒体特性表达式
@media media-type and (media-feature-rule) {
/* CSS rules go here */
}
媒体类型
媒体类型 (Media types )描述设备的一般类别。可以指定的媒体类型为:
screen
主要用于屏幕(计算机屏幕、平板电脑、智能手机)。
在不使用 not
或 only
操作符的情况下,媒体类型是可选的,默认为 all
。
媒体特性
媒体特性 (Media features )描述了 user agent、输出设备,或是浏览环境的具体特征。媒体特性表达式是完全可选的,它负责测试这些特性或特征是否存在、值为多少。每条媒体特性表达式都必须用括号括起来。
最常用的特性是视口宽度,可以使用min-width
(最常用 )、max-width
和width
媒体特性,在视口宽度大于或者小于某个大小——或者是恰好等于某个大小——的时候,应用 CSS 样式规则。
逻辑运算符
逻辑操作符 (logical operators ) 使用 not
, and
, only
和,
(逗号 ) 构建复杂的媒体查询。
and
运算符用来把多个媒体属性组合起来,合并到同一条媒体查询中。只有当每个属性都为真时,这条查询的结果才为真。
not
运算符用于否定媒体查询,如果不满足这个条件则返回 true,否则返回 false。 如果出现在以逗号分隔的查询列表中,它将仅否定应用了该查询的特定查询。 not
关键字不能用于否定单个媒体功能表达式,而只能用于否定整个媒体查询。
only
运算符仅在整个查询匹配时才用于应用样式,并且对于防止老式浏览应用所选样式很有用。
,
逗号将多个媒体查询合并为一个规则。 逗号分隔列表中的每个查询都与其他查询分开处理。 因此,如果列表中的任何查询为 true,则整个 @media
语句均返回 true。 换句话说,列表的行为类似于逻辑或or
运算符。
使用 not
, only
运算符,必须指定媒体类型 。
在老式浏览器中将@media only screen and (min-width: 992px) {...}
简单地解释为only
,因为没有叫 only
的设备,所以老式浏览器不会应用样式。 当不使用only
时,将@media screen and (min-width: 992px) {...}
简单地解释为screen
,忽略查询的其余部分,应用样式。
0x02 断点
断点 (Breakpoints ) 是响应式设计的基石。 它是可自定义的宽度,使用它可以控制何时可以在特定视口或设备大小下调整布局。
断点设置
参照了 Bootstrap 的 响应式设计,预设了五个响应尺寸:xs
、sm
、md
、lg
和 xl
。
在文件 theme-chalk\src\common\var.scss
定义了这些断点。
复制 /* Break-point
--------------------------*/
$--sm : 768 px !default ;
$--md : 992 px !default ;
$--lg : 1200 px !default ;
$--xl : 1920 px !default ;
// 断点Map
$--breakpoints : (
"xs" : (
max-width : $--sm - 1 ,
) ,
"sm" : (
min-width : $--sm ,
) ,
"md" : (
min-width : $--md ,
) ,
"lg" : (
min-width : $--lg ,
) ,
"xl" : (
min-width : $--xl ,
) ,
);
0x03 组件响应式实现
@mixin res()
在文件 theme-chalk\src\mixins\mixins.scss
定义了指令 res
构建 css,使用媒体查询来创建关键的分界点阈值。
复制 /* Break-points
-------------------------- */
// 断点Map
$--breakpoints : (
"xs" : (
max-width : 767 px ,
) ,
"sm" : (
min-width : 768 px ,
) ,
"md" : (
min-width : 992 px ,
) ,
"lg" : (
min-width : 1200 px ,
) ,
"xl" : (
min-width : 1920 px ,
) ,
);
@mixin res ($key, $map : $--breakpoints) {
// 循环断点Map,如果存在则返回
@if map-has-key ($map , $key) {
@media only screen and #{ inspect ( map-get ($map , $key))} {
@content ;
}
} @else {
@warn "Undefeined points: `#{$map}`" ;
}
}
指令功能逻辑如下:
指令 res
接受两个参数 $key
(响应尺寸) 和 $map
(断点 Map)。
指令内部使用函数 map-has-key($map,$key)
作用是根据 $key
参数,返回 $key
在 $map
中对应的 value 值。如果 $key
不存在 $map
中,将返回 null 值(此时生成警告断点未定义 Undefeined points
)。
若返回 true,使用函数 map-get($map,$key)
返回 $key
在 $map
中对应的 value 值。
使用函数 inspect($value)
将其转成字符串,使用插值 #{}
、@content
生成 媒体查询。
复制 // 参数 $key 值为 xs
// 获取Map
map-get($map, $key) => ( max-width: 767px )
// 返回string
inspect(map-get($map, $key)) => '( max-width: 767px )'
@media only screen and #{ inspect ( map-get ($map , $key))} { @content ; }
// 编译结果
@media only screen and ( max-width : 767 px ) { ... }
在栅格系统中,媒体查询通过断点构建 CSS。响应式布局五个响应尺寸样式如下:
复制 /* 超小屏幕(手机,小于 768px) */
@media only screen and ( max-width : 767 px ) {
...;
}
/* 小屏幕(平板,大于等于 768px) */
@media only screen and ( min-width : 768 px ) {
...;
}
/* 中等屏幕(桌面显示器,大于等于 992px) */
@media only screen and ( min-width : 992 px ) {
...;
}
/* 大屏幕(大桌面显示器,大于等于 1200px) */
@media only screen and ( min-width : 1200 px ) {
...;
}
/* 超大屏幕(大桌面显示器,大于等于 1920px) */
@media only screen and ( min-width : 1920 px ) {
...;
}
0x04 基于断点的隐藏实现
Element
额外提供了一系列类名,用于在某些条件下隐藏元素。
使用方式
首先,项目引入样式文件:
复制 import "element-ui/lib/theme-chalk/display.css" ;
然后将这些类名可以添加在任何 DOM 元素或自定义组件上。
hidden-xs-only
- 当视口在 xs
尺寸时隐藏
hidden-sm-only
- 当视口在 sm
尺寸时隐藏
hidden-sm-and-down
- 当视口在 sm
及以下尺寸时隐藏
hidden-sm-and-up
- 当视口在 sm
及以上尺寸时隐藏
hidden-md-only
- 当视口在 md
尺寸时隐藏
hidden-md-and-down
- 当视口在 md
及以下尺寸时隐藏
hidden-md-and-up
- 当视口在 md
及以上尺寸时隐藏
hidden-lg-only
- 当视口在 lg
尺寸时隐藏
hidden-lg-and-down
- 当视口在 lg
及以下尺寸时隐藏
hidden-lg-and-up
- 当视口在 lg
及以上尺寸时隐藏
hidden-xl-only
- 当视口在 xl
尺寸时隐藏
实现原理
文件 theme-chalk\src\common\var.scss
定义了隐藏类断点 Map$--breakpoints-spec
,使用逻辑运算符 and
,让媒体查询能跨越多个断点宽度。
复制 $--breakpoints-spec : (
"xs-only" : (
max-width : $--sm - 1 ,
) ,
"sm-and-up" : (
min-width : $--sm ,
) ,
"sm-only" : "(min-width: #{$--sm}) and (max-width: #{$--md - 1 })" ,
"sm-and-down" : (
max-width : $--md - 1 ,
) ,
"md-and-up" : (
min-width : $--md ,
) ,
"md-only" : "(min-width: #{$--md}) and (max-width: #{$--lg - 1 })" ,
"md-and-down" : (
max-width : $--lg - 1 ,
) ,
"lg-and-up" : (
min-width : $--lg ,
) ,
"lg-only" : "(min-width: #{$--lg}) and (max-width: #{$--xl - 1 })" ,
"lg-and-down" : (
max-width : $--xl - 1 ,
) ,
"xl-only" : (
min-width : $--xl ,
) ,
);
转译后内容如下,定了关于视口宽度的各种媒体查询规则。
复制 $--breakpoints-spec : (
"xs-only" : (
max-width : 767 px ,
) ,
"sm-and-up" : (
min-width : 768 px ,
) ,
"sm-only" : "(min-width: 768px) and (max-width: 991px)" ,
"sm-and-down" : (
max-width : 991 px ,
) ,
"md-and-up" : (
min-width : 992 px ,
) ,
"md-only" : "(min-width: 992px) and (max-width: 1199px)" ,
"md-and-down" : (
max-width : 1199 px ,
) ,
"lg-and-up" : (
min-width : 1200 px ,
) ,
"lg-only" : "(min-width: 1200px) and (max-width: 1919px)" ,
"lg-and-down" : (
max-width : 1919 px ,
) ,
"xl-only" : (
min-width : 1920 px ,
) ,
);
使用指令 res
生成带前缀 hidden
的隐藏类。隐藏类 CSS 规则 display: none !important;
用于隐藏元素。
复制 // 类前缀
.hidden {
// 遍历 Map $--breakpoints-spec
@each $break-point-name, $value in $--breakpoints-spec {
// 生成.hidden-#{$break-point-name} 如 hidden-xs-only hidden-sm-only
& -#{$break-point-name} {
// 生成媒体查询
@include res ($break-point-name, $--breakpoints-spec) {
display : none !important ;
}
}
}
}
最终生成 display.css
,内容如下:
复制 // 当视口在 `xs` 尺寸时
@media only screen and ( max-width : 767 px ) {
/* .hidden-xs-only */
}
// 当视口在 `sm` 及以上尺寸时
@media only screen and ( min-width : 768 px ) {
/* .hidden-sm-and-up */
}
// 当视口在 `sm` 尺寸时
@media only screen and ( min-width : 768 px ) and ( max-width : 991 px ) {
/* .hidden-sm-only */
}
// 当视口在 `sm` 及以下尺寸时
@media only screen and ( max-width : 991 px ) {
/* .hidden-sm-and-down */
}
// 当视口在 `md` 及以上尺寸时
@media only screen and ( min-width : 992 px ) {
/* .hidden-md-and-up */
}
// 当视口在 `md` 尺寸时
@media only screen and ( min-width : 992 px ) and ( max-width : 1199 px ) {
/* .hidden-md-only */
}
// 当视口在 `md` 及以下尺寸时
@media only screen and ( max-width : 1199 px ) {
/* .hidden-md-and-down */
}
// 当视口在 `lg` 及以上尺寸时
@media only screen and ( min-width : 1200 px ) {
/* .hidden-lg-and-up */
}
// 当视口在 `lg` 尺寸时
@media only screen and ( min-width : 1200 px ) and ( max-width : 1919 px ) {
/* .hidden-lg-only */
}
// 当视口在 `lg` 及以下尺寸时
@media only screen and ( max-width : 1919 px ) {
/* .hidden-lg-and-down */
}
// 当视口在 `xl` 尺寸时
@media only screen and ( min-width : 1920 px ) {
/* .hidden-xl-only */
}
0x05 📚 参考
“使用媒体查询”,MDN
“Media_queries”,MDN
"@规则",MDN
screen sizes
“sass 在线编辑器”,sassmeister.com