移动端rem布局
前端很流行的布局方式rem布局,通过设备之间px像素与rem的转换,达到不同屏幕相同视觉效果的布局方式,在了解rem布局之前需要先明白几个概念,设备像素(物理像素)、独立像素、CSS像素。
设备像素(物理像素)
屏幕设备真实的像素点,一张图片就是由一个个像素点构成,屏幕也是有一个个像素点构成,一个iPhone6的设备像素是750*1334,屏幕制造商制作行内标准制定,属于物理范畴,不能修改。
独立像素(逻辑像素)
逻辑像素,操作系统规约定义的一种长度单位。规定一个独立像素等于两个物理像素,那么iPhone6的设备的独立像素是 375 * 667像素,主流操作系统产商按标准规定,属于协议规约范畴。
CSS像素
网页制作中CSS样式语言中定义的长度单位,如今(iPhone4开始)CSS中1px就是1CSS像素等于1独立像素,属于语言协会制定标准。
devicePixelRatio设备像素比
js中也引入了设备devicePixeRito像素比的概念,描述物理像素与独立像素之比(物理像素/独立像素),可以在BOM对象(window)中查看,使用window.devicePixelRatio
进行查看。
resolution
媒体查询中的resolution变量就是指window.devicePixelRatio
@media (min-resolution: 2dppx) {
}
场景理解
远古时代(iPhone3物理像素:320*480),当时1CSS像素=1物理像素。假设我们就学会了编程且是前端,设计网页是按照iPhone3尺寸来进行设计,为了我们的网页能够占满屏幕,我们在CSS样式中设定width: 320px,当时是刚好占满屏幕。可是苹果公司在iPhone4时推出了Retina 屏幕物理像素变成:640*960,屏幕尺寸没有变化。原本设置的网页在iPhone4中就占一半,巨丑!所以新时代救星来了,独立像素的到来,1CSS=1独立像素=2物理像素,这个时候我们的网页在iPhone3、iPhone4都可以占满屏幕了!因为iPhone4屏幕像素(高清屏幕)看得更加的清楚,同理图片也是如此,像素越多越清晰,但体积越大。
尺寸参考
参考网址链接:https://material.io/resources/devices/,其中dp列为独立像素,px列为物理像素。大家觉得搜集麻烦的话可以去我的资源收录网站:http://n.huasenjio.top/,有很多实用的资源网站!
rem布局实现
理念
rem是CSS中的一个长度单位,html根元素中的font-size的值就是1rem,例如你在写样式的时候为html标签(:root伪类)设置了font-size: 14px,那么1rem就是14px,当你修改html的font-size值时,rem也会发生变化。一句话概括就是为html标签定义font-size值,在写样式的时候用rem代替px。固定大小的标签尽量使用rem,自由伸缩元素使用百分比布局或者flex布局。
1)js
因为视口viewport的出现,head标签中的<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
,获取屏幕实际的真实物理屏幕像素已经很简单了,根据js查询到当前屏幕的px值,通过js动态修改html标签的font-size值,父元素宽高值设置rem,子元素设置相对于父元素的百分比宽高的理念就能简单实现一个rem布局。
// 立即执行函数
function () {
const setHtmlFontSize = () => document.documentElement.style.fontSize = document.documentElement.clientWidth / 100
window.addEventListener('DOMContentLoaded,setHtmlFontSize, false) // 初始的 HTML 文档被完全加载和解析完成调用
window.addEventListener('orientationchange',setHtmlFontSize, false) // 屏幕横竖转换时候调用
} ()
把屏幕分为100份,每一份就是一个1rem,例如你的手机是iPhone6(375px),那么1rem==37.5px,每一个屏幕都是下100rem就会占满一块屏幕。如果我们拿到的设计稿是750的物理像素的iPhone6设计稿,那么独立像素就是370px,我们通过马克鳗量到一个元素是30px,那么我们设置元素的宽度时就别写width: 30px,正确的姿势应该是width: 30/37.5rem,为了避免麻烦我们建议使用sass(css增强语言),定义一个转换sass方法。
@function px2rem($px) {
@return $px / 37.5 + rem; // 使用时width: px2rem(30)
}
2)devicePixelRatio
通过document.documentElement.clientWidth获得文档像素再动态修改html标签的font-size的方式,进而给父元素设置CSS宽高距离等使用rem代替px的理念。大屏幕环境下,元素位置宽高不会发生太大改变,而元素内的子元素例如图片文字等则会变化得很小,类似于百分比布局,导致块大内容不佳的问题。出现了新的方案就是利用到js对象devicePixelRatio,查询到当前屏幕的设备像素比,动态设置htmt的font-size值、viewport的mata标签的initial-scale(缩放比例)。设置初始的1rem=30px,devicePixelRatio==2的屏幕下1rem =30*2,而<meta name="viewport">
的值始终是initial-scale = 1 / dpr
,当initial-scale ==1时是正常显示,显示得相对清楚。
'use strict';
const win = window;
export default win.flex = (normal, baseFontSize, fontscale) => {
const _baseFontSize = baseFontSize || 100;
const _fontscale = fontscale || 1;
const doc = win.document; // 获得到文档对象
const ua = navigator.userAgent; // 获取到客户端信息
const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i); // 进行匹对
const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);
const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
let dpr = win.devicePixelRatio || 1;
if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
// 如果非iOS 非Android4.3以上 非UC内核 dpr设为1 不高清;
dpr = 1;
}
const scale = normal ? 1 : 1 / dpr;
let metaEl = doc.querySelector('meta[name="viewport"]'); // 样式选择器
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
doc.head.appendChild(metaEl);
}
// 设置mata的viewport标签
metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${ scale},maximum-scale=${ scale},minimum-scale=${ scale}`);
doc.documentElement.style.fontSize = normal ? '50px' : `${ _baseFontSize / 2 * dpr * _fontscale}px`;
};
vue项目适配rem布局
rem的原理将物理像素px分为一百份,每一份就是1rem,例如当你的手机是苹果6s,物理像素是375px,那么转化成rem就是37.5px。插件设置html根标签的字体属性font-size变为1rem,通过转换将css中的px转换成对应的rem。当屏幕发生大小缩放的时候,更改html下的font-size的大小,就能实现了其他标签的大小距离也随比例缩放,达到rem自适应布局。
1)安装依赖
npm i lib-flexible postcss-px2rem --save
2)删除index.html中的<meta name=‘viewport’ >视口标签
flexible会为页面根据屏幕自动添加<meta name='viewport' >
标签,动态控制initial-scale,maximum-scale,minimum-scale
等属性的值,不删除会造成重复追加,导致代码冗余等情况。
3) 入口文件main.js文件中引入依赖
import 'lib-flexible'
4)配置vue.config.js文件
module.exports = {
devServer: {
port: 3000,
open: true
},
// rem 的配置
css: {
loaderOptions: {
css: { },
postcss: {
plugins: [
require('postcss-px2rem')({
// 适配375px屏幕 设计图750中量出来的尺寸要 / 2
remUnit: 37.5
})
]
}
}
}
}