前端很流行的布局方式rem布局,通过设备之间px像素与rem的转换,达到不同屏幕相同视觉效果的布局方式,在了解rem布局之前需要先明白几个概念,设备像素(物理像素)、独立像素、CSS像素。
屏幕设备真实的像素点,一张图片就是由一个个像素点构成,屏幕也是有一个个像素点构成,一个iPhone6的设备像素是750*1334,屏幕制造商制作行内标准制定,属于物理范畴,不能修改。
逻辑像素,操作系统规约定义的一种长度单位。规定一个独立像素等于两个物理像素,那么iPhone6的设备的独立像素是 375 * 667像素,主流操作系统产商按标准规定,属于协议规约范畴。
网页制作中CSS样式语言中定义的长度单位,如今(iPhone4开始)CSS中1px就是1CSS像素等于1独立像素,属于语言协会制定标准。
js中也引入了设备devicePixeRito像素比的概念,描述物理像素与独立像素之比(物理像素/独立像素),可以在BOM对象(window)中查看,使用window.devicePixelRatio进行查看。
媒体查询中的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是CSS中的一个长度单位,html根元素中的font-size的值就是1rem,例如你在写样式的时候为html标签(:root伪类)设置了font-size: 14px,那么1rem就是14px,当你修改html的font-size值时,rem也会发生变化。一句话概括就是为html标签定义font-size值,在写样式的时候用rem代替px。固定大小的标签尽量使用rem,自由伸缩元素使用百分比布局或者flex布局。
因为视口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) }通过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'; /** * 不用自己添加mata的viewport标签 * @param {Boolean} [normal = false] - 是否正常显示; * @param {Number} [baseFontSize = 100] - 初始字体大小100px; * @param {Number} [fontscale = 1] - 字体缩放比例; */ 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`; };rem的原理将物理像素px分为一百份,每一份就是1rem,例如当你的手机是苹果6s,物理像素是375px,那么转化成rem就是37.5px。插件设置html根标签的字体属性font-size变为1rem,通过转换将css中的px转换成对应的rem。当屏幕发生大小缩放的时候,更改html下的font-size的大小,就能实现了其他标签的大小距离也随比例缩放,达到rem自适应布局。
flexible会为页面根据屏幕自动添加<meta name='viewport' >标签,动态控制initial-scale,maximum-scale,minimum-scale等属性的值,不删除会造成重复追加,导致代码冗余等情况。