如何实现响应式布局

618 阅读6分钟

响应式布局

响应式布局的常用解决方案对比(媒体查询、百分比、rem和vw/vh)

前端开发中,静态网页通常需要适应不同分辨率的设备,常用的自适应解决方案包括媒体查询、百分比、rem和vw/vh等

在静态网页中,我们经常用像素(px)作为单位,来描述一个元素的宽高以及定位信息。在pc端下和移动端下font-size为16px时字体大小显示不同

1. 像素

一个像素表示了计算机屏幕所能显示的最小区域,像素分为两种类型:css像素和物理像素。

我们在js或者css代码中使用的px单位就是指的是css像素,物理像素也称设备像素,只与设备或者说硬件有关,同样尺寸的屏幕,设备的密度越高,物理像素也就越多。

css像素为web开发者提供,在css中使用的一个抽象单位
物理像素只与设备的硬件密度有关,任何设备的物理像素都是固定的

2. 视口

广义的视口,是指浏览器显示内容的屏幕区域,狭义的视口包括了布局视口、视觉视口和理想视口

(1) 布局视口(layout viewport)

布局视口定义了pc网页在移动端的默认布局行为,因为通常pc的分辨率较大,布局视口默认为980px。也就是说在不设置网页的viewport的情况下,pc端的网页默认会以布局视口为基准,在移动端进行展示。因此我们可以明显看出来,默认为布局视口时,根植于pc端的网页在移动端展示很模糊。

(2) 视觉视口(visual viewport)

视觉视口表示浏览器内看到的网站的显示区域,用户可以通过缩放来查看网页的显示内容,从而改变视觉视口。视觉视口的定义,就像拿着一个放大镜分别从不同距离观察同一个物体,视觉视口仅仅类似于放大镜中显示的内容,因此视觉视口不会影响布局视口的宽度和高度。

(3) 理想视口(ideal viewport)

理想视口或者应该全称为“理想的布局视口”,在移动设备中就是指设备的分辨率。换句话说,理想视口或者说分辨率就是给定设备物理像素的情况下,最佳的“布局视口”。

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;">

3. px与自适应

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

不同的移动设备分辨率不同,也就是1个CSS像素可以表示的物理像素是不同的,因此如果在css中仅仅通过px作为长度和宽度的单位,造成的结果就是无法通过一套样式,实现各端的自适应。

4. 媒体查询

通过媒体查询,可以通过给不同分辨率的设备编写不同的样式来实现响应式的布局

媒体查询的缺点也很明显,如果在浏览器大小改变时,需要改变的样式太多,则多套样式代码会很繁琐。

@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;
    }
}

or

<style media=”(min-device-width: 100px) and (max-device-width: 300px)”>
       #div0{
         Background-color: red;
}
</style>

or

<link media=”(min-width:500px)” rel=”stylesheet” href=”common.css”>
<link media=”(max-width:500px)” rel=”stylesheet” href=”mobile.css”>

5.百分比

当浏览器的宽度或者高度发生变化时,通过百分比单位,通过百分比单位可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果。

缺点: 计算困难 、容易使布局问题变得复杂

1)height和width——相对于子元素的直接父元素

2) top和bottom 、left和right——相对于直接非static定位(默认定位)的父元素的高度和宽度

3)padding——不论方向,都相对于直接父亲元素的width,而与父元素的height无关。

4)margin——不论方向,都相对于直接父亲元素的width,而与父元素的height无关。

5)border-radius——相对于自身的宽度(translate、background-size等都是相对于自身的)

//应用——实现一个长宽比为4:3的长方形
.trangle{
  height:0;
  width:100%;
  padding-top:75%;
}

6. rem

通过rem单位,可以实现响应式的布局,特别是引入相应的postcss相关插件,免去了设计稿中的px到rem的计算。

缺点:在响应式布局中,必须通过js来动态控制根元素font-size的大小。也就是说css样式和js代码有一定的耦合性。且必须将改变font-size的代码放在css样式之前

单位

rem是一个灵活的、可扩展的单位,由浏览器转化像素并显示。与em单位不同,rem单位无论嵌套层级如何,都只相对于浏览器的根元素(HTML元素)的font-size。默认情况下,html元素的font-size为16px,所以1 rem = 16px

1 rem = 16px

为了计算方便,通常可以将html的font-size设置成:

html{ font-size: 62.5% }

这种情况下:

1 rem = 10px

rem实现响应式布局

只需要根据视图容器的大小,动态的改变font-size即可。

//将视图容器分为10份,font-size用十分之一的宽度来表示,最后在header标签中执行这段代码,
//就可以动态定义font-size的大小,从而1rem在不同的视觉容器中表示不同的大小,
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);

rem2px和px2rem

rem2px: 从rem换算成px,只要rem乘以相应的font-size中的大小,就能换算成px

px2rem:

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})];
  }
}

7.vw/vh

定义

1vw等于视图宽度的百分之一。

单位含义
vw相对于视窗的宽度,视窗宽度是100vw
vh相对于视窗的高度,视窗高度是100vh
vminvw和vh中的较小值
vmaxvw和vh中的较大值
单位含义
%大部分相对于祖先元素,也有相对于自身的情况比如(border-radius、translate等)
vw/vh相对于视窗的尺寸

换算

设375*667的分辨率

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
};