<meta>的viewport
值方案:理想视口方案、或1/DPR
缩放方案。font-size
阶梯取值方案(位图字体):CSS媒体查询额外设置方案、或JS设置html的data-dpr统一控制方案。flex
优雅解决布局、自适应问题)。使用vm
(或vh
)
参考:大漠:再聊移动端页面的适配。
设置为理想视口:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
用vw
(或vh
、vmin
、vmax
)设置html的font-size
:root {
--psd: 设计稿宽度px; /* 无单位 */
--rfz: 缩小倍数; /* 无单位。可以设置为100:方便计算、也因为PC浏览器通常都有最小字体限制 */
}
html {
/* 单位:vw */
font-size: 具体vw; /* 兼容性 */
font-size: calc(100vw / 设计稿宽度px * 缩小倍数); /* 兼容性 */
font-size: calc(100vw / var(--psd) * var(--rfz));
}
- 若原本是PC页面而增加的WAP适配,就在html外添加媒体查询。
若要限制最大宽度(或高度)的页面,可以媒体查询限定html的
>要限制最小宽度(或高度)同理,改变`min-`为`max-`、改变`最大`为`最小`。 ```css /* 在上面的基础上增加媒体查询限制最大宽度 */ @media (min-width: 最大宽度px) { html { /* 单位:px(不能换算成rem) */ font-size: 具体px; /* 兼容性 */ font-size: calc(最大宽度px / 设计稿宽度px * 缩小倍数); /* 兼容性 */ font-size: calc(最大宽度px / var(--psd) * var(--rfz)); } } /* 或 */ @media (min-height: 最大高度px) { html { /* 单位:px(不能换算成rem) */ font-size: 具体px; /* 兼容性 */ font-size: calc(最大宽度px / 设计稿宽度px * 缩小倍数); /* 兼容性 */ font-size: calc(最大高度px / var(--psd) * var(--rfz)); } } ```font-size
为具体px
。
元素用设计稿的px除以缩小倍数(--rfz
),单位用rem
(手动计算或px转rem方案)。
原理思路:把设计稿转化为宽度的百分比(vw)显示在移动端上。
- 针对1080px的设计稿,初始设定:`--psd: 1080; --rfz: 100;`: 300px的设计稿距离计算如下 1. 1080px设计稿中300px占用:`300px / 1080px ≈ 0.278`; 2. 300px的设计稿距离写成CSS为:`300 / var(--rfz) + rem => 300 / 100 + rem = 3rem`; `3rem => 3 * html的font-size => 3 * calc(100vw / var(--psd) * var(--rfz)) => 3 * 100vw / 1080 * 100 ≈ 27.8vw`; 3. `27.8vw === 设计稿宽度的0.278`,从而设计稿对应了响应式页面。
当Android系统的样式出现问题又找不到原因时,有可能是系统字体大小被修改过。
视口(viewport)
网站外层的容器,控制网站的最高块状容器:<html>
。
PC端的viewport就是浏览器窗口的宽度高度,严格等于浏览器的窗口。
PC端无视
<meta>
的viewport设置。
WAP端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport
可视视口(visual viewport):
浏览器的窗口,可以放大缩小、滚动页面来改变可见部分。
通过<meta name="viewport" content="initial-scale=缩放值, user-scalable=是否缩放, minimum-scale=缩放值, maximum-scale=缩放值">
控制缩放。
视觉上,可视视口永远是浏览器大小,但宽度值等于逻辑像素宽度。
可视视口宽度(屏幕范围内CSS像素堆积的总宽度) = 浏览器宽度 / 现在的缩放值
JS获取:window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
。
随页面缩放而改变。
布局视口(layout viewport):
网站外层容器的固定大小,决定<html>
宽度。不同浏览器默认大小不同,980px左右;不能小于可视视口。
通过<meta name="viewport" content="width=布局视口初始宽度值, initial-scale=缩放值">
设置并缩放成为最终布局视口宽度。
布局视口宽度 = 初始宽度值 / 初始缩放值 > 可视视口宽度 : 初始宽度值 / 初始缩放值 ? 可视视口宽度
JS获取:document.documentElement.clientWidth || document.body.clientWidth
。
随写入的viewport的
宽度值 / 初始缩放值
改变而改变。
CSS媒体查询判断:@media (min-width: 宽度px) and (max-width: 宽度px)
。
随写入的viewport的
宽度值 / 初始缩放值
改变而改变。
概念理解
想象下layout viewport是一张大的不能改变大小和角度的图片。现在你有个更小的框来观看这张大图片,这个框被不透明的材料包围,因此你只能看到大图片的一部分。你通过这个框看到的大图片的部分被称为visual viewport。你能拿着这个框站得离大图片远点(用户的缩小页面功能),以一次性看到这个大图片的更多区域;或你能站得近点(用户的放大页面功能),以看到更少区域。你能改变这个框,但这张大图片的大小和形状都不会改变。
理想视口(ideal viewport):<meta name="viewport" content="width=device-width,initial-scale=1.0">
像素(pixel)
像素是数字图像的最小组成单元,它不是一个物理尺寸,但和物理尺寸存在一个可变的换算关系(物理尺寸之间的换算是固定的),也是分辨率的单位。
CSS像素(前端用的px
)
viewport的像素。浏览器内部对逻辑像素进行再处理的结果(调整逻辑像素的缩放来达到适应设备的一个中间层)。
width=device-width
:让viewport的宽度等于逻辑像素的总宽度。
设备独立像素(Device-Independent Pixels,DIPs),密度无关像素(Density-Independent Pixels,DIPs)
逻辑像素,一种度量单位。由程序使用的虚拟像素,然后由相关系统转换为物理像素呈现。
iOS用
pt
(point),Android用dp
(density-independent pixel),前端用px
。
物理像素(physical pixels),设备像素(device pixels)
e.g. iPhone 13 Mini的渲染像素是
1125x2436
,对应的逻辑像素是375x812@3x
(css或js获取的像素也是这个逻辑像素值),但是它的物理像素是1080x2340
(特殊,设计成渲染分辨率和物理分辨率不一致)。
比例
DPR(Device Pixel Ratio,设备像素比)、dppx(dots per pixel,每物理像素包含的逻辑像素数量)、dpi(dots per inch,每英寸包含逻辑像素数量)
DPR = 物理像素 / 设备独立像素
、1DPR = 1dppx = 96dpi
window.devicePixelRatio
。@media (min或max-resolution: 整数dppx)
、@media (min或max-resolution: 整数dpi)
。
- 改变浏览器缩放,会改变DPR。
- 对于固定的逻辑像素,当系统分辨率改变时(导致物理像素变化),DPR不变。
PPI(Pixels Per Inch,每英寸物理像素,物理像素密度)
PPI = Math.sqrt(物理像素宽的平方 + 物理像素高的平方) / 屏幕对角线长度的英寸
表示每英寸所拥有的物理像素数目。
主屏分辨率
物理像素(或系统提供的、被当做物理像素的值)的宽x高。
rem:相对于根元素的字体大小的单位。rem单位转换为具体px值:rem乘于html的font-size像素。
SCSS在.scss
文件进行
@function rem($px, $base-font-size: 20px) {
@if unitless($px) {
@return rem($px + 0px);
}
@if unit($px) != "px" {
@error "rem()的参数单位必须是px或不带单位";
}
// $base-font-size:切图时设计稿宽度对应的媒体查询中html的font-size 或 --rfz+px
@return $px / $base-font-size + rem;
}
a {
width: rem(20);
}
/*
a {
width: 1rem;
}
*/
px2rem(或px2rem-postcss)在.css
文件进行
/* px2rem设置:remUnit: 20,baseDpr: 1 */
a {
width: 20px;
height: 40px; /*px*/
padding: 60px; /*no*/
margin: 80PX;
}
/*
a {
width: 1rem;
padding: 60px;
margin: 80PX;
}
[data-dpr="1"] a {
height: 40px;
}
[data-dpr="2"] a {
height: 80px;
}
[data-dpr="3"] a {
height: 120px;
}
*/
CSS属性:
@media (min-width: 360px) and (max-width: 640px) {...}
HTML标签:
<link rel="stylesheet" type="text/css" media="(min-width: 360px) and (max-width: 640px)" href="...">
流式布局:节点用百分比
或rem
或flex
或grid
布局
使用自适应结构,如:自适应宽度布局。
img {max-width: 100%;}
- @1、@2、@3不同分辨率的图片放大倍数是1倍、2倍、3倍。
若图片是雪碧图
- 则其间距也要是和放大倍数一致,@1、@2、@3分别间距是2px、4px、6px。
- 则其
background-size
设置为最低分辨率整个雪碧图的高宽)、background-position
设置为最低分辨率时的值。单位用px
、rem
、百分比
都可以。
媒体查询
@mixin image($url) {
background-image: url($url + "@1.png");
@media (min-resolution: 2dppx) {
background-image: url($url + "@2.png");
}
@media (min-resolution: 3dppx) {
background-image: url($url + "@3.png");
}
}
.img {
@include image("去除后缀的图片地址");
}
<img>
的一些属性:srcset
、sizes
;background-image
的值:image-set()
高倍图在低PPI设备下显示,不会导致图片模糊或锯齿,因此有时可简化地把高倍图用在所有机型上
高倍图使用在低PPI设备下可能导致的问题:
iOS、Android可以在系统设置中修改字体大小
、视图大小/显示大小
,会导致H5页面的样式数值发生变化(PC版的缩放同理)。
修改字体大小
、视图大小/显示大小
后,手机内H5现象:
iOS
仅变化视窗,节点样式数值不变化
Android
节点font-size
数值变化
rem
单位时也跟着变化(节点其他样式属性数值不是 rem
仅变化视窗,节点样式数值不变化
line-height
可能都有问题解决方案:利用 html的font-size
+ 元素的font-size用rem
单位、元素的其他样式属性数值不要用 单位(e.g. 用rem
vw
、px
、等) 的响应式方案,并根据系统放大/缩小的倍数,对html的font-size
进行逆向处理:
font-size
值,再获取该节点真实font-size
值,他们的倍数就是系统放大/缩小的倍数,需要逆向处理这个倍数;获得前面的倍数,若放大/缩小多少,则html的font-size
等效缩小/放大多少;
e.g. 一开始设置50px;计算得到100px,得知放大了2倍,这时再最终设置为25px。节点的1rem=1rem x 25px x 2倍=50px,与一开始1rem=50px的期望相同。
节点的font-size
数值用rem
,其他样式属性数值不要用 (可以用rem
vw
的响应式方案);
因为其他样式属性数值,用
rem
时,某些机型跟随系统变化,某些机型又不跟随,但是用vw
、px
等其他单位时还未发现会跟随变化。
text-size-adjust
同步系统放大/缩小)。非纯前端解决方案:让客户端打开WebView时就禁止
变化。e.g. WebView初始化时客户端设置字体大小
、视图大小/显示大小
textZoom: 100