一点关于移动端页面开发的总结

3,612 阅读12分钟

写在最前:

 对于移动端页面的开发自己很早就想做下简单的总结了,但感觉不知道该从何说起,有一天看了两篇网上一位作者的文章(后面资源里面会给出链接),觉得写得真的是很好,但是还有一些问题我不是很清楚,所以自己也查阅了相关的文献,结合前面那位作者的一些思路,写下了这篇总结。当然,有说的不对的地方,还望指出,谢谢。

准备工作:

 照例,贴下我的博客地址,别忘了去点赞哈~

两个像素:设备像素+css像素

  • 设备像素:绝对单位,设备像素即设备的物理像素,对于每个设备来说,其设备像素是固定的,它是每个设备能控制显示的最小单位。通常我们所说的1920x1080像素分别率就用的是设备像素。
  • css像素:适用于web编程,是前端开发在描述css样式时经常用到的像素单位。比如,设置某个div的宽度为width:200px,这个就是css像素,是一种抽象概念,实际上并不存在。

页面的缩放:

  • 当用户放大或者缩小页面时,改变的是css像素,而设备像素不会发生改变。如:页面中一个div,它的宽度是200px,当用户操作页面,放大两倍,此时一个css像素的面变成了4个设备像素的面积:宽放大2倍x高放大两倍
  • 页面缩放比例(zoom level)= screen.width / window.innerWidth (一般情况下可以这么计算)

设备像素比(DPR):

  • 在页面缩放比为1的情况下,设备像素比(DPR) = 设备像素个数 / 视觉视口css像素个数(device-width)
  • 对于不同的设备来说设备像素比是不一样的。在早期iphone的DPR值是等于1的,但是后来引入了高密度屏幕,即为了更清晰的展示画面,在有限的设备空间内引入了更多的设备像素。所以后来iphone设备的DPR就改变了,值一般为2。可以通过调试器看到设备的设备像素比,如下图所示:

场景再现:

移动端需求:给你一个750px的设计稿,上面画了一个200px的矩形框。

 既然是写移动端页面,作为一名前端开发者,我想你们首先就会在里面敲下这样一句话:

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">

 看上去只有那么熟悉了。这句话什么意思?它有什么作用呢?别着急,我们先来理解下viewport这个概念。

viewport:

 viewport即视口,它的作用是限制页面的根元素即。在PC端,视口可以看成只有一个,即我们所看到的页面窗口,它的大小由浏览器窗口来决定。但是在M端视口分为两类:视觉视口(visual viewport)和布局视口(layout viewport),后文我会详细解释为什么移动端有这两个视口。(既然M端做了这样的划分,我们也可以对PC端采取同样的方式,即PC端viewport就是PC端的visual viewport)

 所以,对于PC端来说,根元素的大小就可以由visual viewport来确定了。那么,怎么计算呢?下面分情况给出相应的计算方式:

  1. 浏览器没有出现(横向、纵向)滚动条且没有人为的去设置元素的宽高(html的宽高可以人为的去设置,但是一般情况下我们不建议这样做):
html的宽度 = document.documentElement.clientWidth = document.documentElement.offsetWidth = window.innerWidth
  1. 浏览器出现滚动条且没有人为的去设置元素的宽高:
html的宽度 = document.documentElement.clientWidth = document.documentElement.offsetWidth = window.innerWidth - 滚动条的宽度
  1. 人为设置了的宽度时:
html的宽度 = document.documentELement.offsetWidth

 如此,PC端就可以按照其viewport的尺寸进行页面的布局。有了上面的基础,我们接下来看看M端页面。M端较之于PC端,一个显然的不同就是设备的尺寸。M端的屏幕宽度大多<=400px,不像PC端那样,动不动就是上千像素。这样PC端的页面到了移动端,可谓是不堪入目,下面是真实的网站截图,

  • PC端页面:

  • PC端页面放到移动端:

 可以看到,在没有做M页面优化的情况下,PC端页面放到M端时,为了让你看清整个页面,强行把里面的内容进行缩放,以至于模糊不清,简直无法直视。(当然人家的页面是做了M端优化的,为了看效果我是把里面的给删掉了,哈哈哈,机智吧~)

