移动端适配rem/vw,vh原理(详细)
参考 https://juejin.cn/post/6981800084686143518
了解像素相关知识:
移动端适配
掌握web开发基础系列--物理像素、逻辑像素、css像素
为什么给750px的设计图
其实我一直很想写一些关于适配方面的文章,因为很多东西只有实践才能对这个知识点更加的了解,而不是查几篇文章就行了~
我希望能够解答这些问题:
1.什么是物理像素,和逻辑像素,DPR
2.为什么我们的设计师给的尺寸都是750px
3.rem适配原理以及对应的插件
4.vw,vh适配原理以及对应的插件
1.什么是物理像素,和逻辑像素,DPR
物理像素(physical pixel, 也叫做设备像素):显示器上的像素,机器生产出来时就已经确定了。
逻辑像素(density-independent pixel也叫做css像素/设备独立像素):用于控制元素样式的样式单位像素,CSS像素从来都只是一个相对值。
物理像素(physical pixel)
: 设备屏幕实际拥有的像素点,屏幕的基本单元,是有实体的。比如iPhone 6的屏幕在宽度方向有750个像素点,高度方向有1334个像素点,所有iPhone 6 总共有750*1334个像素点。
逻辑像素/独立像素(density-independent pixel)
: 我们平时描述一张图片宽高时一般用 200px * 100px,这里的px也是逻辑像素。
我们应该知道iphone6的宽度是375px,这里指的是逻辑像素,那就说明1px的css像素里面包含了2个物理像素点,如果你不怕瞎的话,可以将眼睛靠近电脑屏幕,发现屏幕的界面都是根据红、绿、蓝三个颜色组成
以前的的屏幕是假设是375px的物理像素,对应的是375个物理像素点,其实在很久以前,CSS里写个1px,屏幕就给你渲染成1个实际的像素点,DPR=1,多么简单自然~ 后来苹果公司为其产品mac、iPhone以及iPad的屏幕配置了Retina高清屏,也就是说这种屏幕拥有的物理像素点数比非高清屏多4倍甚至更多。如果还按照DPR=1进行展示,那么同一张图片在高清屏上面显示的区域面积会是非高清屏的1/4,这样的话由于图片在屏幕上的展示面积大大缩小,也会导致出现“看不清”的问题。
在1px对应多个物理像素点主要是为了更加高清,也就是越多,对于我们肉眼能看到红、绿、蓝三个色的难度越大. 所以当你使用750px的设计图的时候,对应的图应该是xx2@png
设备像素比(Device Pixel Ratio,DPR)
DPR = 物理像素/逻辑像素
2.rem 适配
2.1 CSS3 长度单位 rem
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
我是根元素html的大小
<div class="two">我是两倍</div>
<div class="three">我是三倍</div>
<style> html{
font-size:12px;
}
.two {
font-size:2rem;
height: 5rem;
width: 5rem;
background-color: red;
}
.three{
font-size:3rem;
height: 10rem;
width: 10rem;
background-color: yellow;
} </style>
</head>
</html>
复制代码
比如上面这个例子,虽然我只设置了font-size:12px;,并没有去设置width是多少,但是rem就是看html的font-size的值为固定值,在这个基础上去乘以对应的倍数,其实我这块我以前老是转不过弯,为啥这么多属性就只设置一个font-size的默认值就行,主要还是看rem初始的定义,也许这个属性不是font-size,也许是test等等,他规定什么属性就是什么属性,我是这么理解的,但是font-size的默认值和最小值值得注意
font-size:2rem; => font-size:2*12px;
那么,思考一下,这个html的font-size的值我到底设置多少呢?是不是应该根据视觉宽度来设定
2.2 浏览器默认字体大小
浏览器默认最小字体12px, 意思就是我设置一个字体为2px,这个2px,是不会起作用的,会显示城最小的字体12px 默认的字体大小是16px,意思就是假设我不会html做任何设置,对其他的样式class设置2rem,那么显示出来的样式应该是32px(16px * 2)
如何获取google浏览器的默认font-size
var div=document.getElementsByTagName('html')[0]
const res = window.getComputedStyle(div).fontSize // 16px
console.log(res, 1111)
复制代码
2.3 rem适配
假设我们的UI图给的尺寸是375px的逻辑像素
.two {
font-size:2rem;
height: 5rem;
width: 5rem;
background-color: red;
}
.three{
font-size:3rem;
height: 10rem;
width: 10rem;
background-color: yellow;
}
复制代码
获取原始值,html的默认font-size为16,意思就是在iphone6下面
375px的UI设计图之下,量出来的应该为:
2rem = 32px 5rem = 80px 3rem = 48px 10rem = 160px
750px的UI设计图,量出来的应该为:
2rem = 64px 5rem = 160px 3rem = 96px 10rem = 320px
复制代码
适配代码分析
innerWidth 浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏)
innerHeight 浏览器窗口可视区高度(不包括浏览器控制台、菜单栏、工具栏)
//原理:
// 获取屏幕的宽度,然后将屏幕分为多少份(设计稿宽度那么多份)
const boxInnerWidth = window.innerWidth
// 假设设计稿为375px
const UIwidth = 375
// 每份分成多少px
const everyPiece = boxInnerWidth/UIwidth
// 将html的font-size设置为比例值
document.documentElement.style.fontSize = `${everyPiece * 100}px`
复制代码
改成以下也可以:
(function () {
function changeRootFont() {
var UIwidth = 750, rem2px = 100;
document.documentElement.style.fontsize =
((window.innerWidth / UIwidth) * rem2px) + 'px';
}
changeRootFont();
window.addEventListener('resize', changeRootFont,false);
})();
复制代码
按道理来说,document.documentElement.style.fontSize = ${everyPiece}px
就行了呀, 为什么要*100,假设我们在iphone6手机里,那么const everyPiece = boxInnerWidth/UIwidth的everyPiece会等于1px,html的font-size设置为1是不会生效的,所以我们需要将font-size扩大到12倍以上,但是你想这里我扩大了,等我写rem倍数的时候,是不是要除以这个对应的扩大倍数,所以为了好除,我们直接写100,也就是我们量出来的ui里面的px数往右边移动两个小数点就好了
.two {
font-size:0.32rem;
height: 0.8rem;
width: 0.8rem;
background-color: red;
}
.three{
font-size:0.48rem;
height: 1.6rem;
width: 1.6rem;
background-color: yellow;
}
复制代码
3.vw,vh适配
100vw = 一个视口的宽度
1vw = 1%视口的宽度
100vh = 一个视口的高度
1vh= 1%视口的高度
复制代码
<div class="test">
哈哈哈哈
</div>
复制代码
.test {
width: calc(100vw * (300 / 375));
height: 100px;
background-color: red;
color: white;
font-size: calc(100vw * (24 / 375)) ;
}
复制代码
假设你在项目中,可以使用sass
@function px2vw($px) {
@return $px * 100vw / 375; // 375的设计图
}
.test {
width: px2vw(300);
height: px2vw(100);
background-color: red;
color: white;
font-size: px2vw(24);
}
复制代码
原理:
因为vw是将屏幕分成100份,1vw表示其中的一份,100vw表示的是横向满屏,那么假设我的设计图是375px,目前量的宽是24px,那么 24/375表示是我占屏幕总宽度的24/375,这时候你又知道 屏幕总宽度为100vw, 那么动态的宽度为24/375*100vw,而24的尺寸不一,所以封装一个方法来调用
VW,rem的优缺点:
rem:
1.因为是根据html根元素来做其他元素的rem处理的,所以script的代码应该在定义其他元素css之前,必须写在header里面,在触发resize的时候还要再获取window.innerWidth
2.如果是设置的${everyPiece * 100}px
这里的比例值不是100,px转成rem会很难算
vw:
1.vw单位兼容性比rem稍差,ios8、安卓4.4及以上才完全支持
2.假设上面这样使用一个方法,写法上看起来我觉得有点怪怪的,没有rem那么直接
所以有了结合版本:(大佬说他就是用的这个,没有任何问题)
html{
font-size:calc(100vw/375*100)
}
.test {
width: 3rem ;
height: 1rem;
background-color: red;
color: white;
font-size: 0.24rem
}
复制代码
4.插件推荐(VUE.JS)
rem (fexible.js,2年前的项目用过)
参考:
fexible的使用
vue项目中使用lib-flexible解决移动端适配的问题
vw (postcss-px-to-viewport,目前在用)
参考(大家可以找个简单的文章看看哈,其实就是个插件):
如何在Vue项目中使用vw实现移动端适配
5.为什么设计师出750px的设计图
参考:
为什么设计稿是750px
看了很多的文章,大概的意思就是设计图是按照物理像素给的图,这块我也没有说彻底弄懂,哭
6.如果有手机端和pc端如何进行适配
const isMobile = function () {
const userAgentInfo = navigator.userAgent
let mobileAgents = [
'Android',
'iPhone',
'SymbianOS',
'Windows Phone',
'iPad',
'iPod',
]
return mobileAgents.some(i => userAgentInfo.includes(i))
}
复制代码
设置全局的isMobileFunc是否为手机端的判断,路由指向同一个页面,这个页面引入pc端的代码,以及mobile的代码,根据isMobile判断显示哪个子组件
适配: var UIwidth = isMobile ? 750 : pcUIWidth, rem2px = 100;
(function () {
function changeRootFont() {
var UIwidth = isMobile ? 750 : pcUIWidth, rem2px = 100;
document.documentElement.style.fontsize =
((window.innerWidth / UIwidth) * rem2px) + 'px';
}
changeRootFont();
window.addEventListener('resize', changeRootFont,false);
})();
复制代码
BTY,关于rem,vw适配更多的优缺点,欢迎评论,后续会将fexible.js和postcss-px-to-viewport的插件使用贴出来
-_-奥利给