页面布局
- 静态布局(Static Layout)
使用CSS逻辑像素单位px
进行定宽布局,是PC端最常见形式。 - 流式布局(Liquid Layout)
流式布局的特点是页面元素宽度按屏幕分辨率进行适配调整,但整体布局不变,典型代表是栅格系统。页面主要划分区域尺寸使用百分比,并搭配min-*
、max-*
属性属性。 - 自适应布局(Adaptive Layout)
创建多个静态布局,每个静态布局对应一个屏幕分辨率范围。屏幕分辨率改变时可以切换为不同的静态布局,页面元素位置会发生改变。但每个静态布局中,页面元素不会随着窗口大小的调整发生变化。实现方式是使用@media
媒体查询给不同尺寸和介质的设备切换不同样式。 - 响应式布局(Responsive Layout)
响应式设计目标是确保一个页面在所有终端都能显示出令人满意的效果,通常会糅合流式布局、弹性布局,再搭配媒体查询使用。会分别为不同屏幕分辨率定义布局,同时在每个布局中应用流式布局理念,即页面元素宽度随窗口调整而自动适配。也就是创建多个流体式布局,分别对应一个屏幕分辨率范围。可以将响应式布局看作是流式布局和自适应布局设计理念的融合。 - 弹性布局(Flexiable Layout)
以REM或RM为单位的布局,适用于移动端且设计对高度和元素间距要求不高。采用REM+JS方式只是宽度自适应,高度并没有做到自适应。对高度或元素间距要求较高的设计,并不合适。
设备像素
- 设备物理像素(Physical Pixel)
表示每英寸所拥有的像素数量,一个物理像素是显示屏上最小的物理显示单元。物理像素数值越大,代表屏幕能够以更高的密度来显示图像。在操作系统调度下,每个设备像素都拥有自己的色值与亮度值。 - 设备独立像素(Density-Independent Pixel,DIP)
设备独立像素又叫做密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(如CSS中的像素),然后会根据相关系统转换为物理像素。 - CSS像素
CSS像素是一个抽象的的单位,主要使用在浏览器中用来精确度量页面内容。一般而言,CSS像素又称为与设备无关的像素,即设备独立像素DIP。
页面中CSS中单位默认使用的是像素px
,CSS中的像素是一个相对值,在不同设备屏幕中对应着不同的设备像素。
例如:在PC中1个CSS像素等于1个物理像素。而在3.5英寸的iPhone3GS分辨率320 x 480中1个CSS像素等于1个物理像素,而在3.5英寸的iPhone4S分辨率640 x 640中1个CSS像素等同于2个物理像素。这也就意味着相同一块3.5英寸的区域内像素多了一倍。 - 设备像素比(Device Pixel Ratio,DPR)
设备像素比是指物理像素和设备独立像素的对应关系,某在某方向中,设备像素比的计算公式是:设备像素比 = 物理像素 / 设备独立像素。可通过JavaScript中的window.devicePixelRatio
获取当前设备的DPR。
设备 | 设备物理像素 | 设备独立像素 | 设备像素比 | 屏幕宽高比 | 宽高比等值转换 | 屏宽转414 |
---|---|---|---|---|---|---|
iPhone3G/S | 320 x 480 | 320 x 480 | 1 | 2:3 | 9:13.5 | 414 x 621 |
iPhone4S | 640 x 960 | 320 x 480 | 2 | 2:3 | 9:13.5 | 414 x 621 |
iPhone5S | 640 x 1136 | 320 x 568 | 2 | 40:71 | 9:16 | 414 x 736 |
iPhone6 | 750 x 1334 | 375 x 667 | 2 | 9:16 | 9:16 | 414 x 736 |
iPhone6+ | 1242 x 2208 | 414 x 736 | 3 | 9:16 | 9:16 | 414 x 736 |
- 位图像素
一个位图像素是栅格图像(如jpg、png、gif等)最小的数据单元,每个位图像素包含自身的显示信息,如显示位置、颜色值、透明度等。理论上,一个位图像素对应于一个物理像素,图像才能得到完美清晰的展示。
例如:对于DPR=2的Retina屏幕而言1个位图像素对应于4个物理像素,由于单一位图像素不可再分割,所以只能就近取色,从而导致图片模糊。所以对于图片清晰度问题,较好的方案是提供两倍图@x2
。
像素密度PPI
类型 | 尺寸 | 屏幕分辨率 | 设备独立像素DIP | 屏幕像素密度PPI |
---|---|---|---|---|
iPhone6,7,8 @2x | 4.7 | 750 x 1334 | 375 x 667 1dp = 2px | 326 |
笔记本 | 14, 15.6 | 1080 x 1920 | 157, 147 | |
显示器 | 24, 27 | 1080 x 2048 2k | 96, 85 |
像素密度表示设备屏幕能够显示的设备独立像素DIP的数量,屏幕显示的像素数量越多画面也就越精细,同时同样屏幕区域能够显示的信息也就越多。
屏幕由像素点组成,每个像素点发出不同颜色的光,进而构成界面。而屏幕的物理尺寸与像素尺寸是不成比例的。不同尺寸的手机屏幕拥有不同的分辨率,分辨率实际上是手机像素的宽高尺寸。
像素密度(pixels per inch,PPI或DPI)表示每英寸长度上排列的设备独立像素点DIP的个数,1英寸等于2.53厘米。像素密度PPI越高则表示屏幕分辨率越高进而屏幕显示越精细。Retine屏幕比普通屏幕清晰的原因,是因为它的像素密度是普通屏幕的数倍。
例如:3.5英寸的iPhone手机屏幕
- iPhone 3GS的屏幕分辨率为320 x 480
- iPhone 4S的屏幕分辨率为 640 x 960
日常所说的屏幕尺寸,实际是指屏幕对角线的长度。计算像素密度首先需要计算设备屏幕对角线等效像素,然后除以对角线长度。例如HTC G7分辨率为480x800,3.7英寸,计算出像素密度为252PPI。
像素密度PPI = 平方像素宽加平方像素高之和开平方的结果,再除以屏幕对角线的英寸数。
密度决定比例
通过计算像素密度PPI可以得知设备屏幕属于哪个密度区间,因为不同密度区间对应着不同的默认缩放比例。
像素密度PPI | 类型 |
---|---|
120~160 | 低密度 |
160~240 | 中密度 |
240~360 | 高密度 |
>320 | 超高密度(Retina) |
缩放比
设备 | 设备宽度 | 设备宽度 | 对角线 | 逻辑分辨率 | 缩放比率 | 设备分辨率 | 像素密度 |
---|---|---|---|---|---|---|---|
iPhone 3GS | 2.4inches 62.1mm | 4.5inches 115.5mm | 3.5-inch | 320 x 480 | @1x | 320 x 480 | 163 |
iPhone 4(S) | 2.31inches 58.6mm | 4.5inches 115.2mm | 3.5-inch | 320 x 480 | @2x | 640 x 960 | 326 |
iPhone 5C | 2.33inches 59.2mm | 4.9inches 124.4mm | 4-inch | 320 x 568 | @2x | 640 x 1136 | 326 |
iPhone 5(S) | 2.31inches 58.6mm | 4.87inches 123.8mm | 4-inch | 320 x 568 | @2x | 640 x 960 | 326 |
iPhone 6 | 2.64inches 67.0mm | 5.44inches 138.1mm | 4.7-inch | 375 x 667 | @2x | 750 x 1334 | 326 |
iPhone 6+ | 3.06inches 77.8mm | 6.22inches 158.1mm | 5.5-inch | 414 x 736 | @3x | 1242 x 2208 | 401 |
页面宽高
- 页面可见区域宽高:
document.body.clientWidth
||document.body.clientHeight
- 页面正文区域宽高:
document.body.scrollWidth
||document.body.scrollHeight
(包含滚动条长度) - 页面被卷左上区域:
document.body.scrollLeft
||document.body.scrollTop
视区 Viewport
通俗来说视区Viewport
就是浏览器上用来显示页面的区域,也就是说,浏览器的实际宽度和手机宽度不一样,无论手机宽度是320px或640px,在手机浏览器内部宽度始终会是浏览器本身的视区。
现代浏览器都会给自身的视区提供一个默认值,大多会以980px或1024px为主。在移动端视区默认一般来说是会大于手机屏幕的,所以当在桌面浏览器正常显示的页面,会以960px设计主区域。放到移动端就会出现横向滚动条,因此会专门会给浏览器设计移动端的页面。
移动端浏览器会将页面放在一个虚拟的窗口viewport
中,通常这个虚拟的窗口会比屏幕宽,这样就不用将每个页面挤到很小的窗口中,以防止破坏没有针对手机浏览器优化的网页布局,用户可以通过平移或缩放来查看页面中的不同部分。
页面中视区viewport
是可绘制的区域,虽然视区的可视面积和屏幕尺寸相匹配,但视区页由自己的尺寸,用来确定页面中的像素数量。
在iPhone
和Android
平台中WebKit
内核的历览器使用980像素宽的视见区或逻辑尺寸,相当于viewport中的width=980px。当页面加载后,页面内容通常被完全缩放以便整个页面都可见,尽管内容会被缩放的非常小且不可读。
在Web页面中,可通过JS动态获取相关参数。
// 获取布局视口宽度
document.documentElement.clientWidth
// 获取展示视口即浏览器可视区域宽度
window.innerWidth
// 获取设备像素比DPR
window.devicePixelRatio
根据目前市场主流移动终端,统计设备独立像素后,移动端H5设计稿推荐尺寸为640 x 1136、750 x 1334。
- 背景图片采用
background-size:cover
实现 - 设计稿不要将重要内容放在太偏下或偏上位置
除去浏览器全屏显示,几乎所有情况下均会存在顶部状态栏和导航栏。根据iPhone标准,状态栏和导航栏的独立像素高度分别为40px和88px。Android平台可以更改状态和导航栏高度可取默认值48px和100px为准。在网页中就会将页面内容向下挤入盲区,根据不同的布局方式可能会挤出视口,也就是可视区域之下。因此取两个平台的最大值148。因此设计稿要尽量保证单页下没有重要内容。如果要在所有屏幕上将重要内容显示完全,需要注意市面上存在的小尺寸屏幕,绝对部分智能机分辨率在640 x 960之上,因此只要重要内容放在盲区之上即可。计算出的最安全高度为812 = 960 - 148。
视区分类
简单来说视区Viewport
是严格等于浏览器的窗口,在桌面浏览器中视区就是浏览器窗口的宽高,但在移动设备上由于视区太窄,为了更好的为CSS
布局服务,所以提供了两个视区,分别是可见视区Visual Viewport
和布局视区Layout Viewport
。
- 布局视区Layout Viewport
如果将移动设备浏览器的可视区域设置为Viewport,某些网站会因为Viewport太窄而显示错乱,所以浏览器会默认将Viewport设置为一个较宽的值,比如980px,使得为桌面浏览器设计的网站也能在移动设备浏览器上正常显示。这个浏览器默认的Viewport也就是Layout Viewport布局视区。布局视区的宽度可以使用JavaScript的document.documentElement.clientWidth
获取。移动设备中默认的视区就是Layout Viewport。
- 可见视区 Visual Viewport
布局视区的宽度是大于浏览器可视区域的宽度的,因此需要一个Viewport来表示浏览器可视区域大小,这个Viewport也就是可见视区Visual Viewport,可见视区可使用JavaScript的document.documentElement.innerWidth
获取。
视区设置
-
width = device-width
视口宽度,device-width
表示设备屏幕宽度。 -
height = device-height
视口高度,device-height
表示设备屏幕高度。 -
initial-scale = float_value
视口初始缩放比例,取值范围[0.0 - 10.0],为1时表示原始尺寸。 -
minimum-scale = float_value
视口最小缩放比例,取值范围[0.0 - 10.0],为1时表示原始尺寸。 -
maximum-scale = float_value
视口最大缩放比例,取值范围[0.0 - 10.0],为1时表示原始尺寸。 -
user-scalable = [yes | no]
用户是否允许调整缩放比例 -
target-densitydpi = [dpi_value | device-dpi | high-dpi | medium-dpi | low-dpi]
用于改变设备的默认缩放,medium-dpi
是默认值。
完美视区 Ideal Viewport
Ideal Viewport是一个能完美适配移动设备的Viewport,首先无需缩放和横向滚动条就能正常查看页面所有内容,其次显示的文字、图片大小合适。比如14px的文本不会因为一个高密度像素的屏幕而显示的太小或无法看清。无论在何种密度屏幕、何种分辨率下,显示出来的大小都差不多,这个Viewport也就是Ideal Viewport。
Ideal Viewport并没有一个固定的尺寸,不同的设备拥有不同的尺寸。比如在IPhone设备中Ideal Viewport宽度是320px,无论屏幕宽度是320还是640的。Ideal Viewport的意义在于,无论在何种分辨率下,针对Ideal Viewport而设计的页面无需缩放和横向滚动条都可以完美地呈现给用户。
移动设备中默认的视区是Layout Viewport,在进行移动设备页面开发时则需要Ideal Viewport。要得到完美视区,需设置meta
标签。
该meta
标签的作用是让当前视区宽度等于设备宽度,同时不允许用户手动缩放。minimum-scale=1.0
与maximum-scale=1.0
并不是必需的。但width = device-width
则是必须的,以保证不会出现横向滚动条。
width
能够控制默认布局视区Layout Viewport的宽度,若不指定则默认会是980px或1024px,这个值会由设备自身所决定。当把布局视区宽度设置为移动设备宽度width = device-width
时,此时布局视区将会变成完美视区。
其实要将当前视区宽度设置为完美视区宽度,既可以设置width = device-width
也可以设置initial-scale = 1.0
,但是单单设置width = device-width
会导致iPhone、iPad设备中横竖屏不分,单单设置initial-scale = 1.0
则会导致IE中横竖屏不分。所以都以竖屏的完美视口宽度为标准,最完美的写法时两则都写上去,width = device-width
解决iPhone、iPad缺陷,initial-scale = 1.0
则解决IE的缺陷。
视区单位 vm & vh
CSS3新增视区单位vm和vh,在移动端iOS8+和Android4.4+获得支持。
-
vm
视区viewport
宽度的1/100,即1vm等于视区宽度的1%。 -
vh
视区viewport
高度的1/100,即1vh等于视区高度的1%。 -
vmin
表示选取vm和vh中最小的那个 -
vmax
表示选择vm和vh中最大的那个
设备像素比 DPR
设备像素比定义了物理像素与设备独立像素之间的对应关系,计算公式为:设备像素比 = 物理像素 / 设备独立像素。
在CSS中可通过以下方式进行媒体查询,针对不同DPR设备做出样式适配。
-webkit-device-pixel-ratio
-webkit-min-device-pixel-ratio
-webkit-max-device-pixel-ratio
在JavaScript中可通过window.devicePixelRatio
获取当前设备的DPR。
window.devicePixelRatio
在Ratina高清设备屏幕中一个CSS像素对应4个物理像素
- 普通屏幕:1个CSS像素对应1个物理像素(1:1)
- Retine屏:1个CSS像素对应4个物理像素(1:4)
Web页面设置视口后,页面与屏幕是1:1显示,移动设备都具有设备像素比DPR
,当DPR=2时移动设备上的一个CSS像素由4个物理像素点组成。
- dpr = 1 如PC端,则html的font-size为50px,此时 1rem = 50px, viewport 的 initial-scale 、minimum-scale 和 maximum-scale 都为 “1.0” 。
- dpr = 2 如iPhone 5 和 6,则html的font-size为100px,此时 1rem = 100px, viewport 的 initial-scale 、minimum-scale 和 maximum-scale 都为 “0.5” 。
- dpr = 3 如iPhone 6 sp,则html的font-size为150px,此时 1rem = 150px; viewport 的 initial-scale 、minimum-scale 和 maximum-scale 都为 “0.3333333333”。
安卓客户端限制了 viewport 设置的缩放属性,让客户端放开限制就行,但是由于市场上的app版本还是不支持,所以需要做兼容性处理。
iPhone6 上有1px 的滚动条,最后处理方案是通过 viewport 中的 maximum-scale 的值加了0.1,由于设置了user-scalable=no,maximum-scale 的值加0.1并不会有什么影响。
通过JS动态获取移动设备的设备像素比,通过设备像素比来计算并设备Web页面中html
标签的字体大小font-size
以及缩放比例。
例如:动态设置 html 的font-size, 同时根据设备DPR调整页面的缩放值,进而达到高清效果。
'use strict';
/**
* @param {Boolean} [normal = false] - 默认开启页面压缩以使页面高清;
* @param {Number} [baseFontSize = 100] - 基础fontSize, 默认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;
// 自动设置viewport
let metaEl = doc.querySelector('meta[name="viewport"]');
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
doc.head.appendChild(metaEl);
}
metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`);
// 默认dpr=2时html的font-size=100px,这样1rem=100px利于px和rem之间的转换。
doc.documentElement.style.fontSize = normal ? '50px' : `${_baseFontSize / 2 * dpr * _fontscale}px`;
};
REM
rem
全称font size of the root element
是指相对于根元素的字体大小的相对单位,计算规则依赖于根元素。
rem
是通过根元素进行适配的,web中根元素是指html
,所以通过设置html
的字体大小即可控制rem
的大小。
REM布局的核心是设置好根html
元素的字体大小font-size
,为了防止在高清屏下像素不够用而导致模糊,当拿到移动设计稿时,移动设计稿一般会以iPhone5设备宽320px或iPhone6设备宽375px为基准,制作出两倍宽的设计稿,即640px或750px。
例如:设置html
标签的font-size:10px
,6rem即6*10px。
html{
font-size:10px;
}
.btn{
width:6rem;
height:3rem;
line-height:3rem;
font-size:1.2rem;
border-radius:.5rem;
display:inline-block;
background-color:#06c;
color:#fff;
text-decoration:none;
text-align:center;
}
rem
适用于WebApp,出于兼容性考虑,WebApp下使用rem
更加能凸价值和功能。
屏幕宽高 | 宽高比 | 根字号 | 元素像素宽度 | 元素REM宽度 |
---|---|---|---|---|
320 | 0.5 | 10px | 100px | 10rem |
384 | 0.6 | 12px | 120px | 10rem |
480 | 0.75 | 15px | 150px | 10rem |
640 | 1 | 20px | 200px | 10rem |
使用CSS的媒体查询控制
html{font-size:10px}
@media screen and (min-width:321px) and (max-width:375px){html{font-size:11px}}
@media screen and (min-width:376px) and (max-width:414px){html{font-size:12px}}
@media screen and (min-width:415px) and (max-width:639px){html{font-size:15px}}
@media screen and (min-width:640px) and (max-width:719px){html{font-size:20px}}
@media screen and (min-width:720px) and (max-width:749px){html{font-size:22.5px}}
@media screen and (min-width:750px) and (max-width:799px){html{font-size:23.5px}}
@media screen and (min-width:800px){html{font-size:25px}}
移动UI设计稿会采用iPhone宽度作为标准
- 设计稿基于iPhon4/5 横向分辨率为640 页面
body
元素的width
为 640 / 100 = 6.4rem - 设计稿基于iPhon6 横向分辨率为750 页面
body
元素的width
为 750 / 100 = 7.5rem
document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + 'px';
document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + 'px';
使用JS控制Web页面文字大小使其自适应屏幕
//Chrome包括其内核的webview有最小字体12px的限制,建议以1080px宽度下100px作为1rem基准,以10px为基准缩放程度极其有限
(function(doc, win){
var docEl = doc.documentElement,
resizeEvent = "orientationchange" in window ? "orientationchange" : "resize",
resizeHandler = function(){
var clientWidth = docEl.clientWidth;
if(!clientWidth){
return;
}
// 根据设计调整
docEl.style.fontSize = 20*(clientWidth/320) + "px";
};
//添加事件
if(!doc.addEventListener){
return;
}
win.addEventListener(resizeEvent, resizeHandler, false);
//注册了document的'DOMContentLoaded'事件,使得打开网页时在内容加载完之后才改变rem。
doc.addEventListener("DOMContentLoaded", resizeHandler, false);
})(document, window);
使用rem
布局的本质是等比缩放,一般是基于宽度。
将屏幕宽度均分100份,每一份的宽度使用x表示,即x=屏幕宽度/100,如果将x作为单位,x前面的数值代表屏幕宽度的百分比。想要屏幕元素随着屏幕宽度等比缩放,只需要确定x单位,可通过CSS3中的rem
来实现。可通过JS设置HTML字体大小等于屏幕宽度的百分之一。
document.documentElement.style.fontSize = document.documentElement.clientWidth / 100 + "px";
若UE设计稿宽度尺寸为640px,设计稿中某元素宽度为100px,则可以计算出100 / 640px * 100px = 15.625。
设计稿宽度 | 设计稿元素宽度 | 页面宽度 | 页面根元素字体大小 | 页面元素宽度 |
---|---|---|---|---|
640px | 100px | 640px | 640px / 100 = 6.4px | 6.4px * 15.625 = 100px |
480px | 75px | 480px | 480px / 100 = 4.8px | 4.8px * 15.625 = 75px |
320px | 50px | 320px | 320px / 100 = 3.2px | 3.2px * 15.625 = 50px |
最佳实践:px2rem移动端自适应方案 https://github.com/imochen/hotcss
EM
字体大小不能使用rem
,因为字体大小和字体宽度并不是线性关系,所以字体大小不能使用rem
。由于设置根元素字体大小会影响所有没有设置字体大小的元素,因为字体大小是会继承的,可以在body
上做字体修正。
如何实现字体的响应式,可通过修改body
字体大小,同时设置字体大小使用em
单位。