移动端自适应方案

问题:

开发移动端时,通常要适配不同的屏幕,由于每个手机的屏幕大小和ppi不一样。会导致显示不一致的问题。
如何做到按一份设计稿,自动适配其他手机屏最佳方案:

解决办法:

  1. 根据devicePixelRatio 动态计算viewport。保证永远都是与设计稿1:1的比例,而且可以很好的解决1像素问题
    font-size,并且采用统一使用rem单位来布局,就可以解决了。

    1
    2
    3
    var pixelRatio = 1 / window.devicePixelRatio;
    //通过js动态设置视口(viewport)
    document.write('<meta name="viewport" content="width=device-width,initial-scale='+pixelRatio+',minimum-scale='+pixelRatio+',maximum-scale='+pixelRatio+'" />');
  2. 设置html的font-size,然后使用rem单位

    1
    2
    3
    4
    5
    6
    7
    var innerWidth = document.documentElement.getBoundingClientRect().width || window.innerWidth;
    //这里的20也就是默认的html字体大小(这个20只是一个参考值),如果你的设计稿是640,那么字体大小就会是40px
    document.documentElement.style.fontSize = 20 * ( innerWidth/320 ) + 'px'

    //原理:
    比如一个div的宽度在640的屏幕上是75px,然后移到`720(window.innerWidth)`的屏幕上是多少呢?
    640 / 75px = 720 / ?

因为我们设置了viewport永远都是1:1所以,网页会放大或缩小,那么我们动态调节html的

使用现有的库,适应更多情况:

继续优化(使用 webpack 和 px2rem-loader):

在写css代码时,使用px2rem方法

在写css代码时,可以省略调用hotcss中的px2rem方法,直接使用px单位,然后让 px2rem-loader 去帮你转换

将hotcss加入webpack
在github中找到hotcss.js,放入项目中

1
entry: ['./app/js/hotcss.js','./app/js/main.js'],

配置loader

1
2
3
4
css: 'vue-style-loader!css-loader!px2rem-loader?remUnit=40&remPrecision=8',
remUnit就是上面html的font-size:40px

// 150px / remUnit:75px = 2rem;

具体webpack配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = env => {
if (!env) {
env = {}
}
let plugins=[
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({template: './app/views/index.html'}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
];
if(env.production){
plugins.push(
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new ExtractTextPlugin("style.css", {ignoreOrder: true})
)
}
return {
entry: ['./app/js/viewport.js','./app/js/main.js'],
devServer: {
contentBase: './dist',
hot: true,
compress: true,
port: 9000,
clientLogLevel: "none",
quiet: true
},
module: {
loaders: [
{
test: /\.html$/,
loader: 'html-loader'
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
cssModules: {
localIdentName: '[path][name]---[local]---[hash:base64:5]',
camelCase: true
},
extractCSS: true,
loaders: env.production?{
css: ExtractTextPlugin.extract({use: 'css-loader!px2rem-loader?remUnit=40&remPrecision=8', fallback: 'vue-style-loader'}),
scss: ExtractTextPlugin.extract({use: 'css-loader!px2rem-loader?remUnit=40&remPrecision=8!sass-loader', fallback: 'vue-style-loader'})
}:{
css: 'vue-style-loader!css-loader!px2rem-loader?remUnit=40&remPrecision=8',
scss: 'vue-style-loader!css-loader!px2rem-loader?remUnit=40&remPrecision=8!sass-loader'
}
}
}, {
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader'
}
]
},
resolve: {
extensions: [
'.js', '.vue', '.json'
],
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
plugins,
output: {
filename: '[name].min.js',
path: path.resolve(__dirname, 'dist')
}
}
};