往前推2到3年,前端工程师还在忧心忡忡地想,移动互联网时代下,前端是不是没有生存空间了。但今天一看,在我们团队,前端工程师超过一半的工作都是在做移动端的Web或者APP的开发。移动Web或者APP在技术本质上是和做桌面端Web没有本质区别,但是移动端的坑那是非常的多,通过学习这部分内容,让你成为一名桌面移动通吃的前端开发工程师。
概念
- 参考: 移动 Web 开发入门
上面这个 slide 资料讲的非常好,算是一个入门的介绍吧。带我们建立基本的移动 web 开发知识体系和常见问题的实践。包含以下几个方面:
- 基本概念
- Native 本地应用 使用 Java Objective-C Swift 开发
- WebApp 网页应用 html5 开发
- Hybrid 混合应用 ooxx(native, web)
- 对比
- 视觉
- 设备的像素
- 文字单位使用 rem
- viewport 属性
- 横屏竖屏
- Flex 伸缩布局
- 响应式设计
- 软键盘
- 隐藏地址栏
- 苹果设备添加到主屏图标
- 交互
- Touch
- click 延迟
- Scroll
- Gestures(hammer —A javascript library for multi-touch gestures)
- 手指友好设计
- HTML5 APIS(图像,摇动,声音等)
- 实践
- 屏蔽点击元素时的阴影
- 图像(像素、矢量图标、base64 减少请求、lazyload)
- CSS3(合理使用渐变/圆角/阴影、代替 js 动画、translate3d、解决动画闪烁)
- localStorage
- 避免(iframe、fixed input)
- SPA 或 Multi page
- can I use
- 压缩合并
- @G/3G 下建立连接时间
- 调试
- 浏览器自己的调试工具,模拟手机设备
- weinre 关于 weinre 我写了一篇博客介绍它。Weinre —WebApp 调试工具
head 标签
参考:
- 移动前端不得不了解的html5 head 头标签
上面的链接详细的讲解了:
- DOCTYPE
- charset
- lang属性
- 优先使用 IE 最新版本和 Chrome
- 360 使用Google Chrome Frame
- SEO 优化部分:页面标题标签(head 头部必须),页面关键词 keywords,页面描述内容 description,定义网页作者 author,网页搜索引擎索引方式
- 为移动设备添加 viewport
viewport
可以让布局在移动浏览器上显示的更好。 通常会写
<meta name ="viewport" content ="initial-scale=1, maximum-scale=3, minimum-scale=1, user-scalable=no">
<!-- `width=device-width` 会导致 iPhone 5 添加到主屏后以 WebApp 全屏模式打开页面时出现黑边 http://bigc.at/ios-webapp-viewport-meta.orz -->
- content 参数:
- width viewport 宽度(数值/device-width)
- height viewport 高度(数值/device-height)
- initial-scale 初始缩放比例
- maximum-scale 最大缩放比例
- minimum-scale 最小缩放比例
- user-scalable 是否允许用户缩放(yes/no)
- ios 设备,iOS 图标,Android,Windows 8
总结:
代码语言:javascript复制<!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 -->
<html lang="zh-cmn-Hans"> <!-- 更加标准的 lang 属性写法 http://zhi.hu/XyIa -->
<head>
<!-- 声明文档使用的字符编码 -->
<meta charset='utf-8'>
<!-- 优先使用 IE 最新版本和 Chrome -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<!-- 页面描述 -->
<meta name="description" content="不超过150个字符"/>
<!-- 页面关键词 -->
<meta name="keywords" content=""/>
<!-- 网页作者 -->
<meta name="author" content="name, email@gmail.com"/>
<!-- 搜索引擎抓取 -->
<meta name="robots" content="index,follow"/>
<!-- 为移动设备添加 viewport -->
<meta name="viewport" content="initial-scale=1, maximum-scale=3, minimum-scale=1, user-scalable=no">
<!-- `width=device-width` 会导致 iPhone 5 添加到主屏后以 WebApp 全屏模式打开页面时出现黑边 http://bigc.at/ios-webapp-viewport-meta.orz -->
<!-- iOS 设备 begin -->
<meta name="apple-mobile-web-app-title" content="标题">
<!-- 添加到主屏后的标题(iOS 6 新增) -->
<meta name="apple-mobile-web-app-capable" content="yes"/>
<!-- 是否启用 WebApp 全屏模式,删除苹果默认的工具栏和菜单栏 -->
<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">
<!-- 添加智能 App 广告条 Smart App Banner(iOS 6 Safari) -->
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<!-- 设置苹果工具栏颜色 -->
<meta name="format-detection" content="telphone=no, email=no"/>
<!-- 忽略页面中的数字识别为电话,忽略email识别 -->
<!-- 启用360浏览器的极速模式(webkit) -->
<meta name="renderer" content="webkit">
<!-- 避免IE使用兼容模式 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 -->
<meta name="HandheldFriendly" content="true">
<!-- 微软的老式浏览器 -->
<meta name="MobileOptimized" content="320">
<!-- uc强制竖屏 -->
<meta name="screen-orientation" content="portrait">
<!-- QQ强制竖屏 -->
<meta name="x5-orientation" content="portrait">
<!-- UC强制全屏 -->
<meta name="full-screen" content="yes">
<!-- QQ强制全屏 -->
<meta name="x5-fullscreen" content="true">
<!-- UC应用模式 -->
<meta name="browsermode" content="application">
<!-- QQ应用模式 -->
<meta name="x5-page-mode" content="app">
<!-- windows phone 点击无高光 -->
<meta name="msapplication-tap-highlight" content="no">
<!-- iOS 图标 begin -->
<link rel="apple-touch-icon-precomposed" href="/apple-touch-icon-57x57-precomposed.png"/>
<!-- iPhone 和 iTouch,默认 57x57 像素,必须有 -->
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/apple-touch-icon-114x114-precomposed.png"/>
<!-- Retina iPhone 和 Retina iTouch,114x114 像素,可以没有,但推荐有 -->
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/apple-touch-icon-144x144-precomposed.png"/>
<!-- Retina iPad,144x144 像素,可以没有,但推荐有 -->
<!-- iOS 图标 end -->
<!-- iOS 启动画面 begin -->
<link rel="apple-touch-startup-image" sizes="768x1004" href="/splash-screen-768x1004.png"/>
<!-- iPad 竖屏 768 x 1004(标准分辨率) -->
<link rel="apple-touch-startup-image" sizes="1536x2008" href="/splash-screen-1536x2008.png"/>
<!-- iPad 竖屏 1536x2008(Retina) -->
<link rel="apple-touch-startup-image" sizes="1024x748" href="/Default-Portrait-1024x748.png"/>
<!-- iPad 横屏 1024x748(标准分辨率) -->
<link rel="apple-touch-startup-image" sizes="2048x1496" href="/splash-screen-2048x1496.png"/>
<!-- iPad 横屏 2048x1496(Retina) -->
<link rel="apple-touch-startup-image" href="/splash-screen-320x480.png"/>
<!-- iPhone/iPod Touch 竖屏 320x480 (标准分辨率) -->
<link rel="apple-touch-startup-image" sizes="640x960" href="/splash-screen-640x960.png"/>
<!-- iPhone/iPod Touch 竖屏 640x960 (Retina) -->
<link rel="apple-touch-startup-image" sizes="640x1136" href="/splash-screen-640x1136.png"/>
<!-- iPhone 5/iPod Touch 5 竖屏 640x1136 (Retina) -->
<!-- iOS 启动画面 end -->
<!-- iOS 设备 end -->
<meta name="msapplication-TileColor" content="#000"/>
<!-- Windows 8 磁贴颜色 -->
<meta name="msapplication-TileImage" content="icon.png"/>
<!-- Windows 8 磁贴图标 -->
<link rel="alternate" type="application/rss xml" title="RSS" href="/rss.xml"/>
<!-- 添加 RSS 订阅 -->
<link rel="shortcut icon" type="image/ico" href="/favicon.ico"/>
<!-- 添加 favicon icon -->
<title>标题</title>
</head>
<body>
</body>
</html>
页面切换动画
- 移动端重构系列13——页面切换
- CSS3 3D Transform
关于 HammerJS 的一个中文文档
- Hammer.js
CSS Processing
CSS语言由于其自身语言设计的问题,加上一些浏览器兼容性问题,往往会使得我们在写它的时候,要写很多冗余代码,或者为了兼容性对同一个样式设定写好几遍。针对这些问题,诞生了CSS预处理和后处理的概念及相关方法、工具。 这些工具和方法帮助我们能够更加高效地书写可维护性更强的CSS代码。
这里我尝试使用了 Sass,果然很好用。下面记录几个 sass 教程。
- Sass入门-w3cplus
- SASS用法指南-阮一峰
安装
首先要有 ruby 环境。
由于国内网络原因(你懂的),导致 rubygems.org 存放在 Amazon S3 上面的资源文件间歇性连接失败。这时候我们可以通过gem sources命令来配置源,先移除默认的 https://rubygems.org 源,然后添加淘宝的源 https://ruby.taobao.org/,然后查看下当前使用的源是哪个,如果是淘宝的,则表示可以输入 sass 安装命令 gem install sass
了。
$ gem sources --remove https://rubygems.org/
$ gem sources -a https://ruby.taobao.org/
$ gem sources -l
*** CURRENT SOURCES ***
https://ruby.taobao.org
# 请确保只有 ruby.taobao.org
$ gem install sass
编译
代码语言:javascript复制sass --watch style.scss:style.css --style expanded
补充
rem
字体单位使用 rem,用户在手机上设置了字体大小时,不会打破布局,造成混乱。
- CSS3的REM设置字体大小-w3cplus
- 响应式十日谈第一日:使用 rem 设置文字大小-一丝
安全
安全是大家经常容易忽视,但其实一旦出现影响会非常大的问题,尤其对于没有经历过企业开发,或者没有踩过坑的同学,如果等到公司工作,做实际项目后非常容易发生安全问题。
分类
WEB基本攻击大致可以分为三大类:“资源枚举”、“参数操纵” 和 “其它攻击”
- 资源枚举
- 参数操纵
- SQL注入
- XPath注入
- cgi命令执行
- XXS(cross-site scripting跨域脚本攻击)其重点是“跨域”和“客户端执行”
- Reflected XSS ——基于反射的XSS攻击。主要依靠站点服务端返回脚本,在客户端触发执行从而发起WEB攻击。
- DOM-based or local XSS——基于DOM或本地的XSS攻击
- Stored XSS——基于存储的XSS攻击
- 会话劫持
- 其它攻击
- CSRF(cross-site request forgery)跨站请求伪造
- 钓鱼攻击指的是网站的伪造,比如ta0bao.com,然后在其中应用XSS等方式发起攻击。
- 拒绝服务(DoS)指的是向网站发起洪水一样的请求(Traffic Floor),导致服务器超负荷并关闭,处理方法常规是采用QoS(Quality of Service)的软硬件解决方案。
关于 XSS
跨网站脚本(Cross-site scripting,通常简称为XSS或跨站脚本或跨站脚本攻击)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。 XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。 ——维基百科
XSS 防护
- 浏览器解析顺序: HTML Parser >> CSS Parser >> JavaScript Parser
- 浏览器解码顺序: HTML Decoding >> URL Decoding >> JavaScript Decoding
- 具体的防护方式:
- 验证输入并且基于语境和按照正确的顺序转义不可信数据
- HTML 中的字符串
- HTML 属性中的字符串
- 事件句柄属性和 JavaScript 中的字符串
- HTML 属性中的 URL 路径
- HTML 风格属性和 CSS 中的字符串
- JavaScript 中的 HTML
- 始终遵循白名单优于黑名单的做法
- 使用 UTF-8 为默认的字符编码以及设置 content 为 text/html
- 不要将用户可以控制的文本放在标签前。通过使用不同的字符集注射可以导致 XSS。
- 使用 <!DOCTYPE html>
- 使用推荐的 HTTP 响应头进行 XSS 防护
- 防止 CRLF 注入/HTTP 响应拆分
- 禁止 TRACE 和其他非必要方法
- 验证输入并且基于语境和按照正确的顺序转义不可信数据
对于 innerHTML 的方式输出的,我们可以采用如下的方式转码
代码语言:javascript复制/**
* 转码 XSS 防护
* @param {String} str 用户输入的字符串
* @return {String} 转码后的字符串
*/
function changeCode(str) {
str = str.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
.replace(///g, "/");
return str;
}
参考:
- 浅谈WEB安全性(前端向)
- XSS的原理分析与解剖
- 原创翻译:给开发者的终极XSS防护备忘录
性能优化
在自己做一些小项目时,可能是学校的一些网站项目,流量可能日均都不超过500,而且大多是校园局域网内访问;或者是开发一些实验室的MIS系统,这辈子你都不会去使用你开发的这个系统。在这样一些项目中,性能优化往往会被你忽略。 但是如果你是做一个日均PV数万、数十万、甚至更大的量级,开发的页面会被全国各地,不同网络条件的用户来进行访问。这个时候,性能问题就无法忽视了。在当今的网络条件下,如果你的页面3秒都无法完成首屏渲染,一定会让你的网站流失很多用户。 整个网站的性能优化有很多的环节和工作,大多数时候,不是前端工程师单独就能完成的,尤其在职能划分明确的公司中,往往需要前后端、运维、DBA等多个职位协同完成。所以,在我们的课程中,主要让你了解整个性能优化都涉及哪些方面的工作,同时,我们会专注介绍一些在前端领域可以重点关注的技术点。
这里就是网页的打开速度,如果你的网页打开速度很慢,那么一定会有用户的流失。所以性能优化很重要。
- 网页内容
- 减少http请求次数
- 减少DNS查询次数
- 避免页面跳转
- 缓存Ajax
- 延迟加载
- 提前加载
- 减少DOM元素数量
- 根据域名划分内容
- 减少iframe数量
- 避免404
- 服务器
- 使用CDN
- 添加Expires 或Cache-Control报文头
- Gzip压缩传输文件
- 配置ETags
- 尽早flush输出
- 使用GET Ajax请求
- 避免空的图片src
- Cookie
- 减少Cookie大小
- 页面内容使用无cookie域名
- CSS
- 将样式表置顶
- 避免CSS表达式
- 用<link>代替@import
- 避免使用Filters
- Javascript
- 将脚本置底
- 使用外部Javascirpt和CSS文件
- 精简Javascript和CSS
- 去除重复脚本
- 减少DOM访问
- 使用智能事件处理
- 图片
- 优化图像
- 优化CSS Sprite
- 不要在HTML中缩放图片
- 使用小且可缓存的favicon.ico
- 移动客户端
- 保持单个内容小于25KB
- 打包组建成符合文档
具体细节参考文章:
- 毫秒必争,前端网页性能最佳实践
我在 ToDo 这个任务中主要使用了 CDN 来加载静态资源。比如我使用了 百度静态资源公共库。引用了里面的 fontawesome,速度果然比在 GitHub 仓库里快很多。下一步是压缩我自己写的静态资源。
其他参考资料:
- 给网页设计师和前端开发者看的前端性能优化
- 梳理:提高前端性能方面的处理以及不足
- css sprite原理优缺点及使用
- CSS Sprites:鱼翅还是三鹿?
- 大型网站的灵魂——性能
- 编写高效的 CSS 选择器
模块化
对于一个复杂项目,特别是多人协作的复杂项目,如何合理划分模块,如何更加方便地进行模块加载,如何管理模块之间的依赖,是一个项目团队都会面临的问题,目前业界已经有了一些较为普遍的解决方案,如AMD。这个部分希望你能够通过学习JavaScript的模块化,学习如何合理地规划项目模块,合理使用模块化工具来优化你的项目代码结构。
一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,否则就都乱套了。
根据AMD规范,我们可以使用 define
定义模块,使用 require
调用模块。
目前,通行的 js 模块规范主要有两种:CommonJS
和 AMD
。
AMD规范
AMD 即 Asynchronous Module Definition,中文名是“异步模块定义”的意思。它是一个在浏览器端模块化开发的规范,服务器端的规范是 CommonJS
模块将被异步加载,模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。
AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出。
详细 API 如下:
- AMD(中文版))
CommonJS规范
CommonJS 是服务器端模块的规范,Node.js 采用了这个规范。Node.JS 首先采用了 js 模块化的概念。
根据 CommonJS 规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为 global 对象的属性。
输出模块变量的最好方法是使用 module.exports 对象。
为什么要用 requireJS
试想一下,如果一个网页有很多的js文件,那么浏览器在下载该页面的时候会先加载js文件,从而停止了网页的渲染,如果文件越多,浏览器可能失去响应。其次,要保证js文件的依赖性,依赖性最大的模块(文件)要放在最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
RequireJS就是为了解决这两个问题而诞生的:
(1)实现js文件的异步加载,避免网页失去响应; (2)管理模块之间的依赖性,便于代码的编写和维护。
requireJS
- requireJS 官网
- requireJS 中文网
AMD和CMD
CMD(Common Module Definition) 通用模块定义。该规范明确了模块的基本书写格式和基本交互规则。该规范是在国内发展出来的。AMD是依赖关系前置,CMD是按需加载。
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。 CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
- CMD 模块定义规范
对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
AMD:提前执行(异步加载:依赖先执行) 延迟执行 CMD:延迟执行(运行到需加载,根据顺序执行)
参考
- Javascript模块化编程(一):模块的写法—阮一峰
- Javascript模块化编程(二):AMD规范
- Javascript模块化编程(三):require.js的用法
- 详解 JavaScript 模块开发
- 浅谈模块化的JavaScript
- 再谈 SeaJS 与 RequireJS 的差异
- 玩转AMD系列 by erik@EFE
- 玩转AMD - 写在前面
- 玩转AMD - 设计思路
- 玩转AMD - 应用实践
- 玩转AMD - Loader
前端工程化
业界目前有非常多的前端开发工具,完成一些开发过程中可以自动化完成的工作,提高研发效率,并且可以提高多人协作时的开发过程一致性,提高整个项目的运维效率。 在EFE日常工作中,我们是基于EDP,完成项目开发过程中的项目构建、包管理、调试、单测、静态检测、打包、压缩、优化、项目部署等一系列所有工作。
注:
如果网络不好,可以使用 淘宝 NPM 镜像。
参考
- 前端工程与模块化框架
- 手机百度前端工程化之路
- 对话百度前端工程师张云龙:F.I.S与前端工业化
- EDP
- Grunt教程——初涉Grunt
- gulp入门指南
- Gulp开发教程(翻译)
- Gulp 中文网
- npm的package.json中文文档
最终作品
在任务三中,做了一个 PC 端的 ToDo 应用。任务四是将它优化,以适应移动端设备。
ToDo WebApp Version
- 任务四要求
- 源代码
- 在线 demo
- 我的博客 HyG
Details
数据存储
代码语言:javascript复制 使用数据库的思想,构建3张表。
cateJson 分类
childCateJson 子分类
taskJson 任务
分类表 cate
----------------------
id* | name | child(FK)
----------------------
子分类表 childCate
--------------------------------
id* | pid(FK) | name | child(FK)
--------------------------------
任务表 task
----------------------------------------------
id* | pid(FK) | finish | name | date | content
----------------------------------------------
使用 Sass
重构了 CSS 代码
响应式布局
加入页面切换效果
处理了 XSS 防护
性能优化
模块化
前端工程化
其他
-webkit-tap-highlight-color
属性
感谢 fiona 指出。
safari移动端点击的时候会闪一下加上 -webkit-tap-highlight-color: transparent;
就不会闪了。
参考:
-webkit-tap-highlight-color
css88-webkit-tap-highlight-color
属性
textarea 标签 disabled 颜色
- 为什么用 disabled 属性? 因为我发现仅仅使用 readonly 属性,在 IE 下是显示光标的。于是使用 disabled。
- 出现的问题 各家浏览器对于 disabled 属性有自己的样式设定,比如 IE 下是灰色的。苹果设备下也是。改变这些样式的方法也不是统一的。如果要兼容 Safari 必须加上
background: #fff;
-webkit-text-fill-color: rgba(0, 0, 0, 1);
-webkit-opacity: 1;
于是最终代码如下:
代码语言:javascript复制textarea:disabled {
color:#000;
background: #fff;
-webkit-text-fill-color: rgba(0, 0, 0, 1);
-webkit-opacity: 1;
}
- 参考:Disabled input text color 中的评论