You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
注: 此处只针对于 Android, windows 也有 DIP 概念, 含义不同, IOS 貌似不存在
设备像素比 (Device Pixel Ratio (DPR))
Device pixel ratio, the ratio between physical pixels and logical pixels used by cascading style sheets (CSS): other names for it are “CSS Pixel Ratio” and “dppx” 表示 1 个 CSS 像素(宽度)等于几个物理像素(宽度)
一个相对长度单位。作用于根元素,相对于初始值 / 默认值大小;作用域非根元素,相对于根元素 html 字体大小(常用)
em
Font size of the parent, in the case of typographical properties like font-size, and font size of the element itself, in the case of other properties like width.
作用于 font-size 属性,相对于父元素字体大小(常用);作用于非 font-size 属性,相对于自身字体大小
;(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {});
if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
var content = flexibleEl.getAttribute('content');
if (content) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
dpr = parseFloat(initialDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
function refreshRem(){
// 动态设置的缩放大小会影响布局视口的尺寸, 设备物理像素大小
// 设备逻辑像素 device-width = 设备物理像素 /(devicePixelRatio * scale)
var width = docEl.getBoundingClientRect().width; // iphone6 => 750
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === 'complete') {
doc.body.style.fontSize = 12 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
doc.body.style.fontSize = 12 * dpr + 'px';
}, false);
}
refreshRem();
flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
}
布局
相关概念
设备像素(Device Pixels)
设备屏幕的物理像素,表示屏幕上可以铺多少个点点,而不是一个绝对长度单位(例如 in,mm); 单位是 px,比如 iPhone6 的 (750 x 1334px)
分辨率(Resolution)
一个物理概念
对于屏幕,分辨率一般表示屏幕上显示的物理像素总和。比如,我们说 iPhone6 屏幕分辨率是 (750 x 1334px)
对于图像,概念等同于图像尺寸、图像大小、像素尺寸等等。比如,我们说 (20 x 20px) 的 icon
CSS 像素(CSS Pixels)
是 Web 编程的概念,指的是 CSS 样式代码中使用的逻辑像素, 或者称为
设备独立像素
, 因为只与设备相关;1 个 CSS 像素在不同设备上可能对应不同的物理像素数,这个比值是设备的属性(Device Pixel Ratio,设备像素比),比如,iPhone6:375 x 667px
通过
document.documentElement.clientWidth/clientHeight / document.documentElement.getBoundingClientRect().width
获取在 CSS 规范中,长度单位可以分为绝对单位和相对单位。px 是一个相对单位,相对的是设备像素(Device Pixels)
设备独立像素 (device-independent pixels (DIP) / Density-independent Pixels (DP))
Android 设备的特点是屏幕尺寸很多,因此为了显示能尽量和设备无关,提出了 dip,参照的 density 是 160。
注: 此处只针对于 Android, windows 也有 DIP 概念, 含义不同, IOS 貌似不存在
设备像素比 (Device Pixel Ratio (DPR))
像素密度
像素密度也叫显示密度或者屏幕密度,缩写为 DPI(Dots Per Inch) 或者 PPI(Pixel Per Inch)
视口(viewport)
桌面上视口宽度等于浏览器宽度,但在手机上有所不同。
布局视口 (layout viewport)
手机上为了容纳为桌面浏览器设计的网站,默认布局视口宽度远大于屏幕宽度,为了让用户看到网站全貌,它会缩小网站 document.documentElement.clientWidth
视觉视口 (Visual viewport)
屏幕的可视区域,即物理像素尺寸, 可变, 与当前缩放值和设备的屏幕宽度有关
visual viewport 宽度 = ideal viewport 宽度 / 当前缩放值
可以通过window.innerWidth
来获取,但在 Android 2, Oprea mini 和 UC 8 中无法正确获取。理想视口 (ideal viewport)
ideal viewport 是最适合移动设备的 viewport,ideal viewport 的宽度等于移动设备的屏幕宽度 在移动开发时, 在 meta[name='viewport']中, 通过
width = device-width
把当前的 viewport 宽度设置为理想视口, 否则宽度将默认为布局视口 980ideal viewport 并没有一个固定的尺寸,不同的设备拥有有不同的 ideal viewport。早期所有 iPhone 理想视口为 320x480px
所以,在没有缩放的情况下,屏幕的 CSS 像素宽度其实是指理想视口的宽度,而 meta 标签:
指定了布局视口 = 理想视口,并且禁止缩放。所以添上 width=device-width 的 viewport meta 后页面变大了(一开始页面内容小得看不清),实际上是布局视口变小了
initial-scale=1 解决了 iphone、ipad 无论横竖屏都把宽度设为竖屏时 ideal viewport 的宽度 width=device-width 解决了 IE 无论横竖屏都把宽度设为竖屏时 ideal viewport 的宽度
视觉视口与理想视口关系:
参考: www.ayqy.net/blog / 完全理解 px… github.com/jawil/blog/…
rem (Font size of the root element)
一个相对长度单位。作用于根元素,相对于初始值 / 默认值大小;作用域非根元素,相对于根元素 html 字体大小(常用)
em
Font size of the parent, in the case of typographical properties like font-size, and font size of the element itself, in the case of other properties like width.
作用于 font-size 属性,相对于父元素字体大小(常用);作用于非 font-size 属性,相对于自身字体大小
布局方案
百分比 + 媒体查询
媒体查询 前提:
<meta name="viewport" content="width=device-width"/>
mate 中的device-width / width
:可理解为,把布局视口设置为理想视口
最常见的方式,通过屏幕宽度(用 CSS 像素描述的宽度)来区分各种设备,如下:
rem 布局
rem: 根元素 (html) 的字体大小. 即 1rem = html 中设置的 font-size
获取设备宽度
document.documentElement.getBoundingClientRect().width / document.documentElement.clientWidth
原理: 实质时比例问题, 根据设计图比例计算出固定 rem 值 实现: 主要通过修改 html 的 fontSize
直接引入 [www.jianshu.com/p/b00cd3506…]
(function (doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
if(clientWidth>=640){
docEl.style.fontSize = '100px';
}else{
docEl.style.fontSize = 100 * (clientWidth / 640) + 'px'; // 640: 可根据设计图来定
}
};
复制代码
使用 flexible.js
github.com/amfe/lib-fl…
缺点:
iframe 问题
富文本问题
高清方案
部分 android 机型不兼容
系统字体缩放时, 发生变化, 导致页面错乱,因为和根元素字体紧密联系;解决方案: 缩放还原
1> juejin.im/post/59f678…
2> 基于 flexible.js 添加以下代码: juejin.im/post/5b9cb9…
var root = window.document.documentElement;
var fontSize = parseFloat(root.style.fontSize);
// html最终的font-size大小
var finalFontSize = parseFloat(window.getComputedStyle(root).getPropertyValue("font-size"));
if(finalFontSize !== fontSize) {
root.style.fontSize = fontSize * fontSize / finalFontSize + "px";
}
复制代码
lib-flexible
旧版本
旧版本 #17 代码
处理过程如下:
先取 dpr (dpr = window.devicePixelRatio)
再设置 scale = 1/dpr
然后就有 innerWidth 了, innerWidth = 375 / scale = 750px (device-width = document.documentElement.clientWidth)
最后将 innerWidth 分成 10rem, font-size = innerWidth / 10 = 75px
;(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {});
})(window, window['lib'] || (window['lib'] = {}));
复制代码
新版本
新版本 2.0 代码
meta 标签固定为
代码逻辑为: 取 width 分为 10rem, font-size = width / 10
注: 手机淘宝首页 2019-01-16, 也是这个方案, 但是是 width = 3.75rem, font-size = 100px, 估计是为了方便除
代码, 添加部分注释
vw/vh (css3 新增属性)
实现:
缺点:
vw + rem
优点:
实现: 以下实现把屏幕平均分成 10 份,即屏幕宽 10rem, 以 rem 与 vw 关系: rem:vw = 10:1 或者 1rem = 10vw 为依据
100vw === 10 rem === document.documentElement
前提:<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
html 的 font-size 等于 1/10 的视口宽度 (即: 1rem = 1 / 10 * 100vw => 等同于 lib-flexible 中 document.documentElement.style.fontSize = clientWidth / 10) [此处取 1/10, 因为在淘宝方案也是取这个值, 为了更好计算可以去其他值]
// $vw_design: 设计图尺寸
// $vw_fontsize: 设计图尺寸 / 10 假设把设计图分为10份, 每份的大小(设计图的1rem), 并以此为基数
html {
font-size: ($vw_fontsize / $vw_design) * 100vw; // 直接写 10vw
// 同时,通过Media Queries 限制根元素最大最小值
@media screen and (max-width: 320px) {
font-size: 32px;
}
@media screen and (min-width: 540px) {
font-size: 54px;
}
}
复制代码
计算使用 scss 函数: 设计图元素尺寸 / (设计图尺寸 / 10) * 1rem
// $basesize: 设计图元素尺寸
@function rem($basesize) {
@return ($basesize / $vw_fontsize) * 1rem;
}
//简化
@function rem($basesize) {
@return ($basesize / $vw_design) * 10rem;
}
复制代码
计算原理:
观察最后推论,于是也可以按照以下理解:
参考: juejin.im/post/5c0357…
rem + js
js 动态设置 html {font-size: (clientWidth / 屏幕平均分成份数)px}
防止使用 rem 后,未设置 font-size 的元素继承使用根元素的 font-zsize,重置 body 的 font-size 为默认值(一般 16px)或使用媒体查询字体响应式(320, 480, 640 移动端尺寸)
总结
响应式布局方案
总结:
其他
1px 实现
百分比计算
参考: github.com/sunmaobin/s…
https://juejin.im/post/5ee5e5cd51882557525a8d69?utm_source=gold_browser_extension
The text was updated successfully, but these errors were encountered: