前端多端响应式适配方案

什么是响应式布局?

响应式布局指的是同一页面在不同屏幕尺寸下展示不同的页面布局。从这句话可以看出我们如果想要达到这样的目的,那么就必须要能够检测/感知页面屏幕尺寸的变化,在不同的尺寸下修改对应的CSS,以达到响应式的效果。

我们通常有两种方式检测屏幕尺寸的变化:

  1. 通过JS,利用resize事件来监听网页尺寸的变化,然后通过document来获取页面宽度 // 监听屏幕尺寸变化 window.addEventListener("resize", (event) => { console.log("当前屏幕宽度", document.documentElement.clientWidth) })

  2. 第二种是通过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)

可以看到最大规格这一行实现效果不同,这是因为两个设备宽不同,当我们为文字指定固定大小的时候,可能在大屏上正好显示,小屏就会超出,和我们想要达到的效果有所出入。想要解决这个问题,我们主要有两种方案:

  1. rem
  2. 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% = 10pxrem(root em)单位是一种相对单位,它相对于 HTML 元素的字体大小来计算,所以在后续中1rem就等于10px。但是无论如何设置html {font-size},浏览器的默认值是始终存在的,并不会因为项目的设置而变化,这个默认值会被用于:

  • 媒体查询中 em 的计算基准。

  • 当没有定义 html { font-size } 时,remem 的初始基准

所以即使我们在第四行媒体查询中编写了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还给我们提供了两个尺寸单位vwvh,它们两个都是相对于视口而言的,其中一个vw表示视口宽度的百分之一,一个vh表示视高度的百分之一。当屏幕尺寸发生变化时,vwvh也会同步发生变化,这样我们就不需要再通过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);
}

好了以上就是本文所有内容,完结,撒花🎉

相关推荐
一小只因程序猿9 分钟前
《异步编程之美》— 全栈修仙《Java 8 CompletableFuture 对比 ES6 Promise 以及Spring @Async》
前端·javascript·jvm·spring·es6
用户95576606095822 分钟前
**使用RAG与Elasticsearch构建强大的检索增强生成系统**
前端
华子w9089258592 小时前
基于spingbott+html+Thymeleaf的24小时智能服务器监控平台设计与实现
服务器·前端·html
桃园码工2 小时前
2_CSS3 背景 --[CSS3 进阶之路]
javascript·css3·css3 背景
萨克・麦・迪克2 小时前
mac安装java17
前端·macos
熊猫在哪2 小时前
macOS安装nvm
前端·macos·node.js·nvm
AwesomeDevin3 小时前
一种前端硬编码图片扩写方案
前端
放逐者-保持本心,方可放逐3 小时前
css 布局及动画应用(flex+transform+transition+animation)
前端·css·transform·animation·flex·transition·transgorm
卿言卿语3 小时前
第三章:HTML的字符实体,meta标签以及全局属性
前端·html·visual studio code
marshalVS3 小时前
前端学习-事件对象与典型案例(二十六)
前端·javascript·学习