问题:当前市场上手机屏幕宽度不尽相同,常见有320px(ipone5)、375px(ipone678)等等,而为了在不同宽度的手机屏幕上良好现显示网页,我们需要解决方案。
原理:当前前端解决手机屏幕自适应的手段极多,究其原理,主要分为两大版块:
一、使用百分比长度单位,当前百分比长度单位一般如下:vw、vh、vm、em、rem、%,优点:一套css代码即可适应所有屏幕宽度不同的手机;
二、使用固定长度单位px,再使用js根据当前屏幕宽度与固定宽度计算比例,进行网页缩放。优点:网页宽度恒定,便于计算
实现:
一、使用百分比宽度单位实现移动端屏幕自适应
我们来聊聊这些百分比长度单位的定义及优缺点。
vw:相对于视口的宽度,视口被均分为100单位的vw;即将当前屏幕宽度均分为100份,1vw即为当前屏幕宽度的1%;优点:vw单位长度准确分明,常用此单位,推荐使用此单位。
vh:相对于视口的高度,视口被均分为100单位的vh;即将当前屏幕高度均分为100份,1vh即为当前屏幕高度的1%;基本不用此单位,它的优点vw都有,但是它有一个致命的缺点:手机屏幕高度分成100份后,不是便于计算的数字,譬如iphone5屏幕高568px,此时1vh=5.68px;iphone678屏幕高667px,此时1vh=6.67px;若设计稿一个div宽高皆为100px,你能口算出它的宽高为多少vh吗?我们不可能带着计算器写代码。
vm:相对于视口的宽度或高度,取决于哪个更小,视口宽度或高度中更小的那个被均分为100单位的vm;即将当前屏幕宽度或高度均分为100份,1vm即为当前屏幕宽度或高度的1%;它的优点vw都有,也曾见有人使用此单位,但我觉得vw比它更好。
em:相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于上一个父元素的默认字体尺寸。举例而言,浏览器默认字体大小为16px,在css中设置
html{font-size:15px;}
body{font-size:14px;}
em将优先使用自身的字体大小,若自身没有设置字体大小,将继承上一个父元素的字体大小,此时没有为当前标签设置字体样式,于是继承body的字体大小,而不是继承html的字体大小,即1em=14px;此单位若要用于屏幕自适应,需与vw配合使用设置父元素的字体大小。于css中进行字体设置譬如:font-size1:4vw;,方可实现屏幕自适应。基本不用此单位,它的优点rem都有,但它是优先使用自身的字体大小,其次继承上一个父元素的字体大小,而我们在使用标签时,经常需要给标签设置字体样式,将导致em的根元素字体尺寸不定,使用起来十分麻烦。
举例如下所示:
在w3c等教学网站中,他们使用px单位作为em单位的根单位,但是使用px做根单位的em单位是无法实现移动端屏幕自适应的。在移动端中,不推荐将px作为em的根单位。
rem:相对长度单位,相对于根元素(即html元素)内文本的字体尺寸。rem继承且只继承html标签的字体大小。同样的,此单位若要用于屏幕自适应,需与vw配合使用设置根元素的字体大小。必须在css中进行字体设置:
html{font-size:4vw;}
,方可实现屏幕自适应。常用此单位,推荐使用此单位。看到这里,相信很多朋友都会感到疑惑,明明直接使用vw单位即可实现自适应,为何要使用vw单位进行设置后来使用rem单位呢?原因很简单:便于计算。首先,设计师设计的移动端设计稿通常使用750px宽度(契合iphone678的屏幕宽度),前端工程师通常使用375px的网页宽度(在所有手机屏幕宽度中,它是最方便计算的宽度)。此时,1vw=3.75px;而4vw=15px;8vw=30px;那么请问,哪个单位更便于计算?由于30px与375px相除并非整数,我推荐使用15px(即1rem=4vw)。
当然,这只是我的小技巧,rem单位与vw单位的优先度相差无几,事实上,使用vw单位的人极多,也许比使用rem单位的人更多,全看各人喜好。
也有人使用px作为rem的根单位,再使用js进行单位缩放,不推荐这样使用,又不是没有rem单位和vw单位用,缩放单位个鸡儿。
%:基本没人用。原因:单纯使用%无法确定div的高度,若使用%,那么必须搭配px等固定长度单位来确定高度,形如
.a{
width: 20%;
height: 20px;
}
这样的方式,很容易导致图片等变形。
二、使用固定长度单位px,再使用js根据当前屏幕宽度与固定宽度计算比例,进行网页缩放,来实现移动端屏幕自适应
这个方法主要需要用到css3的两个属性:transform、 transform-origin。通过transform属性的值scale可以进行网页缩放,这是根本。另外必须允许网页缩放,否则transform属性会不起作用。
这个手段简单来说,需要先定一个网页宽度(譬如750px),再通过js获取屏幕宽度,屏幕宽度/网页宽度=缩放比例,然后通过js执行缩放(为标签添加transform及transform-origin属性)。话不多说,直接上代码。
<html>
<head>
<meta content="width=device-width,height=device-height,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<style>
*{margin: 0;padding: 0;}
#div1{width: 750px;height: 600px;background-color: red;}
#div2{width: 375px;height: 300px;background-color: green;}
</style>
</head>
<body id="body">
<div id="div1">
<div id="div2"></div>
</div>
</body>
<script type="text/javascript">
//id 需要进行缩放的标签id
function suofang(id) {
var num = 750;//css中固定的网页宽度
var oWidth = window.screen.width;//获取当前手机屏幕宽度
var objId = document.getElementById(id);//获取传入的id标签对象
rate = oWidth / num;//缩放比例 = 当前手机屏幕宽度/css中固定的网页宽度
if (oWidth < 1920) {
objId.style.transformOrigin = "left top 0px";
objId.style.transform = "scale(" + rate + ")";
/* IE 9 */
objId.style.msTransformOrigin = "left top 0px";
objId.style.msTransform = "scale(" + rate + ")";
/* Safari and Chrome */
objId.style.webkitTransformOrigin = "left top 0px";
objId.style.webkitTransform = "scale(" + rate + ")";
/* Firefox */
objId.style.mozTransformOrigin = "left top 0px";
objId.style.mozTransform = "scale(" + rate + ")";
/* Opera */
objId.style.oTransformOrigin = "left top 0px";
objId.style.oTransform = "scale(" + rate + ")";
}
};
suofang("body");//执行缩放
</script>
</html>
话不再说,直接上效果:
额外记录:电脑大屏缩放:
<template> <div id="container"> <router-view></router-view> </div> </template> <script> export default { mounted() { window.onresize = (e)=>{//监听当前窗口缩放 this.pageResize(); }; this.pageResize();//初始化页面缩放 }, methods: { // 页面缩放 pageResize() { var num = 1920;//css中固定的网页宽度 var oWidth = document.body.clientWidth;//获取当前窗口宽度 var objId = document.getElementById('container');//获取传入的id标签对象 var rate = oWidth / num;//缩放比例 = 当前屏幕宽度/css中固定的网页宽度 objId.style.transformOrigin = "left top 0px"; objId.style.transform = "scale(" + rate + ")"; /* IE 9 */ objId.style.msTransformOrigin = "left top 0px"; objId.style.msTransform = "scale(" + rate + ")"; /* Safari and Chrome */ objId.style.webkitTransformOrigin = "left top 0px"; objId.style.webkitTransform = "scale(" + rate + ")"; /* Firefox */ objId.style.mozTransformOrigin = "left top 0px"; objId.style.mozTransform = "scale(" + rate + ")"; /* Opera */ objId.style.oTransformOrigin = "left top 0px"; objId.style.oTransform = "scale(" + rate + ")"; }, } }; </script> <style scoped> #container{ width: 1920px !important; height: 1080px !important; } </style>
事实上,有更简便的方法来缩放网页,即通过js操纵meta标签中的initial-scale(即网页初始缩放比例)属性即可。话不多说,直接上代码。
<html>
<head>
<meta content="width=device-width,height=device-height,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<style>
*{margin: 0;padding: 0;}
#div1{width: 750px;height: 600px;background-color: red;}
#div2{width: 375px;height: 300px;background-color: green;}
</style>
</head>
<body id="body">
<div id="div1">
<div id="div2"></div>
</div>
</body>
<script type="text/javascript">
//网页缩放函数
function suofang() {
var num = 750;//css中固定的网页宽度
var oWidth = window.screen.width;//获取当前手机屏幕宽度
rate = oWidth / num;//缩放比例 = 当前手机屏幕宽度/css中固定的网页宽度
if (oWidth < 1920) {
document.getElementsByTagName('meta')[name="viewport"].content="width=device-width,height=device-height,initial-scale=1.0,maximum-scale=1.0,user-scalable=no,width=device-width,height=device-height,initial-scale="+
rate+",maximum-scale=2.0,user-scalable=no";//修改meta的属性
}
};
suofang();
</script>
</html>
话不再说,直接上效果:
ps:此外,还可以使用媒体适配查询的方法来进行自适应,不过媒体适配查询这个方法一般用于pc端与移动端适应。我想应该没人会这么蠢,单纯为了解决移动端自适应而使用它,毕竟为不同宽度手机屏幕的同一个页面的写很多套css实在太蠢了。举例如下:
@media screen and (min-width:1281px) and (max-width:1920px) and (orientation:portrait) {
html { font-size: 15px; }
}
@media screen and (min-width:320px) and (max-width:1280px) and (orientation:portrait) {
html { font-size: 73.24%; }
}