近年来, 人们逐渐倾向移动端的使用. 越来越多的人使用手机/平板来上网. 既然有需求, 那就自然会有市场~ 作为一个身在一线的前端工程师在工作中也难免会遇到这种场景/需求. 下面就分享一下对于移动端的一些学习笔记~
移动端基础的知识
移动端的屏幕相比 PC 来说多的太多了, 因此我们不能只是使用传统的 px, 首先来认识一下我们常用的单位吧.
- px: css pixels 逻辑像素, 浏览器使用的抽象单位
- dp, pt: device independent pixels 设备无关像素
- dpr devicePixelRatio 设备像素缩放比
它们之间的计算公式是: 1px = (dpr)² * dp
这里我们用 IPhone 5 为例, 我们知道, iPhone 5 的dpr
为 2, 根据上面的公式, 我们能得出:
平面上: 1px = (2)² * dp
=> 1px = 4dp(四个物理像素)
但我们在实际的开发中, 更多的是按照长度(维度)来换算:
维度上: 1px = dpr * dp
=> 1px = 2 * dp
因此在移动端开发的时候. 我们拿到 UI 的设计图, 设计图(IPhone5)的尺寸是640 * 1136
. 这是因为dpr
的缘故. 因此我们需要在开发时, 将原先的宽度除于 2 才行.
还有我们常说的Retina
屏又是什么? Retina屏(高清屏幕)
就是dpr <= 2
.
viewport
viewport, 就是视图窗口. 其中它在手机上又分为一下两个窗口.
- Visual viewport (可视窗口)
- Layout viewport (布局窗口)
最下面一层就是layout viewport
, 上面一层就是visual viewport
, visual viewport
可以控制窗口的缩放(salce), 能看得到更多底层的layout viewport
的东西.
这里值得注意的是, layout viewport
的宽度是大于浏览器可视区域的宽度的.
meta
如果我们没有限制viewport
的缩放比的话. 我们通过获取window.innerWidth(布局窗口) / document.body.clientWidth
的缩放比得知, 设备会根据页面的大小, 自动的去调整缩放比. 这就会不符合我们的预期.
这时我们可以通过Meta
标签来控制viewport
. 它的语法如下:
1 | <meta name="viewport" content="name=value,name=value" /> |
参数如下:
width
: 设置布局 viewport 的特定值(“device-width”)initial-scale
: 设置页面的初始缩放minimum-sacle
: 最少缩放maximum-scale
: 最大缩放user-scalable
: 用户能否缩放
目前主流的编辑器在使用emmet
生成基本HTML
模板时都会自带插入一句
1 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
而有时候我们不希望用户能控制页面的搜索,那我们就可以设置user-scalable
为no
, 百度就是如下的做法:
1 | <meta |
移动端布局
移动端的布局就能不像 PC 端一样用固定宽度了, 因为移动端有太多不同的屏幕分辨率了.. 因此现在主流的布局方式还是响应式布局和 flex 布局. 未来还有 Grid 布局, 不过现在普及度不够高暂时放放, 以后有机会单独开一篇.
响应式布局
响应式布局实际上是一个设计理念, 它是多项技术的综合体. 其核心就是媒体查询(@media).
响应式网站的优点主要有:
- 减少工作量: 代码, 设计, 内容只需要一份. 多出的工作也仅仅是 js 和 css 样式的调整.
- 相对来说会节省时间
- 每个设备都能得到正确的设计
相反, 它也带有一些副作用(缺点):
- 由于我们是响应式布局, 需要加载更多的样式和脚本资源
- 设计比较难精准定位和控制
- media实际上是 css3 的玩意, 对老版本浏览器兼容不好(特指 IE)
接着我们继续看看响应式设计着重的几个点吧:
关于响应式设计中针对不同分辨率的媒体查询设计, 可以看我 Repo 中的这一块.
百分比布局
仅仅使用媒体查询来适应不同的固定宽度设计, 只会从一组 css 到另一组 css 的切换. 两组之间没有任何平滑渐变. 当没有命中媒体查询时, 表现就会不可控.就比如说 iPhone 又出了个 iPad mini, 这个设备的宽度介于 iphone 和 ipad 之间. 这样就有可能会导致布局的错乱, 我们应该要尽量避免这种情况发生.
弹性图片
很简单也很常见的思路. 图片设置宽度 100%, 外层一个 div 包裹着, div 设置宽度, 可以随着媒体查询改变宽度 从而实现自适应
1
2
3img {
max-width: 100%;
}当页面达到手机屏幕宽度的时候, 我们可以考虑放弃一些传统页面的设计思想. 力求页面简单, 简洁(手机屏幕小). 因此需要作出以下处理:
- 同比例缩减元素尺寸
- 调整页面结构布局
- 隐藏冗余的元素
除此之外, 应该将经常需要切换位置元素使用「绝对定位」, 减少重绘提高渲染性能.
一般我们根据屏幕的尺寸进行响应式设计:
- 0~480: 小屏幕
- 481~800: 中屏幕
- 801~1400: 大屏幕
- 1400+: 巨屏幕
Flex 布局
Flexbox
的出现是为了解决复杂的 web 布局,因为这种布局方式很灵活。容器的子元素可以任意方向进行排列. 有效的针对不同屏幕宽度大小的情况下,让元素自动有效合理处理布局结构。
Flex
在移动布局上已经运用的很广泛了. 比如我们常见的垂直居中, 原先需要好几行代码的效果, 现在就一行align-items: center
就能解决了, 十分便利.
Flex
网上已经有太多的详细教程了. 考虑到篇幅限制, 这边也就不再过多的赘述了. 不过值得一提的是, Flexbox
是有新旧两个版本的, 新的是display: flex
, 旧的(2009 年的语法)是display: box
; 两者作用都差不多, 只是使用的属性名有些差异, 如果要兼容低版本的浏览器的话可以考虑后者.
扩展阅读:
[张鑫旭]CSS box-flex 属性,然后弹性盒子模型简介: http://www.zhangxinxu.com/wordpress/?p=1338
Flex 入门: http://ife.baidu.com/note/detail/id/952
Flexbox 详解: https://segmentfault.com/a/1190000002910324
移动端一些常见的坑
1px border
这个问题常出现在 ios 下, 其根本原因还是retina屏
的问题. 1px
使用了2dp
渲染, 因此看上去就会粗一点.
常见的解决方案有以下几个:
背景渐变
CSS3 有了渐变背景,可以通过渐变背景实现 1px 的 border,实现原理是设置 1px 的渐变背景,50% 有颜色,50% 是透明的。
1 | @mixin commonStyle() { |
缺点就是没办法实现圆角.
使用 scale 缩放 0.5 倍:
1 | .sidebar .folder li { |
多行文本溢出
webkit 内核的浏览器可以尝试使用-webkit-line-clamp
, 可惜兼容性不高.
1 | .intwoline { |
终端交互优化
最近几年,爆炸式的移动 Web 浏览器的使用打破了这个途径。低带宽,高延迟,小内存,低处理器性能的移动设备环境,迫使开发者不得不想办法通过优化前端页面的性能来满足用户的性能预期。
300 毫秒的故事
移动 web 页面上的 click 事件响应都要慢上 300ms
移动设备访问的 web 页面都是 pc 上的页面. 在默认的 viewport(980px)
的页面往往都是需要”双击”或”捏开”放大页面, 来看清页面. 正是为了确定用户是”双击”还是”单击”. sofari 需要个 300ms 的延迟来判断. 而后来的 Iphone 也一直沿用这样的设计, 没借鉴成功 iPhone 的 android 也沿用了这样的设计. 于是”300ms 的延迟”就成为了一道规范.
因此针对这个延迟, 出现了使用 tap 基础事件去代替 click 事件. 已经有成熟的类库去帮我们实现了, 这也不展开讲.
移动端的事件
现在智能手机的普及, 触摸成为了移动设备的交互的核心事件, 主要有这几种常用的事件
• Touchstart: 手指触摸屏幕触发(只有第一下才会触发)
• Touchmove: 手指在屏幕滑动, 连续触发
• Touchend: 手指离开屏幕时触发
• Touchcanel: 系统取消 touch 时候触发(不常用)
除了常见的事件属性外, 触摸事件也有自己专有的触摸属性:
- touches: 跟踪触摸操作的 touch 对象数组
- targetTouches: 特定时间目标的 touch 对象数组
- changeTouches: 上次触摸改变的 touch 对象数组
其中touches
是最为常用的. 它是一个数组, 包含着几个 touch 对象, 每个 touch 对象包含如下属性:
• clientX: 触摸目标在视口中的 x 坐标
• clientY: 触摸目标在视口中的 y 坐标
• Identifier: 标识触摸的唯一 ID
• pageX: 触摸目标在页面中的 x 坐标.
• pageY: 触摸目标在页面中的 y 坐标.
• screenX: 触摸目标在屏幕中的 x 坐标
• screenY: 触摸目标在屏幕中的 y 坐标
• target: 触摸的 DOM 节点目标
不过值得注意的是 Android 下可能会有 touchend 不触发的 bug, 已知 Android 4.0, 4.1, 4.4 ~ 5.0 都有这个 bug.
弹性滚动
当客户端的页面滚动到底部或顶部的时候, 滚动条会允许我们再向上(下)拖, 松开就会有缓冲反弹的效果, 能有一个良好的用户体验.
移动 web 页面也有这样的能力. 但是滚动有几种情况需要考虑(副作用):
- body 层滚动: (系统特殊化处理)
自带弹性滚动, overflow:hidden 失效, GIF 和定时器暂停 - 局部滚动: 没有弹性滚动, 没有滚动惯性, 不流畅
而局部滚动开启弹性滚动的方式也很简单, 只需要在 body 上添加如下的代码:
1 | body { |
上拉刷新, 下拉加载
在移动端, 我们常常能看到这种 —— 顶部会允许下拉一小点距离, 松开时页会有弹性的滚动向下, 并且加载数据. 这是一种良好的交互. 多数类库或者插件都能实现这种效果. 可惜本人移动端的经验不足, 没有自己去实现过一次. (再占一个坑吧~
总结
移动端与 PC 端的开发主要还是着重点不同吧. 比如在移动开发时, 我们必须要考虑用户的流量, 并不是所有人都在用着好的 WIFi 来上网.
其中如何在这个小屏幕下给用户带来良好的体验也是另外一门学问. 本文只是总结一些常见的东西, 比如移动端适配也还没有讲. 如果以后自己的工作重心倾向移动端的话, 就会继续再更新相关的内容吧~
参考资料: