在前端领域中,我们所说的响应式设计,其实就是UI要匹配不同尺寸的设备,能够完整展示网页内容。
这就需要在CSS设置对应的适配规则:
@media规则
@media规则就是用来匹配不同设备的,比如响应式布局中常用到的宽度查询和适配:
.left{
width:200px;
height:100px;
}
@media only screen and (max-width:480px){
.left{
display:none;
}
}
这段css代码就是在设备屏幕宽度小于480px的时候,侧边栏隐藏。
那么@media规则由四部分组成:
- 媒体查询修饰符only;
- 媒体类型screen;
- 媒体条件and;
- 媒体特性max-width;
媒体查询修饰符
css媒体查询有两个修饰符:only和not。not就是否定意思,否定了整个查询语句;only修饰符最早是用来区分IE7和IE8的,因为这类老版本的浏览器会忽略不能识别的媒体条件和媒体特性,比如会把screen and 识别为screen。现在如果不考虑老版本的浏览器的话,那么only修饰符也就没有意义了。
媒体类型
常见的媒体类型有screen、print和all。print类型只有在打印和打印预览的时候生效;其他的场景就使用screen;all就表示匹配所有的设备了。例如:
@media print{
header,footer{
display:none;
}
}
这段样式代码表示在打印的时候,头部和尾部直接隐藏。
如果想指定多个媒体类型的话,就使用逗号隔开。比如:
@media screen,print{}
媒体条件
媒体条件是有三个:not、and和or。
not表示否定某个媒体特性; and表示同时满足所有条件; or表示满足所有 条件之一即可。
例如:
/*如果设备更新频率慢或者是不支持鼠标行为*/
@media (update:slow) or (hover:none){}
/*宽度在320px到480px,同时分辨率在150dpi的设备*/
@media only screen{
and (min-width:320px)
and (max-width:480px)
and (resolution:150dpi){
body{
line-height:2;
}
}
}
媒体特性
媒体特性就是对媒体特性的描述信息,包括浏览器、用户设备和使用环境。比如:
/*设备像素比等于2*/
@media (-webkit-device-pixel-ratio:2){}
@media (resolution:2dppx){}
/*设备像素比大于2*/
@media (-webkit-min-device-pixel-ratio:2){}
@media (min-resolution:2dppx){}
CSS媒体特性有很多,但是我们常用到也就是width、height,以及宽高比例和屏幕分辨率这些特性。
这里有两个浏览器已经更新了的特性:
prefers-color-scheme,用来检测当前网页是否处于深色模式或者是黑暗模式,它的参数如下:
- no-preference,表示系统没有告知用户使用的颜色方案;
- light,表示系统倾向于使用浅色模式;
- dark,表示系统倾向于使用深色模式
比如:
@media (prefers-color-scheme:dark){
body{
filter:invert(1) hue-rotate(180deg);
background:#333;
color:#fff;
}
img{
filter:invert(1) hua-rotate(180deg);
}
}
如果需要在JavaScript中对系统判断主题的话,可以使用原生的window.matchMedia()方法,比如:
window.matchMedia("prefers-color-scheme:dark").matches;
prefers-reduced-motion:检测系统是否设置不必要动画的操作,参数如下:
- no-preference表示用户没有通知系统任何首选项
- reduced表示用户已通知系统
比如有这样的场景,在PC端浏览器展示一张图片,当鼠标经过图片时才显示图片的描述信息;如果是在移动端访问这张图片的话,图片的描述信息直接显示,代码如下:
.img-text{
display:none;
}
img:hover{
display:block;
}
@media (any-hover){
.img-text{
display:block;
}
}
环境变量函数env()
env()函数,是为了解决带有刘海屏和底部触摸条的移动设备,如果按钮和触摸条很贴近,那么就会出现交互冲突,env函数正好是让网页内容显示在设备的安全区域范围内。
/* 直接使用4个安全内边距值 */
env(safe-area-inset-top);
env(safe-area-inset-right);
env(safe-area-inset-bottom);
env(safe-area-inset-left);
/* 使用4个安全内边距值,同时设置兜底尺寸值 */
env(safe-area-inset-top, 20px);
env(safe-area-inset-right, 1em);
env(safe-area-inset-bottom, 0.5vh);
env(safe-area-inset-left, 1.4rem);
rem、vw单位和移动端适配
rem,其中的r表示是root的意思,在html网页中,root指的是html元素。当我们在html元素设置一个字体大小的时候,如:
html{
font-size:16px;
}
那么0.5rem就等于8px,1rem等于16px。如果要整个网页都保持弹性,那么就需要让元素的宽高和文字大小使用rem单位,然后在不同的宽度设备设置对应的根字号大小即可,比如:
html{
font-size:16px;
}
@media (min-width:414px){
html{
font-size:18px;
}
}
@media (min-width:600px){
html{
font-size:20px;
}
}
还有一种方式在head嵌入一段JavaScript代码:
document.documentElement.style.width = document.documentElement.clientWidth / 7.5 + 'px';
这两种方式效果不太好,因为很难捕获到准确的临界点,比如有的设备宽度是411px。
另一个最佳的方案是结合可视区域相对单位:vw、vh、vmin、vmax,和calc函数,代码如下:
html {
font-size: 16px;
}
@media screen and (min-width: 375px) {
html {
/* 375px作为16px基准,414px宽度时正好对应18px的根字号大小 */
font-size: calc(16px + 2 * (100vw - 375px) / 39);
}
}
@media screen and (min-width: 414px) {
html {
/* 屏幕宽度从414px到1000px,根字号大小累积增加4px(18px-22px) */
font-size: calc(18px + 4 * (100vw - 414px) / 586);
}
}
@media screen and (min-width: 1000px) {
html {
/* 屏幕宽度从1000px往后每增加100px,根字号大小就增加0.5px */
font-size: calc(22px + 5 * (100vw - 1000px) / 1000);
}
}