什么是响应式布局?
响应式布局指的是同一页面在不同屏幕尺寸下展示不同的页面布局。从这句话可以看出我们如果想要达到这样的目的,那么就必须要能够检测/感知页面屏幕尺寸的变化,在不同的尺寸下修改对应的CSS,以达到响应式的效果。
我们通常有两种方式检测屏幕尺寸的变化:
-
通过JS,利用resize事件来监听网页尺寸的变化,然后通过document来获取页面宽度 // 监听屏幕尺寸变化 window.addEventListener("resize", (event) => { console.log("当前屏幕宽度", document.documentElement.clientWidth) })
-
第二种是通过CSS来实现,通过@media媒体查询绑定该设备下的CSS样式,当且仅当该媒体查询与正在使用其内容的设备匹配时,该CSS块才能应用于该文档。例如: div.container { background-color: skyblue } // 设备宽度大于640px @media screen and (min-width: 640px) { div.container { background-color: blue } } 上面这段代码给了div一个默认背景色为天蓝色,默认应用在宽度小于640px设备中。然后当设备宽达到或者超过640px时更改背景颜色为蓝色。这种先从移动端开始布局的适配方法被称为是移动优先方案。
移动端优先已经成为一种流行的设计方法,特别是随着移动设备的普及和移动互联网的快速发展。然而,选择哪种方法应该基于项目具体情况。在某些情况下,桌面端优先可能更合适。重要的是要确保你的网页在所有设备上都能提供良好的用户体验
移动端优先
对于移动设备而言,不同的设备分辨率上会有较大的差异。下面是同样一段代码,在IPhone 6和IPhone 6 Plus上的实现效果图:
(IPhone 6)
(IPhone 6 Plus)
可以看到最大规格这一行实现效果不同,这是因为两个设备宽不同,当我们为文字指定固定大小的时候,可能在大屏上正好显示,小屏就会超出,和我们想要达到的效果有所出入。想要解决这个问题,我们主要有两种方案:
- rem
- viewport
rem适配
rem(root em)单位是一种相对单位,它相对于 HTML 元素的字体大小来计算。如果我们使用rem
作为文字大小单位,同时html根标签fontSize
可以根据屏幕的大小自动发生变化,那么就可以在大屏幕上显示大文字,小屏幕上显示小文字了。例如:
xml
<style>
div {
font-size: 0.4rem
}
</style>
// ....
<script>
const MAX_FONT_SIZE = 42;
document.addEventListener('DOMContentLoaded', () => {
const html = document.querySelector('html')
let fontSize = window.innerWidth / 10 * window.devicePixelRatio
fontSize = fontSize > MAX_FONT_SIZE ? MAX_FONT_SIZE : fontSize
html.style.fontSize = fontSize + 'px'
})
</script>
通过这种方案元素/布局可以实时响应窗口大小的变化,字体大小可以根据屏幕宽度连续变化,提供更平滑的响应式体验
如果我们对 设备宽度适配 有明确的预设目标,且希望通过 CSS 来优化不同屏幕尺寸下的字体显示,也可以通过下面这种方式(不过这种方式灵活性没有上面好,对于某个区间的例如处于75em和56.25em之间,即使屏幕发生变化了,字体大小也只是按照区间固定的比例变化,无法进行细粒度的动态调整,适合一些简单的响应式设计):
css
html {
font-size: 62.5%;
}
@media only screen and (max-width: 75em) {
html {
font-size: 56.25%;
}
}
@media only screen and (max-width: 56.25em) {
html {
font-size: 50%;
}
}
@media only screen and (min-width: 112.5em) {
html {
font-size: 75%;
}
}
浏览器默认的字体大小通常是16px,这是不变的,我们一开始基于浏览器的默认值16px来计算字体大小16px * 62.5% = 10px
。rem
(root em)单位是一种相对单位,它相对于 HTML 元素的字体大小来计算,所以在后续中1rem
就等于10px
。但是无论如何设置html {font-size}
,浏览器的默认值是始终存在的,并不会因为项目的设置而变化,这个默认值会被用于:
-
媒体查询中
em
的计算基准。 -
当没有定义
html { font-size }
时,rem
和em
的初始基准
所以即使我们在第四行媒体查询中编写了max-width: 75em
,也不是根据10px
计算,而是根据16px
默认值去计算的。有人会问那项目中的em
也是根据浏览器默认的16px
计算,那还谈什么响应变动啊,根本就固定了啊。并不是这样,项目中 CSS 的 em
基于其父元素的 font-size
,而全局基准通常是 html { font-size }
的设置。
注:如果一个元素的直接父元素没有设置 font-size
,CSS 会遵循"向上查找"的规则,直到找到一个设置了 font-size
的祖先元素,或者最终使用浏览器的默认值(通常为 16px
)
还有人有疑问,我为什么非要使用em
而不是px
呢?我们上面说了em
依赖浏览器默认字体大小,px
是绝对单位,始终与屏幕的物理像素直接对应。而用户可以在浏览器直接修改浏览器默认的字体大小,如果我们依据px
那么效果呈现图可能过大或者过小不符合我们的预期,而em
会进行动态适配。
viewport适配
当我们期望样式问题,最好可以直接通过css解决时还可以使用viewport
。
viewport
是视口 的意思,它表示浏览器的可视区域,也就是浏览器中用来显示网页的那部分区域。 我们可以通过meta标签来指定viewport
ini
<meta name="viewport" content="width=device-width,initial-scale=1.0">
css还给我们提供了两个尺寸单位vw
和vh
,它们两个都是相对于视口而言的,其中一个vw
表示视口宽度的百分之一,一个vh
表示视高度的百分之一。当屏幕尺寸发生变化时,vw
和vh
也会同步发生变化,这样我们就不需要再通过js来控制了,而是可以直接通过vw
单位来指定元素的fontsize
,这样同样可以达到我们想要的效果
css
div {
font-size: 4vw
}
异形屏
现在的手机屏幕不一致,刘海屏、凹槽屏和全面屏等等,我们对于一些非常规屏称为异形屏。
我们在编写代码时元素可能会出现与曲面屏边缘/手机底部黑条/顶部刘海条/...重叠的情况,那样十分不美观且用户体验较差,所以我们应该把这块区域空出来,那么这块区域具体应该是多少呢? 想要知道这个我们需要先了解一个概念:安全区域
安全区域
安全区域指的是一个可视窗口范围,处于安全区域的内容不受圆角、齐刘海、小黑条的影响。图示如下:
我们进行布局时,应该仅在安全区域中进行布局。想要完成这样的功能,我们需要借助:
- 一个
viewport
属性 - 四个距离变量
- 两个
CSS
函数
viewport属性
我们需要为viewport
添加viewport-fit
属性,这个属性用于定义内容如何适应不同形状的屏幕。 有三个值:
- contain:可视窗口完全包含网页内容
- conver:网页内容完全覆盖可视窗口
- auto:默认值,跟contain表现一致
ini
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover">
viewport-fit=cover
主要用于 iPhone X 及其以后的设备,确保页面内容完全覆盖屏幕,即使设备有刘海或圆角。需要注意的是,viewport-fit=cover
主要对 iOS 设备有效,是专门为了适配 iPhoneX 及类似设备(如刘海屏设备)而诞生的,安卓设备可能不会有这种效果
四个距离变量
-
safe-area-inset-left
:设备屏幕左侧的安全区域边距。 -
safe-area-inset-right
:设备屏幕右侧的安全区域边距。 -
safe-area-inset-top
:设备屏幕顶部的安全区域边距。 -
safe-area-inset-bottom
:设备屏幕底部的安全区域边距
两个CSS函数
我们使用两个CSS函数配合这四个变量来使用:
- constant(safe-area-inset-); / 兼容 iOS<11.2 */
- env(safe-area-inset-top); /* 标准语法 */
然后我们通过在 CSS 中设置这些值,以确保内容不会进入安全区域。例如:
css
div {
position: fixed;
top: constant(safe-area-inset-top);
top: env(safe-area-inset-top);
left: env(safe-area-inset-left);
right: env(safe-area-inset-right);
bottom: env(safe-area-inset-bottom);
}
好了以上就是本文所有内容,完结,撒花🎉