如何解决M端设备尺寸太小的问题呢:

 既然移动端的视觉视口太窄(浏览器的宽度)而不能满足css布局的需求,那么就想办法弄一个更宽的视口出来,满足M端布局需求。此时,layout viewport应运而生。

 布局视口比视觉视口要宽的多,M端就是根据布局视口来进行css布局的。而且在M端,元素的大小是由布局视口来确定的,就像我们之前谈到的PC端和视觉视口的关系那样。那么,布局视口到底有多大呢,以及他是怎样去计算的呢?

 对于M端来说,其布局视口的大小取决于浏览器厂商,一些常见的布局视口取值如下表所示:

browserviewport width
Safiri980px
Opera850px
Android WebKit800px
IE974px
跟PC端有点类似,布局视口的大小可有下面的方式取得:
布局视口的宽度 = document.documentElement.clientWidth
布局视口的高度 = document.documentElement.clientHeight

有了这个布局视口的概念后,我们再来看看PC端页面放到M端,会呈现出怎样的情况:

 看到了么,此时页面到了M端以后,不会强行的去缩放里面的内容,而是根据布局视口的大小去进行css布局,由于布局视口比视觉视口(浏览器的宽度)大很多,就出现了滚动条。所以,通过滚动页面你可以清楚的看到页面的整个内容了。但是,这还不是我们想要的M端页面,我们想要怎样一种效果呢?应该是这样:我们不想页面出现滚动条,而且想要页面所有的内容都呈现在我们的视野范围内。即要是我们能够自己去控制M端布局视口的大小就好了,让它以一个用户比较舒适的大小呈现在屏幕上,标签帮我们完成了这一举动,让我们继续看看吧。

meta:

 最初是由苹果公司提出的,后来被多家浏览器厂商复制。其目的是为了调整M端布局视口的大小,以适应各种宽度的移动设备。该标签应该置于标签内,其语法如下所示:

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" user-scalable=no>

 是不是很熟悉,对啦,我们在文章的开头时曾写过。关于viewport我们不再解释,下面简单说一下content里面的内容。content属性的值是一个字符串,字符串里面的内容是由逗号隔开的名值对,一共5个:

  1. width:布局视口的宽度,可以自己设定准确的值如width=300,也可以是一些特殊值,如width=device-width,顾名思义就是设备的宽度
  2. initial-scale:设置页面的初始缩放程度,可以是小数
  3. minimum-scale:设置页面的最小缩放程度
  4. maximum-scale:设置页面的最大缩放程度
  5. user-scalable: 是否允许用户对页面进行缩放

 所以,列子中代码的含义就是,设置布局视口的宽度为设备的宽度,页面的初始缩放比例、最小缩放比例以及最大缩放比例值为1,不允许用户缩放页面。

 好了,写到这里,大家或多或少对有了一定的了解吧,下面我们就开始真正的移动端页面开发了,哈哈哈,费了老大劲儿解释,但是我觉得很有必要吧。

移动端页面开发:

&承接上面的需求,我们在750px的设计稿(其实这也是现在iPhone6/7的设计稿样子)上看到了一个宽高都是200px的绿色矩形框,如下图所示:

 于是我们这样设计代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>移动端页面开发</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .weekend {
            width: 200px;
            height: 200px;
            background-color: green;
        }
    </style>
</head>
<body>
    <div class="weekend"></div>
</body>
</html>

 效果如下所示:

image

 咋一看,哎,不对呀,矩形框的宽高没有问题,但是设计稿上的设备宽度是750,而浏览器显示的宽度则是375,这是怎么回事呢。其实,设计稿是按照设备像素去设计的,所以在页面缩放比为1的情况下,根据公式:

DPR = 设备像素/视觉视口css像素个数(device-width)

 在iphone7上DPR=2,所以1个css像素等效于2个设备像素,所以对于矩形框的宽度,应该设为200/2=100px,当然对于其他的DPR值,我们应该用设计稿上的设备像素/DPR,得到真正应该得到的css像素。但是,如果我们不想每次都去计算真正的css像素值,而是让浏览器自动去计算呢。别忘了,我们前面提到的中content的 值initial-scale,它缩放的是css的像素,所以利用这个特性,设置initial-scale = 1/DPR,此时M端一个设备像素就等于一个css像素了,这样我们就可以直接将设计稿上的像素值设为css的像素值,而不用人为的去计算了。代码如下: (多说一句,利用window.devicePixelRatio可以获取设备的DPR值)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>移动端页面开发</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .weekend {
            width: 200px;
            height: 200px;
            background-color: green;
        }
    </style>
