响应式布局常见的方案-移动+PC

5,502 阅读7分钟

导读:

前端开发,必然会遇到多端适应,在不同分辨率的设备上,拥有同样的效果。常见的方法有媒体查询、百分比、rem、vw/vh,开发人员在常用的px单位情况下,怎么运用上面的方法呢,请见正文。

一、相关概念

1、px与视口

px, 是开发人员常用来进行开发的单位,宽、高、间隙等,但是大家想一下,应该清楚: px是跟常用的单位,比如厘米/米等固定单位是有区别的。

我们在pc端,设置文字16px,在移动端,可能就变得很小很小了。

为了理清楚这个概念我们首先介绍像素和视口的概念

1.1 像素概念

像素是网页布局的基础,一像素表示设备能显示的最小的单位,像素又分为物理像素和CSS像素

  • CSS像素是为开发者提供的一种抽象的单位
  • 只跟设备自身有关,并且每个设备自身的像素是固定的

物理像素和CSS像素又是怎么转换的呢,先看一下视口的概念

1.1 视口概念

视口分广义和狭义,广义是浏览器显示内容的屏幕区域,狭义分下面几种:布局、视觉、理想

1.1.1 布局视口(layout viewport)

在pc网页的情况下,默认定义大小为980px,如果在没有设置viewport情况下,pc页面在移动端展示的话,会以默认大小为基准,如果以默认大小进行显示的话,在移动端会很模糊

1.1.2 视觉视口(visual viewport)

表示浏览器看到的网站的区域,用户可以通过放大缩小来进行查看网页里面的内容,从而改变视觉视口的大小,相当于拿一个放大镜进行观察。因此,视觉这并不影响布局视口的实际高度和宽度

1.1.3 理想视口(ideal viewport)

可以总结为一句话,理想视口就是在给定的物理像素情况下,最佳的布局视口。换句话说,就是要获取移动端的最佳布局视口。

为了在移动端获取最佳布局视口,常用viewport标签来进行控制

<meta id="viewport" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1; user-scalable=no;">

主要属性为 content里面的width,要适应移动端布局,需要设置其为device-width,一般表示分辨率宽,这样设置就把移动端的布局设置成理想视口了。

1.2 DPR 设备像素比
1 DPR = 物理像素/分辨率

如果在不缩放情况下,1css 对应 1dpr

1 CSS像素 = 物理像素/分辨率
1.3 PX、自适应

通过上面的viewport元标签,我们已经把布局设置成理想视口时,1CSS像素可以表示为

1CSS = 物理像素/分辨率

在pc布局视口下,一般为980px,移动端以iphone6为例,分辨率375 * 667 ,现在有一个750px * 1134px视觉稿,在pc端:

1CSS = 750 / 980 = 0.76px

在移动端:

1CSS = 750 / 375 = 2 px

很明显移动端和PC端每CSS像素对应的物理像素,如果只用一套px的CSS的作为单位,这样是无法做到各端展示一样的样式。要想得到一样的效果,有下面几种办法。

二、媒体查询

如果一套样式不行,那么能否给每一种设备各一套不同的样式来实现自适应的效果?

答案是肯定的

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

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

三、百分比

除了用px结合媒体查询实现响应式布局外,我们也可以通过百分比单位 " % " 来实现响应式的效果。

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

css中的子元素中的百分比(%)到底是谁的百分比?

1 百分比的具体分析

1.1 height和width的百分比

子元素的height或width中使用百分比,是相对于子元素的直接父元素,width相对于父元素的width,height相对于父元素的height。

1.2 top和bottom 、left和right

子元素的top和bottom如果设置百分比,则相对于直接非static定位(默认定位)的父元素的==高度==。

同样,子元素的left和right如果设置百分比,则相对于直接非static定位(默认定位的)父元素的==宽度==。

1.3 padding/margin

子元素的padding如果设置百分比,不论是垂直方向或者是水平方向,==都相对于直接父亲元素的width==,而与父元素的height==无关==。 margin跟padding一样

2百分比缺点

  • 计算困难,如果我们要定义一个元素的宽度和高度,按照设计稿,必须换算成百分比单位。
  • 从小节1可以看出,各个属性中如果使用百分比,相对父元素的属性并不是唯一的。比如width和height相对于父元素的width和height,而margin、padding不管垂直还是水平方向都相对比父元素的宽度、border-radius则是相对于元素自身等等,造成我们使用百分比单位容易使布局问题变得复杂

四、rem

1 rem 单位换算

rem单位无论嵌套层级如何,都只相对于浏览器的根元素(HTML元素)的font-size。默认情况下,html元素的font-size为16px,所以:

1 rem = 16px

可以通过改变html font-size 来进行动态自适应

2 rem2px, px2rem

有个问题就是开发的时候,单位用rem,而设计师一般都是用px来设计,开发者用rem来开发,极为不适应,虽然可以 font-size进行转换。

有个方案,是开发也用px,用webpack loader进行转译

2.1 直接用loader
npm install px2rem-loader

配置文件

module.exports = {
  // ...
  module: {
    rules: [{
      test: /\.css$/,
      use: [{
        loader: 'style-loader'
      }, {
        loader: 'css-loader'
      }, {
        loader: 'px2rem-loader',
        // options here
        options: {
          remUni: 75,
          remPrecision: 8
        }
      }]
    }]
  }
2.1 用webpack的插件
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})];
  }
}

3 rem 缺点

在响应式布局中,必须通过js来动态控制根元素font-size的大小。

五、通过vw/vh来实现自适应

css3中引入了一个新的单位vw/vh,与视图窗口有关,vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度,除了vw和vh外,还有vmin和vmax两个相关的单位。

单位 含义
vw 相对于视窗的宽度,视窗宽度是100vw
vh 相对于视窗的高度,视窗高度是100vh
vmin vw和vh中的较小值
vmax vw和vh中的较大值

相关的转换,比如 375 分辨率的设备

1px = (1/375)*100 vw

也可以通过postcss的相应插件,预处理css做一个自动的转换,可以自动将px转化成vw。

var defaults = {
  viewportWidth: 320,
  viewportHeight: 568, 
  unitPrecision: 5,
  viewportUnit: 'vw',
  selectorBlackList: [],
  minPixelValue: 1,
  mediaQuery: false
};

通过指定视窗的宽度和高度,以及换算精度,就能将px转化成vw。比如375

vw/vh 方案因浏览器兼容有问题,暂时只作了解,可不深入学习.