1. 前端移动端适配总结 2. 移动端三种适配方案 3.前端解决移动端适配的五种方法 4.移动端前端适配方案(总结) – 面试重点 5.网页设计师的终极CSS工具 6.
1、前端移动端适配总结
从 Chrome32+版本开始是会默认禁用用户缩放的,但是考虑到兼容大部分设备,还是要加上其他设置,让 meta标签能够有更好的容错性。也就是下面这段代码:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;">
需要注意的是,在 ios10+以上,尽管开发者设置了 user-scalable=no, Safari还是允许用户通过手势来缩放。(安卓手机各大厂商的内置浏览器也逐渐开放用户缩放,即使使用 meta标签进行设置)
解决的方法也很简单,只需要 检测 touch相关事件来阻止事件的触发 即可。
window.onload = function() {
// 同时按下两个手指
document.addEventListener('touchstart', function(event) {
if(event.touches.length > 1) {
event.preventDefault()
}
})
var lastTouchEnd = 0;
// 特别注意300ms时差的设置
document.addEventListener('touchend', function(event) {
var now = (new Date()).getTime();
if(now-lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
})
}
2.移动端三种适配方案
五种属性
device-width:意思是设备宽度
inital-scale:页面初始缩放值,默认为1;
maximum-scale:允许用户缩放到的最大比例。
minimum-scale:允许用户缩放到的最小比例。
user-scalable:用户是否可以手动缩放。
媒体查询适配
使用 @media 查询 可以针对不同的屏幕尺寸设置不同的样式,特别是如果你需要设置设计响应式的页面,@media 是非常有用的。 当你重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。
使用方法:
可以直接在link标签中插入媒体查询css 上面的意思表示如果浏览器可视区域小于等于800px时,就执行example.css中的样式。
<link rel="stylesheet" media="(max-width: 800px)" href="example.css" />
@media (max-width: 600px) {
body {
background-color:red;
}
}
嵌入式css写法 使用and
(min-width: 700px) and (orientation: landscape) { ... }
使用,(逗号)可以使得多个媒体查询属性中有任意一个属性符合要求,就应用后面的css样式
符合前一项媒体查询属性或者后一项媒体查询属性时应用后面的css样式
@media (min-width: 700px), handheld and (orientation: landscape) { ... }
使用not可以排除后面的媒体查询属性,在其余的媒体查询中应用css样式
表示在宽度大于700px时,应用css样式
@media not (max-width:700px){...}
3.em和rem动态适配
em
- em和rem都是相对单位长度
- em是相对父级font-size来变化的
- 他会继承父级元素的字体大小,代表倍数
- 如:浏览器默认font-size:16px,那么em就是1em
body{font-size:20px;}
div{font-size:2em} //实际像素为font-size:40px;
当给body设置font-size:20px,后,div设置font-size:2em, div的font-size实际变成了40px
不过在实际布局中,如果嵌套过深,em计算起来比较的繁琐,容易出现错误,因此不见大范围使用,小范围可以结合其它长度单位来使用,
rem
rem是相对于html根元素font-size来变化的,始终是基于根元素字体大小,也代表倍数,浏览器默认的font-size为16px,那么rem单位就是1rem;
body{font-size:20px;}
div{font-size:2em} //实际像素为font-size:32px;
当给body设置为font-size:20px,给div设置为font-size:2rem,div的实际font-size变成了32px,
动态计算rem的javascript代码
在移动端布局中使用rem,由于它是基于根元素的,所以只要根元素不发生变化,那么页面就不会发生变化,同时呢也没有em的繁琐嵌套计算,在配合上动态计算rem的javascript代码,使之在移动端布局中广受欢迎, 使用如下javascript代码即可动态计算
(function(win) {
var doc = win.document;
var docEl = doc.documentElement;
var tid;
function refreshRem() {
var width = docEl.getBoundingClientRect().width;
if (width >=750) width = 750;
if(width<=320) width=320;
var rem = width / 7.5;
docEl.style.fontSize = rem + 'px';
}
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
refreshRem();
})(window);
4.移动端适配的五种方法
第一种方法:viewport适配
//获取meta节点
var metaNode = document.querySelector('meta[name=viewport]');
//定义设计稿宽度为375
var designWidth = 375;
//计算当前屏幕的宽度与设计稿比例
var scale = document.documentElement.clientWidth/designWidth;
//通过设置meta元素中content的initial-scale值达到移动端适配
meta.content="initial-scale="+scale+",minimum-scale="+scale+",maximum-scale="+scale+",user-scalable=no";
第二种方法:借助media实现rem适配
//对屏幕大小划分了html不同的font-size
@media screen and (min-width: 320px) {html{font-size:50px;}}
@media screen and (min-width: 360px) {html{font-size:56.25px;}}
@media screen and (min-width: 375px) {html{font-size:58.59375px;}}
@media screen and (min-width: 400px) {html{font-size:62.5px;}}
@media screen and (min-width: 414px) {html{font-size:64.6875px;}}
@media screen and (min-width: 440px) {html{font-size:68.75px;}}
@media screen and (min-width: 480px) {html{font-size:75px;}}
@media screen and (min-width: 520px) {html{font-size:81.25px;}}
@media screen and (min-width: 560px) {html{font-size:87.5px;}}
@media screen and (min-width: 600px) {html{font-size:93.75px;}}
@media screen and (min-width: 640px) {html{font-size:100px;}}
@media screen and (min-width: 680px) {html{font-size:106.25px;}}
@media screen and (min-width: 720px) {html{font-size:112.5px;}}
@media screen and (min-width: 760px) {html{font-size:118.75px;}}
@media screen and (min-width: 800px) {html{font-size:125px;}}
@media screen and (min-width: 960px) {html{font-size:150px;}}
第三种方法:JS配合修改配合rem适配
var designWidth = 375; // 设计稿宽度
var remPx = 100; // 在屏幕宽度375px,的时候,设置根元素字体大小 100px
var scale = window.innerWidth / designWidth; //计算当前屏幕的宽度与设计稿比例
// 根据屏幕宽度 动态计算根元素的 字体大小
document.documentElement.style.fontSize = scale*remPx + 'px';
第四种方法:JS动态修改配合CSS预处理器(less)
// 计算屏幕宽度
var screen = document.documentElement.clientWidth;
// 计算字体大小,取屏幕宽度的16分之一
var size = screen / 16;
// 设置根元素字体大小
document.documentElement.style.fontSize = size + 'px';
js获取当前屏幕的宽度,将屏幕宽度的16分之一设置给html的font-size
// 此时设计稿的宽度为375,定义一个less变量等于16分之一的设计稿宽度
@rem: 375/16rem;
如果此时设计稿中的16可以为任意值,你设置多少,js中屏幕宽度就除于多少再赋值给html的font-size。
若设计稿中的某元素设置宽高为200px
.box{
width:200px;
height:200px;
}
此时可以替换为:
.box{
width:200/@rem;
height:200/@rem;
}
第五种方法:JS动态修改配合rem适配
这种方法跟第四种雷同,但不需要再在less中定义变量,只需要进行js获取配合查找替换px即可。
// 计算屏幕宽度
var screen = document.documentElement.clientWidth;
// 设置根元素字体大小
document.documentElement.style.fontSize = screen + 'px';
.box{
width:200px;
height:200px;
}
.box{
width:200/375rem;
height:200/375rem;
}
分析:
这种方法是js动态获取屏幕宽度,直接将html的font-size 设置为屏幕的宽度,再在 less 中进行换算。若此时js获取的屏幕宽度为750px,html的font-size值设置为750px后,此时计算box的width为400px
200/375rem = 200/375*750 px = 400px
5、移动端前端适配方案(总结) – 面试重点
目前为止出现的一些关于移动端适配的技术方案
(1)通过媒体查询的方式即CSS3的meida queries
(2)以天猫首页为代表的 flex 弹性布局
(3)以淘宝首页为代表的 rem+viewport缩放
(4)rem 方式
1.Media Queries
通过查询设备的宽度来执行不同的 css 代码,核心语法是:
@media screen and (max-width: 600px) {
/*当屏幕尺寸小于600px时,应用下面的CSS样式*/
/*你的css代码*/
}
优点
- media query可以做到设备像素比的判断,方法简单,成本低,特别是对移动和PC维护同一套代码的时候。目前像Bootstrap等框架使用这种方式布局
- 图片便于修改,只需修改css文件
- 调整屏幕宽度的时候不用刷新页面即可响应式展示
缺点
- 代码量比较大,维护不方便
- 为了兼顾大屏幕或高清设备,会造成其他设备资源浪费,特别是加载图片资源
- 为了兼顾移动端和PC端各自响应式的展示效果,难免会损失各自特有的交互方式
2.Flex弹性布局
以天猫的实现方式进行说明:
它的viewport是固定的:如下
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
高度定死,宽度自适应,元素都采用px做单位。
随着屏幕宽度变化,页面也会跟着变化,效果就和PC页面的流体布局差不多,在哪个宽度需要调整的时候使用响应式布局调调就行(比如网易新闻),这样就实现了『适配』。
3.rem + viewport 缩放
这也是淘宝使用的方案,根据屏幕宽度设定 rem 值,需要适配的元素都使用 rem 为单位,不需要适配的元素还是使用 px 为单位。(1em = 16px)
PS:rem
rem是CSS3新增的一个相对单位(root em,根em),这个单位引起了广泛关注。这个单位与em有什么区别呢?
区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。这个单位可谓集相对大小和绝对
大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁
反应。目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一
个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。比如:p{font-size:14px;font-size:0.875rem;}
(推荐一个单位转换的工具:)实现原理
- 根据rem将页面放大dpr倍, 然后viewport设置为1/dpr.
- 如iphone6 plus的dpr为3, 则页面整体放大3倍, 1px(css单位)在plus下默认为3px(物理像素)
然后viewport设置为1/3, 这样页面整体缩回原始大小. 从而实现高清。
mobile-fe4.png
mobile-fe3.png
这样整个网页在设备内显示时的页面宽度就会等于设备逻辑像素大小,也就是device-width。
这个 device-width 的计算公式为:设备的物理分辨率/(devicePixelRatio * scale),
————————————————
在scale为1的情况下,device-width = 设备的物理分辨率/devicePixelRatio 。
4、rem实现
比如说“魅族”移动端的实现方式,viewport也是固定的:
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
通过以下代码来控制rem基准值(设计稿以720px宽度量取实际尺寸)
!function (d) {
var c = d.document;
var a = c.documentElement;
var b = d.devicePixelRatio;
var f;
function e() {
var h = a.getBoundingClientRect().width, g;
if (b === 1) {
h = 720
}
if(h>720) h = 720;//设置基准值的极限值
g = h / 7.2;
a.style.fontSize = g + "px"
}
if (b > 2) {
b = 3
} else {
if (b > 1) {
b = 2
} else {
b = 1
}
}
a.setAttribute("data-dpr", b);
d.addEventListener("resize", function () {
clearTimeout(f);
f = setTimeout(e, 200)
}, false);
e()
}(window);
css通过sass预编译,设置量取的px值转化rem的变量$px: (1/100)+rem;
像素边框高清
1.淘宝实现方式
上面说到的淘宝的实现方式即rem+viewport 缩放来实现。
——————
transform: scale(0.5)
CSS代码:
div{
width: 1px;
height: 100%;
display: block;
border-left: 1px solid #e5e5e5;
-webkit-transform: scale(.5);
transform: scaleX(.5);
}
缺点:
圆角无法实现,实现4条边框比较麻烦,并且只能单独实现,如果嵌套,会对包含的效果产生不想要的效果,所以此方案配合:after和before独立使用较多。
box-shadow
实现方法:
利用CSS对阴影处理的方式实现0.5px的效果。
-webkit-box-shadow:0 1px 1px -1px rgba(0, 0, 0, 0.5);
6、移动端自适应适配布局的方法总结
方法一:rem布局
首先确定你的设计稿是基于iphone6还是iphone4/5:
如果设计稿基于iphone6,横向分辨率为750,body的width为750 / 100 = 7.5rem
如果设计稿基于iphone4/5,横向分辨率为640,body的width为640 / 100 = 6.4rem(1) 对视口做如下设置:
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
(2) 在index.html入口文件里写:
var deviceWidth = document.documentElement.clientWidth;
// 注意:iphone6要除以7.5
document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';
(3).使用方法:如果设计图上标注高200px, 写 height: 2rem
方法二:固定一个某些宽度,使用一个模式,加上少许的媒体查询
方法三:淘宝的lib-flexible插件
(1) 在项目中安装lib-flexible
$ npm install lib-flexible --save
(2) 在项目的入口js文件中引入lib-flexible
import 'lib-flexible'
(3) 删除该meta标签,需要使用lib-flexible自己生成的 meta name="viewport"来达到高清适配的效果:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
(4) 使用px2rem-loader自动将css中的px转换成rem,安装px2rem-loader
$ npm install px2rem-loader --save-dev
(5) 打开build/utils.js文件,找到exports.cssLoaders方法,在里面添加如下代码
const px2remLoader = {
loader: 'px2rem-loader',
options: {
remUint: 75
}
}
(6) 修改generateLoaders方法中的loaders
// 注释掉这一行
// const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
// 修改为
const loaders = [cssLoader, px2remLoader]
if (options.usePostCSS) {
loaders.push(postcssLoader)
}
然后重新npm run dev,打开控制台可以看到代码中的px已经被转成了rem
该插件需要注意以下两点:
1.此方法只能将.vue文件style标签中的px转成rem,不能将script标签和元素style里面定义的px转成rem
2.如果在.vue文件style中的某一行代码不希望被转成rem,只要在后面写上注释 /* no*/就可以了
7、移动端页面自适应解决方案—rem布局(进阶版)
该方案使用相当简单,把下面这段已压缩过的 原生JS(源码已在文章底部更新,2017/5/3) 放到 HTML 的 head 标签中即可(注:不要手动设置meta标签viewport,该方案自动帮你设置)
<script>!function(e){function t(a){if(i[a])return i[a].exports;var n=i[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=window;t["default"]=i.flex=function(e,t){var a=e||100,n=t||1,r=i.document,o=navigator.userAgent,d=o.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i),l=o.match(/U3\/((\d+|\.){5,})/i),c=l&&parseInt(l[1].split(".").join(""),10)>=80,p=navigator.appVersion.match(/(iphone|ipad|ipod)/gi),s=i.devicePixelRatio||1;p||d&&d[1]>534||c||(s=1);var u=1/s,m=r.querySelector('meta[name="viewport"]');m||(m=r.createElement("meta"),m.setAttribute("name","viewport"),r.head.appendChild(m)),m.setAttribute("content","width=device-width,user-scalable=no,initial-scale="+u+",maximum-scale="+u+",minimum-scale="+u),r.documentElement.style.fontSize=a/2*s*n+"px"},e.exports=t["default"]}]); flex(100, 1);</script>