个人博客原文地址:原文地址 若是文章对您有帮助,您的star是对我最好的鼓励~css
简要介绍:前端开发中,静态网页一般须要适应不一样分辨率的设备,经常使用的自适应解决方案包括媒体查询、百分比、rem和vw/vh等。本文从px单位出发,分析了px在移动端布局中的不足,接着介绍了几种不一样的自适应解决方案。html
- px和视口
- 媒体查询
- 百分比
- 自适应场景下的rem解决方案
- 经过vw/vh来实现自适应
在静态网页中,咱们常常用像素(px)做为单位,来描述一个元素的宽高以及定位信息。在pc端,一般认为css中,1px所表示的真实长度是固定的。前端
那么,px真的是一个设备无关,跟长度单位米和分米同样是固定大小的吗?webpack
答案是否认的,下面图1.1和图1.2分别表示pc端下和移动端下的显示结果,在网页中咱们设置的font-size统一为16px。css3
图1.1 pc端下font-size为16px时的显示结果git
图1.2 移动端下font-size为16px时的显示结果github
从上面两幅图的对比能够看出,字体都是16px,显然在pc端中文字正常显示,而在移动端文字很小,几乎看不到,说明在css中1px并非固定大小,直观从咱们发如今移动端1px所表示的长度较小,因此致使文字显示不清楚。web
那么css中的1px的真实长度到底由什么决定呢?npm
为了理清楚这个概念咱们首先介绍像素和视口的概念浏览器
像素是网页布局的基础,一个像素表示了计算机屏幕所能显示的最小区域,像素分为两种类型:css像素和物理像素。
咱们在js或者css代码中使用的px单位就是指的是css像素,物理像素也称设备像素,只与设备或者说硬件有关,一样尺寸的屏幕,设备的密度越高,物理像素也就越多。下表表示css像素和物理像素的具体区别:
css像素 | 为web开发者提供,在css中使用的一个抽象单位 |
---|---|
物理像素 | 只与设备的硬件密度有关,任何设备的物理像素都是固定的 |
那么css像素与物理像素的转换关系是怎么样的呢?为了明确css像素和物理像素的转换关系,必须先了解视口是什么。
广义的视口,是指浏览器显示内容的屏幕区域,狭义的视口包括了布局视口、视觉视口和理想视口
布局视口定义了pc网页在移动端的默认布局行为,由于一般pc的分辨率较大,布局视口默认为980px。也就是说在不设置网页的viewport的状况下,pc端的网页默认会以布局视口为基准,在移动端进行展现。所以咱们能够明显看出来,默认为布局视口时,根植于pc端的网页在移动端展现很模糊。
视觉视口表示浏览器内看到的网站的显示区域,用户能够经过缩放来查看网页的显示内容,从而改变视觉视口。视觉视口的定义,就像拿着一个放大镜分别从不一样距离观察同一个物体,视觉视口仅仅相似于放大镜中显示的内容,所以视觉视口不会影响布局视口的宽度和高度。
理想视口或者应该全称为“理想的布局视口”,在移动设备中就是指设备的分辨率。换句话说,理想视口或者说分辨率就是给定设备物理像素的状况下,最佳的“布局视口”。
上述视口中,最重要的是要明确理想视口的概念,在移动端中,理想视口或者说分辨率跟物理像素之间有什么关系呢?
为了理清分辨率和物理像素之间的联系,咱们介绍一个用DPR(Device pixel ratio)设备像素比来表示,则能够写成:
1 DPR = 物理像素/分辨率
复制代码
在不缩放的状况下,一个css像素就对应一个dpr,也就是说,在不缩放
1 CSS像素 = 物理像素/分辨率
复制代码
此外,在移动端的布局中,咱们能够经过viewport元标签来控制布局,好比通常状况下,咱们能够经过下述标签使得移动端在理想视口下布局:
<meta id="viewport" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1; user-scalable=no;">
复制代码
上述meta标签的每个属性的详细介绍以下:
属性名 | 取值 | 描述 |
---|---|---|
width | 正整数 | 定义布局视口的宽度,单位为像素 |
height | 正整数 | 定义布局视口的高度,单位为像素,不多使用 |
initial-scale | [0,10] | 初始缩放比例,1表示不缩放 |
minimum-scale | [0,10] | 最小缩放比例 |
maximum-scale | [0,10] | 最大缩放比例 |
user-scalable | yes/no | 是否容许手动缩放页面,默认值为yes |
其中咱们来看width属性,在移动端布局时,在meta标签中咱们会将width设置称为device-width,device-width通常是表示分辨率的宽,经过width=device-width的设置咱们就将布局视口设置成了理想的视口。
上述咱们了解到了当经过viewport元标签,设置布局视口为理想视口时,1个css像素能够表示成:
1 CSS像素 = 物理像素/分辨率
复制代码
咱们直到,在pc端的布局视口一般状况下为980px,移动端以iphone6为例,分辨率为375 * 667,也就是说布局视口在理想的状况下为375px。好比如今咱们有一个750px * 1134px的视觉稿,那么在pc端,一个css像素能够以下计算:
PC端: 1 CSS像素 = 物理像素/分辨率 = 750 / 980 =0.76 px
复制代码
而在iphone6下:
iphone6:1 CSS像素 = 物理像素 /分辨率 = 750 / 375 = 2 px
复制代码
也就是说在PC端,一个CSS像素能够用0.76个物理像素来表示,而iphone6中 一个CSS像素表示了2个物理像素。此外不一样的移动设备分辨率不一样,也就是1个CSS像素能够表示的物理像素是不一样的,所以若是在css中仅仅经过px做为长度和宽度的单位,形成的结果就是没法经过一套样式,实现各端的自适应。
在前面咱们说到,不一样端的设备下,在css文件中,1px所表示的物理像素的大小是不一样的,所以经过一套样式,是没法实现各端的自适应。由此咱们联想:
若是一套样式不行,那么可否给每一种设备各一套不一样的样式来实现自适应的效果?
答案是确定的。
使用@media媒体查询能够针对不一样的媒体类型定义不一样的样式,特别是响应式页面,能够针对不一样屏幕的大小,编写多套样式,从而达到自适应的效果。举例来讲:
@media screen and (max-width: 960px){
body{
background-color:#FF6699
}
}
@media screen and (max-width: 768px){
body{
background-color:#00FF66;
}
}
@media screen and (max-width: 550px){
body{
background-color:#6633FF;
}
}
@media screen and (max-width: 320px){
body{
background-color:#FFFF00;
}
}
复制代码
上述的代码经过媒体查询定义了几套样式,经过max-width设置样式生效时的最大分辨率,上述的代码分别对分辨率在0~320px,320px~550px,550px~768px以及768px~960px的屏幕设置了不一样的背景颜色。
经过媒体查询,能够经过给不一样分辨率的设备编写不一样的样式来实现响应式的布局,好比咱们为不一样分辨率的屏幕,设置不一样的背景图片。好比给小屏幕手机设置@2x图,为大屏幕手机设置@3x图,经过媒体查询就能很方便的实现。
可是媒体查询的缺点也很明显,若是在浏览器大小改变时,须要改变的样式太多,那么多套样式代码会很繁琐。
除了用px结合媒体查询实现响应式布局外,咱们也能够经过百分比单位 " % " 来实现响应式的效果。
好比当浏览器的宽度或者高度发生变化时,经过百分比单位,经过百分比单位可使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果。
为了了解百分比布局,首先要了解的问题是:
css中的子元素中的百分比(%)究竟是谁的百分比?
直观的理解,咱们可能会认为子元素的百分比彻底相对于直接父元素,height百分比相对于height,width百分比相对于width。固然这种理解是正确的,可是根据css的盒式模型,除了height、width属性外,还具备padding、border、margin等等属性。那么这些属性设置成百分比,是根据父元素的那些属性呢?此外还有border-radius和translate等属性中的百分比,又是相对于什么呢?下面来具体分析。
(1)子元素height和width的百分比
子元素的height或width中使用百分比,是相对于子元素的直接父元素,width相对于父元素的width,height相对于父元素的height。好比:
<div class="parent">
<div class="child"></div>
</div>
复制代码
若是设置: .father{ width:200px; height:100px; } .child{ width:50%; height:50%; } 展现的效果为:
(2) top和bottom 、left和right
子元素的top和bottom若是设置百分比,则相对于直接非static定位(默认定位)的父元素的高度,一样
子元素的left和right若是设置百分比,则相对于直接非static定位(默认定位的)父元素的宽度。
展现的效果为:
(3)padding
子元素的padding若是设置百分比,不管是垂直方向或者是水平方向,都相对于直接父亲元素的width,而与父元素的height无关。
举例来讲:
.parent{
width:200px;
height:100px;
background:green;
}
.child{
width:0px;
height:0px;
background:blue;
color:white;
padding-top:50%;
padding-left:50%;
}
复制代码
展现的效果为:
子元素的初始宽高为0,经过padding能够将父元素撑大,上图的蓝色部分是一个正方形,且边长为100px,说明padding不论宽高,若是设置成百分比都相对于父元素的width。
(4)margin
跟padding同样,margin也是如此,子元素的margin若是设置成百分比,不管是垂直方向仍是水平方向,都相对于直接父元素的width。这里就不具体举例。
(5)border-radius
border-radius不同,若是设置border-radius为百分比,则是相对于自身的宽度,举例来讲:
<div class="trangle"></div>
复制代码
设置border-radius为百分比:
.trangle{
width:100px;
height:100px;
border-radius:50%;
background:blue;
margin-top:10px;
}
复制代码
展现效果为:
除了border-radius外,还有好比translate、background-size等都是相对于自身的,这里就不一一举例。
百分比单位在布局上应用仍是很普遍的,这里介绍一种应用。
好比咱们要实现一个固定长宽比的长方形,好比要实现一个长宽比为4:3的长方形,咱们能够根据padding属性来实现,由于padding不论是垂直方向仍是水平方向,百分比单位都相对于父元素的宽度,所以咱们能够设置padding-top为百分比来实现,长宽自适应的长方形:
<div class="trangle"></div>
复制代码
设置样式让其自适应:
.trangle{
height:0;
width:100%;
padding-top:75%;
}
复制代码
经过设置padding-top:75%,相对比宽度的75%,所以这样就设置了一个长宽高恒定比例的长方形,具体效果展现以下:
从上述对于百分比单位的介绍咱们很容易看出若是所有使用百分比单位来实现响应式的布局,有明显的如下两个缺点:
(1)计算困难,若是咱们要定义一个元素的宽度和高度,按照设计稿,必须换算成百分比单位。 (2)从小节1能够看出,各个属性中若是使用百分比,相对父元素的属性并非惟一的。好比width和height相对于父元素的width和height,而margin、padding无论垂直仍是水平方向都相对比父元素的宽度、border-radius则是相对于元素自身等等,形成咱们使用百分比单位容易使布局问题变得复杂。
首先来看,什么是rem单位。rem是一个灵活的、可扩展的单位,由浏览器转化像素并显示。与em单位不一样,rem单位不管嵌套层级如何,都只相对于浏览器的根元素(HTML元素)的font-size。默认状况下,html元素的font-size为16px,因此:
1 rem = 12px
复制代码
为了计算方便,一般能够将html的font-size设置成:
html{ font-size: 62.5% }
复制代码
这种状况下:
1 rem = 10px
复制代码
rem单位都是相对于根元素html的font-size来决定大小的,根元素的font-size至关于提供了一个基准,当页面的size发生变化时,只须要改变font-size的值,那么以rem为固定单位的元素的大小也会发生响应的变化。 所以,若是经过rem来实现响应式的布局,只须要根据视图容器的大小,动态的改变font-size便可。
function refreshRem() {
var docEl = doc.documentElement;
var width = docEl.getBoundingClientRect().width;
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', refreshRem);
复制代码
上述代码中将视图容器分为10份,font-size用十分之一的宽度来表示,最后在header标签中执行这段代码,就能够动态定义font-size的大小,从而1rem在不一样的视觉容器中表示不一样的大小,用rem固定单位能够实现不一样容器内布局的自适应。
若是在响应式布局中使用rem单位,那么存在一个单位换算的问题,rem2px表示从rem换算成px,这个就不说了,只要rem乘以相应的font-size中的大小,就能换算成px。更多的应用是px2rem,表示的是从px转化为rem。
好比给定的视觉稿为750px(物理像素),若是咱们要将全部的布局单位都用rem来表示,一种比较笨的办法就是对全部的height和width等元素,乘以相应的比例,现将视觉稿换算成rem单位,而后一个个的用rem来表示。另外一种比较方便的解决方法就是,在css中咱们仍是用px来表示元素的大小,最后编写完css代码以后,将css文件中的全部px单位,转化成rem单位。
px2rem的原理也很简单,重点在于预处理以px为单位的css文件,处理后将全部的px变成rem单位。能够经过两种方式来实现:
1) webpack loader的形式:
npm install px2rem-loader
复制代码
在webpack的配置文件中:
module.exports = {
// ...
module: {
rules: [{
test: /\.css$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'px2rem-loader',
// options here
options: {
remUni: 75,
remPrecision: 8
}
}]
}]
}
复制代码
}
2)webpack中使用postcss plugin
npm install postcss-loader
复制代码
在webpack的plugin中:
var px2rem = require('postcss-px2rem');
module.exports = {
module: {
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader!postcss-loader"
}
]
},
postcss: function() {
return [px2rem({remUnit: 75})];
}
}
复制代码
网易新闻的移动端页面使用了rem布局,具体例子以下:
经过rem单位,能够实现响应式的布局,特别是引入相应的postcss相关插件,免去了设计稿中的px到rem的计算。rem单位在国外的一些网站也有使用,这里所说的rem来实现布局的缺点,或者说是小缺陷是:
在响应式布局中,必须经过js来动态控制根元素font-size的大小。
也就是说css样式和js代码有必定的耦合性。且必须将改变font-size的代码放在css样式以前。
css3中引入了一个新的单位vw/vh,与视图窗口有关,vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度,除了vw和vh外,还有vmin和vmax两个相关的单位。各个单位具体的含义以下:
单位 | 含义 |
---|---|
vw | 相对于视窗的宽度,视窗宽度是100vw |
vh | 相对于视窗的高度,视窗高度是100vh |
vmin | vw和vh中的较小值 |
vmax | vw和vh中的较大值 |
这里咱们发现视窗宽高都是100vw/100vh,那么vw或者vh,下简称vw,很相似百分比单位。vw和%的区别为:
单位 | 含义 |
---|---|
% | 大部分相对于祖先元素,也有相对于自身的状况好比(border-radius、translate等) |
vw/vh | 相对于视窗的尺寸 |
从对比中咱们能够发现,vw单位与百分比相似,单确有区别,前面咱们介绍了百分比单位的换算困难,这里的vw更像"理想的百分比单位"。任意层级元素,在使用vw单位的状况下,1vw都等于视图宽度的百分之一。
一样的,若是要将px换算成vw单位,很简单,只要肯定视图的窗口大小(布局视口),若是咱们将布局视口设置成分辨率大小,好比对于iphone6/7 375*667的分辨率,那么px能够经过以下方式换算成vw:
1px = (1/375)*100 vw
复制代码
此外,也能够经过postcss的相应插件,预处理css作一个自动的转换,postcss-px-to-viewport能够自动将px转化成vw。 postcss-px-to-viewport的默认参数为:
var defaults = {
viewportWidth: 320,
viewportHeight: 568,
unitPrecision: 5,
viewportUnit: 'vw',
selectorBlackList: [],
minPixelValue: 1,
mediaQuery: false
};
复制代码
经过指定视窗的宽度和高度,以及换算精度,就能将px转化成vw。
能够在https://caniuse.com/ 查看各个版本的浏览器对vw单位的支持性。
从上图咱们发现,绝大多数的浏览器支持vw单位,可是ie9-11不支持vmin和vmax,考虑到vmin和vmax单位不经常使用,vw单位在绝大部分高版本浏览器内的支持性很好,可是opera浏览器总体不支持vw单位,若是须要兼容opera浏览器的布局,不推荐使用vw。
小结:本文介绍在布局中经常使用的单位,好比px、%、rem和vw等等,以及不一样的单位在响应式布局中的优缺点。