移动端适配以及多屏幕自适应方案

2023-09-18 05:00:15


前言

本文主要记录适配移动端以及多屏幕的解决办法,还有postcss转换插件的编写。


一、移动端适配问题

在MDN中提到:

在移动设备和其他窄屏设备中,某些内容在比普通屏幕更宽的虚拟窗口或视口中渲染页面,然后缩小渲染的结果,以便可以一次看到所有内容。然后,用户可以通过平移和缩放以查看页面的不同区域。例如,如果移动屏幕的宽度为 640px,则页面可能会使用 980px 的虚拟视口渲染,然后页面将缩小以适应 640px 的空间。

横向滚动条

换成通俗易懂的话就是说,为了适配窄屏,他会把渲染视口以短边进行截断,然后就出现了横向滚动条,让用户能够左右滑动来查看完整的页面,但是这样做对移动端有很大的问题,左右滑动对移动端的用户体验大打折扣。
所以需要某种机制或者方法来适配移动端。
以下是最为常见的移动端适配方案。


二、meta-viewport标记

meta标签写在<head>标签中

<head>
    <meta charset="UTF-8">
<!--    移动端适配-->
    <meta name="viewport" content="with=device-width,initial-scale=1.0">
    <title>Title</title>
</head>

其中有很多选项用来调整视口与屏幕的关系

  • width
    控制视口的大小。这可以设置为特定像素数(如’width=600’),也可以设置为特殊值device-width,即 100vw,100% 的视口宽度。最小值为 1。最大值为 10000。负值会被忽略。

  • height
    控制视口的大小。这可以设置为特定像素数(如 width=600),也可以设置为特殊值 device-height,即 100vh,100% 的视口高度。最小值为 1。最大值为 10000。负值会被忽略。

  • initial-scale
    控制页面首次加载时显示的缩放倍数。最小值是 0.1。最大值是 10。默认值为 1。负值会被忽略。

  • minimum-scale
    控制页面允许缩小的倍数。最小值是 0.1。最大值是 10。默认值为 1。负值会被忽略。

  • maximum-scale
    控制页面允许放大的倍数。设置一个低于 3 的值将不具备无障碍访问性。最小值是 0.1。最大值是 10。默认值为 1。负值会被忽略。

  • user-scalable
    控制是否允许页面上的放大和缩小操作。有效值为 0、1、yes 或 no。默认值为 1,与 yes 相同。将值设置为 0(即与 no 相同)将违反 Web 内容无障碍指南(WCAG)。

  • interactive-widget
    指定交互式 UI 组件(如虚拟键盘)对页面视口的影响。有效值:resizes-visual、resizes-content 或 overlays-content。默认值:resizes-visual。

  • viewport-fit
    设置为 cover 可以解决 刘海屏 的留白问题

最终完整的meta标签可以写成:

<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">

在创建vue项目时,他会在index.html中自动加入这个标签。

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue + TS</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

优点:

  • 不需要考虑一些屏幕计算问题,直接使用设计稿中的数值就可以

缺点:

  • 存在兼容问题,部分安卓机识别不了完整的meta属性
  • 使整个页面都进行了适配,导致某些不用适配的也参与了适配
  • 图片会失真

三、rem字体适配

rem是个长度单位,表示相对根元素的字体大小,例如根元素为14px,那么1rem表示14px,2rem表示28px。
利用JS控制根元素的字体大小就可以控制整个页面的字体大小的适配
首先是需要获取当前视口宽,利用宽动态调整根元素字体大小document.documentElement.clientWidth
利用window.onresize监听当前窗口变化

其中关键点是以下的两个点:

  • 计算对应宽度的根元素字体大小

    这个一般设计稿会给,设计稿都是固定某个宽,上边对应的字体大小就是这个宽对应的字体大小,就比如设计稿给我们一个宽375px,字体28px的设计稿,那么其他宽度对应的字体大小就是:其他宽度 × 28 ÷ 750

  • 计算子元素字体与根元素对应关系
    这个也是根据设计稿计算个比例就可以了,例如一个根元素是28px,子元素是14px,那么转换成rem就是:14 ÷ 28 = 0.5 rem
    这个也有一些插件可以实现将px自动转换成rem,如postcss-pxtorem,参考文章:px自动转rem