</head>
<body>
    <div class="weekend"></div>
    <script>
        var scale = 1/window.devicePixelRatio;
        document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=' + scale + ', user-scalable=no')
    </script>
</body>
</html>

 效果如下所示:

 这下好了,好像达到我们想要的效果了,可是为什么说好像呢,看到这里的朋友不知道有没有想过这样一个问题,假如现在你不是iphone7的设备,而是iphone5,他们的DPR值都为1,但是设备的宽度却是不一样的。然而我们的代码设计并没有考虑到这样的情况,我们来验证下这个想法,用iphone5看一下页面效果,如下所示:

 果然,iphone5上还是100px,这该如何是好呢?我们应该留意到了这样一个现象,随着设备的宽度在变化,因为我们设置了页面布局视口的宽度值等于device-width,而html的宽度又是由布局视口所决定的(document.documentElement.clientWidth),所以只要我们想到有什么办法能让页面中元素的宽度能够随着根元素的变化而变化,这样我们就能够达到想要的效果了。是的,没错,就是rem,我想对于rem这个概念应该并不陌生吧。简单来说,rem是一个相对单位,是相对于html字体大小的单位。举个例子:  当我们设置html {font-size: 10px}时,设置页面某个div {width: 2rem},此时div经过计算后的宽度就等于2*10即20px。所以,通过rem的这个功能,我们就可以实现我们想要的效果了。开始写吧,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>移动端页面开发</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .weekend {
            width: 2.666667rem;
            height: 2.666667rem;
            background-color: green;
        }
    </style>
</head>
<body>
    <div class="weekend"></div>
    <script>
        var scale = 1/window.devicePixelRatio;
        document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=' + scale + ', user-scalable=no');
        document.documentElement.style.fontSize = document.documentElement.clientWidth / 10;
    </script>
</body>
</html>

 代码修改的地方有两处,一个是script里面,添加了一个修改根元素fontSize的语句,为什么要除以100呢,因为直接取document.documentElement.clientWidth的值感觉有点略大了,这个标准孙便设计的,想怎么来怎么来。==但是有个地方我们得注意一下:==就是font-size的最小值问题,我们不能设置得太小否则无效== 。另外一个地方就是style里面css样式,因为是750px的设计稿,所以width值设置为200/(750/100),同样如果是640px的设计稿,就是200/(640/100),哈哈,大功告成,我们来看一看效果:

 终于,大功告成,真是不容易啊,可是,这个真的就是最佳的解决方案么?那可未必。你们看,我们在设置css的样式的时候,需要用设计稿上的样式去除以fontSize转化后的值,比如说750的设计稿,就要除以75;640的设计稿就要除以64,毕竟这些值不是什么容易除尽的值,所以计算起来还比较麻烦。那有没有什么解决方案呢?哈哈哈,办法总比困难多,根据网上有人提出的解决方案,完美的解决了这个问题,其实就一句话,我这里不做解释,留给各位自己去体会,相信在前面介绍的基础上,这段代码是很容易解释的,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="">
    <title>移动端页面开发</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .weekend {
            width: 2rem;
            height: 2rem;
            background-color: green;
        }
    </style>
</head>
<body>
    <div class="weekend"></div>
    <script>
        document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + 'px';
    </script>
</body>
</html>

 就一句话,巧妙的解决了移动端设计的问题,对于设计稿上的宽度,只要除以100即可。

写在最后:

 终于,这篇文章算是完结了,花了自己一个周六的时间,当然里面关于最后移动端页面的设计思路是对别人文章的很大借鉴,但是整体很多地方都有自己的想法总结与移动端知识的延伸。其实,我们再来看M端,无外乎两个方面是我们需要考虑的问题:一个是移动端一个css像素和一个设备像素的对等关系,一个是不同设备的宽度自适应问题。知道怎么去解决这两个问题,那么你就算是基本上掌握了移动端页面设计的主要思想。当然,不管是对别人借鉴也好,还是自己领悟也好,主要是自己对这部分知识点有所掌握,能够站在自己的角度独立完成这篇总结,对我而言也是极好的。里面有些说得不正确的地方,还望各位读者指出,谢谢~

参考资料:

A tale of two viewports — part one

A tale of two viewports — part two

一篇真正教会你开发移动端页面的文章(1)

一篇真正教会你开发移动端页面的文章(2)