网页移动端适配的胡乱分析
由viewport到移动端页面适配
如果你想认真仔细地了解可以看看这一篇博客
对于viewport,字面意思是视口,也就是我们正常能看见的窗口。有大神把viewport分为layout viewport(浏览器默认的viewport,基本大于浏览器可视区域), visual viewport(浏览器的可视区域) 和 ideal viewport(移动设备理想的viewport)。为什么会这么麻烦呢?
这就要提到像素(px)了。css中的1px和事实上的1px其实并不相同。mdn上边说的是A pixel is not a pixel
,像素并非像素。嗯,有点复杂。其实也没那么复杂。css里边的px是一个相对的概念,在移动设备上,如果屏幕像素密度很高,而css和物理像素依然是一比一的关系的话,那么我们视觉上是没法看清网页的。所以如果屏幕像素密度很高,基本上一个css像素会对应几个物理像素。
而这是现在,以前手机上的分辨率不高的时候,在我们还活在诺基亚支配的恐惧下的时候(ps:这里没有贬它的意思,毕竟那个时代能做到那样已经很不错了),我们用的是wap来实现手机上的网页,功能有限。直到苹果出来了,苹果改变了移动终端浏览网页的方式,使得html可以在移动端展示。但是初代iPhone屏幕是3.5英寸,分辨率为480*320,为了让用户有更好的浏览体验(至少能把页面显示完全),iPhone默认把你的页面的viewport设置为980px(也就是layout viewport),这样我们就可以通过滑来滑去来浏览那些为电脑设计的网页了。
所以这就直接导致了不论我们的分辨率多高只要这个网页没有适配移动端那么我们极有可能看到的是一个布局完全错乱的网站,因为移动端真正的viewport(也就是可视区域,visual viewport)不够宽。鉴于随着科技的发展,越来越多的网站都会为移动设备进行单独的设计,这个可以完美适配移动设备的viewport,称为ideal viewport。
对于开发者而言,做移动端的适配的话当然离不开ideal viewport了,而移动设备浏览器默认的viewport是layout viewport(那个比屏幕宽的),如果想要得到ideal viewport,需要用到html的meta标签。
快捷键:meta:vp
<meta name="viewport" content="width = device-width, initial-scale = 1.0, user-scalable = no">
width: 设置的是layout viewport的宽度,可以为正整数,为device-width的时候表示等于设备的宽度。
initial-scale: 设置页面的缩放值,是一个数字。如果为1.0的话表示不进行缩放,完全适配移动端。也就是说,缩放为1.0的话表示此时的ideal viewport和layout viewport是相等的。
user-scalable: 设置用户是否可以进行缩放。yes表示可以,no表示不可以。
除了上边的三个之外,content里边还可以设置minimum-scale(允许用户的最小缩放值),maximum-scale(允许用户的最大缩放值)和height(基本不用的参数)。
在使用的时候,width = device-width
和initial-scale = 1.0
可以达到同样的效果,但是在不同的设备上两个属性的兼容性不同,所以为了保险起见一般会把两句都加上。
获取visual viewport宽度:window.innerWidth
获取layout viewport宽度:document.documentElement.clientWidth
当它们的比例为一比一的时候,就是ideal viewport。
由媒体查询到移动端适配
@media是写在同一个css文件中的查询条件,当设备符合某个媒体查询条件的时候里边的css生效。
用@media的时候注意覆盖的问题,比如下边的情况
@media(max-width: 320px){ background: red; }
@media(max-width: 375px){ background: black; }
此时background: red
并不会生效,因为max-width: 375px
包括max-width: 320px
,并且它写在后边,所以会覆盖前边的。
如果你不想它被覆盖可以把范围小的写在下边。或者让它们没有交集,比如这样
@media(min-width: 0) and (max-width: 320px) { background: red; }
@media(min-width: 321px) and (max-width: 375px) { background: black; }
除了@media之外你也可以直接在link文件的时候执行查询条件,比如<link rel="stylesheet" rel="style.css" media="(max-width: 320px)">
。这里需要注意的是虽然我们在请求的资源里进行了查询,但其实就算显示的设备不满足查询条件,这个css文件也一样会下载。只是不生效而已。
所有的响应式网站用的都是媒体查询,一个典型的响应式网站在这里,事实上响应式不过是你做了两版网页,一个用于PC端一个用于移动端。如果你选择移动端优先,那就是选择了方案Mobile first,PC端优先就是Desktop first了(emmm为什么要整个专业名词)。
响应式基本上是通过元素的隐藏和显示来实现,对css进行各种覆盖。实际开发中很少会用到响应式,比如淘宝和京东都是通过后台判断,给你进行重定向到另一个地方,而知乎是选择展示另一个网页。
由rem到移动端适配
网页单位:
rem可以说是专为移动端网页开发准备的一个单位了。网页开发中的单位包括有我们常见的px,em,vh,vw,百分比,rem等等。px是绝对像素单位。em是一个相对长度单位,一般说来1em指的是一个font-size的宽度,你可以简单的记成一个字母M的宽度。vh(viewport height)和vw(viewport width)分别是相对于视口的高度和宽度,比如100vh就是视口的高度。其实到这里已经够了,我们可以用vw做兼容性很好的手机页面。但是vw的兼容性太差,所以不得不放弃这个方案。而百分比的话虽然可以保证宽度的良好缩放比,但不能保证高度具有同样的效果,如果你需要一个元素的宽高在缩放的时候也保持着相同的比例,那你就不得不放弃这个方案。而我们要说的rem,是一个在保证兼容性的情况下也能保证长宽比的一个方案。rem(root em)是相对于根元素的大小来确定自己本身的大小,这里的根元素,指的是html元素而不是body。
常识相关:
需要注意的是浏览器默认字体大小是16px,也就是说如果你不写font-size的话,那么它的font-size就是16px。
以及,Chrome浏览器的最小字号是可以在浏览器的设置里边手动设置的,如果没有修改的话那么默认最小字号是12px。也就是说,如果你设置font-size: 6px;
显示出来的结果依然是12px。
以及,网页显示的最小单位是1px,小于1px的都会按照1px来显示。
正文:
一切单位以宽度为基准就可以很好地还原设计图,因为高度是可以滑动的。但是只有vw是以宽度为基准的,而它的兼容性不好所以被我们弃用。这里的主角rem同样与宽度无关,但是我们可以让它变得与宽度有关。
我们知道js可以为html添加元素,所以我们用js来动态获取页面的viewport,让1rem === 1vw
。
var width = window.innerWidth/100
document.write('<style>html{font-size: '+ width +'px}<style>')
但是这样写的话你就犯了一个常识性错误。Chrome的最小字号默认是12px。你这样设置的话,1rem很有可能小于12px,这样布局是会错乱的。所以保险起见除以10就够了,把视口的宽度分为十份来进行布局。
这是一个简单的网页示例。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<script>
var width = window.innerWidth/10
document.write('<style>html{font-size: '+ width +'px}<style>')
</script>
<style>
*{ margin: 0; padding: 0; }
body{ margin: 0; padding: 0; font-size: 16px; }
.child{
float: left;
background: #ddd;
width: 4rem;
height: 2rem;
margin: .5rem .5rem;
}
.clearfix::after{
content: '';
display: block;
clear: both;
}
</style>
</head>
<body>
<div class="parent clearfix">
<div class="child">box</div>
<div class="child">box</div>
<div class="child">box</div>
<div class="child">box</div>
</div>
</body>
</html>
在我们使用热门布局的时候,并不意味着px等其它的单位就不可用了,事实上,为了更好地完成一个网页。你可以将他们混着用。因为有的时候屏幕如果很小的话,由rem计算出来的字体或者什么的可能就看不清楚了,这个时候还不如用px这种绝对单位。
将px转换成rem:
如果用rem的话我们需要手动计算rem的值,很麻烦。众所周知程序员都很懒,所以使用sass可以很好的帮你解决这个问题。
1. 安装sass
npm config set registry https://registry.npm.taobao.org/
touch ~/.bashrc
echo 'export SASS_BINARY_SITE="https://npm.taobao.org/mirrors/node-sass"' >> ~/.bashrc
source ~/.bashrc
npm i -g node-sass
鉴于国内上网的诸多限制所以我们没法直接用命令npm i -g node-sass
来安装,只能先把下载源设置为淘宝镜像然后再执行下载。这种安装的是node-sass。你也可以安装ruby-sass。
2. 使用scss的函数将px转换成rem
tips: SCSS是Sass3引入的新的语法。
先创建style.scss文件和style.css文件。
然后开启自动转换,如果你是node-sass的话,请使用node-sass -wr style.scss -o style.css
,如果是ruby-sass的话,使用sass --watch style.scss:style.css
。开启之后不要动它。
在style.scss
文件中写下这段代码。
@function px2rem( $px ){
@return $px/$designWidth*10 + rem;
}
$designWidth = 640; //设计稿的宽度
然后就可以直接在style.scss
文件里用px2rem(不加单位的像素值)
了,sass服务会帮我们把它的值计算出来并写入css文件。
最后需要注意的一点东西
- 移动端没有click事件,没有hover,有touch。很多框架都封装了touch实现的滑动事件(swiper)。所以一般不监听click和hover。
- 手机上没有滚动条。