<style>
  .box{
    font-size: 3rem;
  }
  #text{
      font-size: 0.5rem;
  }
</style>
<body>
<div class="box">
  smz
</div>
<div id="text"></div>
</body>
<script>
  function adapter() {
    const text = document.querySelector('#text')
    //获取布局视口宽度,布局视口=设备横向独立像素值
    const dpWidth = document.documentElement.clientWidth
    //计算根字体大小
    const rootFonstSize = (dpWidth * 28)/375
    //设置根字体大小
    document.documentElement.style.fontSize = rootFonstSize + 'px'
    text.innerText = `当前根元素字体大小:${document.documentElement.style.fontSize}`
  }
  adapter()
  // 监听窗口变化
  window.onresize = adapter
</script>

rem


四、vw和vh

vw和vh也是长度单位,他与传统的以像素为单位不同,他是以视口百分比为单位
对于百分比布局有一定的区别,百分比是相对于父元素,尔vw和vh是相对于视口的

  • 1vw:表示视口宽度的百分之1
  • 1vh:表示视口高度的百分之1

也就是说100vw和100vh表示整个视口

使用vw和vh就不用再使用JS控制了
同样,使用此单位也需要计算设计稿中px与视口比例关系:对应像素长度 × 100vw ÷ 设计稿屏幕像素宽

less文件:

body{
  @basic:375/100vw;
  .box{
    width: 300/@basic;
    height: 150/@basic;
    background: red;
    margin: auto;
  }
}

vw


五、postcss转换插件

在vite开发的项目中集成了postcss,可以利用postcss编写一个全局转换的的一个方法,可以快速将px转换成vw,或者对某些可以做到不转换。

  • 在项目目录下新建plugins目录用来存放插件

  • 在tsconfig.node.json下添加配置项
    tsconfig.node.json

  • 在plugins目录下新建ts文件编写插件

import {Plugin} from "postcss";
// 默认宽度
const Options = {
    viewportWidth: 375 //UI设计稿宽度
}
interface Options {
    viewportWidth?:number
}
export const PostcssPxToViewport = (options:Options = Options):Plugin =>{
    const opt = Object.assign({},Options,options)// 将Options,options复制到同一对象中
    return {
        postcssPlugin : "postcss-px-to-viewport",// 名称
        //钩子函数 取css结点
        Declaration(cssNode){
            // 这里可以改名字‘smz’ 改成需要转换的,比如‘smz’ 就只针对 单位为'smz'的css结点进行转换
            if (cssNode.value.includes('smz')){// cssNode.value.includes('px')对含有px单位的css结点,可更改
                const num = parseFloat(cssNode.value)// 转换成数字去掉px
                cssNode.value =  `${(( num / opt.viewportWidth) * 100).toFixed(2)}vw` // 计算公式
            }
        }
    }
}
  • 在vite.config.ts引入注册插件

引入插件

使用:

<template>
<div class="box">
  postcss转换插件
</div>
  <div class="box2">
    普通未转换
  </div>
</template>

<style scoped>
.box{
  width: 200smz;
  height: 100smz;
  font-size: 20smz;
  border: 3px solid red;
}
.box2{
   width: 200px;
   height: 100px;
   font-size: 20px;
  border: 3px solid yellow;
 }
</style>

postcss转换插件

总结

以上三种方案,是相互搭配进行移动端的适配的。

更多推荐

基于GBDT+Tkinter+穷举法按排队时间预测最优路径的智能导航推荐系统——机器学习算法应用(含Python工程源码)+数据集(三)

目录前言总体设计系统整体结构图系统流程图运行环境Python环境Pycharm环境Scikit-learnt模块实现1.数据预处理2.客流预测3.百度地图API调用4.GUI界面设计1)手绘地图导入2)下拉菜单设计3)复选框设计4)最短路径结果输出界面设计5)智能推荐结果输出设计6)界面展示5.路径规划6.智能推荐相关

【C++】内联函数 ③ ( C++ 编译器 不一定允许内联函数的内联请求 | 内联函数的优缺点 | 内联函数 与 宏代码片段对比 )

文章目录一、内联函数不一定成功1、内联函数的优缺点2、C++编译器不一定允许内联函数的内联请求3、是否内联决定权在编译器手中二、内联函数与宏代码片段对比1、内联函数2、宏代码片段一、内联函数不一定成功1、内联函数的优缺点"内联函数"不是在运行时调用的,"内联函数"是编译时将函数体对应的CPU指令直接嵌入到调用该函数的地

【表格插入小计行】el-table表格,数组对象中根据某字段插入小计行计算数据

前言功能解释:遇到的一个需求,是表格的tabledata数组。里面有科室医生还有很多消费指标等数据。然后需要我排序后把科室放在一起。然后在每个科室下面添加一行数据,是小计行。用于计算上面相同科室的所有数据汇总。然后最下面再来个合计行,加上所有的小计。效果图刚排序后是这样的表格样子,数据是我模拟的然后插入小计行后是这样的

JavaScript事件流:深入理解事件处理和传播机制

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录引言1.事件流的发展流程1.1传统的DOM0级事件1.2DOM2级事件和addEventListener方法1.3W3CDOM3级事件1.4React与VirtualDOM2.事件流的属性2.1事件捕获阶段2.

《从菜鸟到大师之路 Redis 篇》

《从菜鸟到大师之路Redis篇》(一):Redis基础理论与安装配置Nosql数据库介绍是一种非关系型数据库服务,它能解决常规数据库的并发能力,比如传统的数据库的IO与性能的瓶颈,同样它是关系型数据库的一个补充,有着比较好的高效率与高性能。专注于key-value查询的redis、memcached、ttserver。

transformer大语言模型(LLM)部署方案整理

说明大模型的基本特征就是大,单机单卡部署会很慢,甚至显存不够用。毕竟不是谁都有H100/A100,能有个3090就不错了。目前已经有不少框架支持了大模型的分布式部署,可以并行的提高推理速度。不光可以单机多卡,还可以多机多卡。我自己没啥使用经验,简单罗列下给自己备查。不足之处,欢迎在评论区指出。框架名称出品方开源地址Fa

JWT 令牌撤销:中心化控制与分布式Kafka处理

【squids.cn】全网zui低价RDS,免费的迁移工具DBMotion、数据库备份工具DBTwin、SQL开发工具等令牌对于安全数字访问至关重要,但如果您需要撤销它们怎么办?尽管我们尽了最大努力,但有时代币可能会被泄露。这可能是由于编码错误、意外记录、零日漏洞和其他因素造成的。令牌撤销是现代安全性的一个重要方面,确

并发编程——synchronized

文章目录原子性、有序性、可见性原子性有序性可见性synchronized使用synchronized锁升级synchronized-ObjectMonitor原子性、有序性、可见性原子性数据库事务的原子性:是一个最小的执行的单位,一次事务的多次操作要么都成功,要么都失败。并发编程的原子性:一个或多个指令在CPU执行过程

【无公网IP内网穿透】 搭建Emby媒体库服务器并远程访问「家庭私人影院」

目录1.前言2.Emby网站搭建2.1.Emby下载和安装2.2Emby网页测试3.本地网页发布3.1注册并安装cpolar内网穿透3.2Cpolar云端设置3.3Cpolar内网穿透本地设置4.公网访问测试5.结语1.前言在现代五花八门的网络应用场景中,观看视频绝对是主力应用场景之一,加上移动网络技术的发展,随时随地

vue3.2+ts封装axios

1.创建utils文件夹/server下面创建index.ts,代码如下:importaxios,{AxiosRequestConfig}from"axios";import{BASE_URL,TIMEOUT}from"@/config/axios";/***@说明接口请求返回信息(按照自己的实际情况分配基础请求格式)

解决WSL2占用内存过多问题(Docker on WSL2: VmmemWSL)

解决WSL2占用内存过多问题(DockeronWSL2:VmmemWSL)一、问题描述二、问题解决2.1创建`.wslconfig`文件2.2重启wsl2一、问题描述安装完WSL2后,又安装了Docker,使用了一段时间,发现电脑变卡,进一步查看,发现CPU和内存占用过大,如下图:docker仅仅运行了mysql和zk

热文推荐