移动端设计稿尺寸:750*1334 (iphone6)
为标准
设备像素比:
设备物理像素和设备独立像素的比例; 也就是 DPR = 物理像素 / 设备独立像素 iphone6以下 dpr=2
可以通过 window.devicePixelRatio
来获取
移动布局开发准备工作
一、搭建本地静态html
页面服务器
# 1. 全局安装 http-server
npm i -g http-server
# 2. 在项目文件夹下: 执行 npm init -y 得到 package.json 文件, 然后配置 script
"script": {
"dev": "http-server ./ -o --port 8089"
}
# 启动服务
npm run dev
二、VSCode编辑设置 LESS 自动编译成 CSS
/* #步骤:
* 1. 在扩展中安装 Easy LESS 插件 (切记插件名没有中横杆)
* 2. 在设置中找到 setting.json 文件进行一下配置
*/
"less.compile": {
"compress": false, // 是否压缩
"sourceMap": false, // 是否生产map文件,可在控制台看到less行数
"out": "${workspaceRoot}\css\",
"outExt": ".css" // 输出文件后缀, 小程序可以写 .wxss
}
三、VSCode编辑器安装插件输入 px
提示 rem
转换值
一般UI给我们的稿子大小是750的。就以这个为例子:在flexible.js中,把750px分为10份,1rem 为 75px。所以font-size的基准值为75px;
css换算成rem公式为: px值 / 75 = rem, 例如:100px=100/75=1.33rem
/* #步骤:
* 1. 在扩展中安装 cssrem 插件
* 2. 选项 -> 设置 -> 扩展下的cssrem 设置基准 foot-size 为 75
*/
四、使用iconfont
字体图标
登录iconfont.cn, 选择你需要的图标保存至项目。并生成在线连接, 将代码保存至本地即可使用。
// style/iconfont.css
@font-face {
font-family: "iconfont"; /* Project id 2524131 */
src: url('//at.alicdn.com/t/font_2524131_8g1ggguc7ig.woff2?t=1619912299648') format('woff2'),
url('//at.alicdn.com/t/font_2524131_8g1ggguc7ig.woff?t=1619912299648') format('woff'),
url('//at.alicdn.com/t/font_2524131_8g1ggguc7ig.ttf?t=1619912299648') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-shuben:before {
content: "e6ca";
}
iconfont 的使用
全局引入:在main.js
文件中进行全局引入, import './style/iconfont.css'
具体使用: <span class="iconfont icon-shuben'><!--书本--></span>
移动端开发适配
一、 设置meta
标签
<!-- 强制让文档与设备的宽度保持1:1 -->
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<!-- 禁止识别电话和邮箱 -->
<meta name="format-detection" content="telephone=no,email=no" />
二、动态设置html
根节点的字体大小,实现 rem
适配
// 动态设置html的字体: font-size设为100px, 1rem = 100px
(function(win, doc) {
if (!win.addEventListener) return;
function setHtmlFontSize() {
var html = document.documentElement;
var k = 750;
html.style.fontSize = html.clientWidth / k * 100 + "px";
}
doc.addEventListener('DOMContentLoaded', setHtmlFontSize, false);
win.addEventListener('resize', setHtmlFontSize, false);
win.addEventListener('load', setHtmlFontSize, false);
})(window, document)
H5界面淘宝提供的适配方案flexible.js
github地址:https://github.com/amfe/lib-flexible
官方文档地址:https://github.com/amfe/article/issues/17
Flexible.js的使用:
使用了flexible.js,页面模板不需要设置 <meta name="viewport">
的标签,会自动设置根元素html的font-size、动态创建viewport、针对retina屏做dpr
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="yes" name="apple-touch-fullscreen">
<meta content="telephone=no,email=no" name="format-detection">
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
<link rel="apple-touch-icon" href="favicon.png">
<link rel="Shortcut Icon" href="favicon.png" type="image/x-icon">
<title>案例实战</title>
</head>
<body>
<!-- 页面结构写在这里 -->
</body>
</html>
移动端常见问题【解决方案】
一、禁止电话与邮箱
添加meta
标签全局禁用
<meta name="format-detection" content="telephone=no,email=no" />
局部使用:
<a href="tel:15919829191">电话: 15919829191</a>
<a href="mailto:645629118@qq.com">邮箱: 645629118@qq.com</a>
二、解决链接按钮高亮问题
使用 a 标签作为按钮时,移动端页面中的链接长按会触发一个色块高亮效果;
a {
-webkit-tap-highight-color: transparent;
}
/* 或者设置你需要的颜色 */
a {
-webkit-top-highlight-color: rgba(0,0,0,0);
}
三、解决按钮圆角过圆的问题
<style>
input{
border-radius: 10px;
-webkit-appearance: none;
}
</style>
<input type="button" value="按钮" />
四、font-boosting 问题
Foot Boosting 是 webkit
给移动端提供的一个特性。当在手机浏览器上缩小页面后字体很小看不清,这时浏览器会自动增大字体大小 ,解决方案: 设置最大高度
p {
font-size: 14pxl
max-height: 99999px;
}
五、1物理像素问题
<style>
#test:before {
position: absolute;
bottom: -1px;
content: "";
display: block;
100%;
height: 1px;
background: #f00;
}
@media only screen and(-webkit-device-pixel-ration: 2) {
#test:before {
transform: scaleY(0.5)
}
}
@media only screen and(-webkit-device-pixel-ration: 3) {
#test:before {
transform: scaleY(0.33)
}
}
</style>
<div id="test">1物理像素</div>
六、移动端触摸事件【点透】问题解决方案
/*
* 底层节点阻止默认行为
* 1. 解决IOS10下设置meta无法禁止用户缩放的兼容性问题
* 2. 解决IOS10下溢出隐藏的问题 body,html{ 100%; overflow: hidden;}
* 3. 阻止橡皮筋效果(页面华东到最顶和最低部的缓冲反弹的效果)
* 4. 禁止长按选中文字、选中图片、弹出菜单等
* 5. 阻止默认行为后,元素无法获取焦点,元素阻止冒泡后可正常使用
*/
document.addEventListener("touchstart", function(ev) {
ev.preventDefault();
})
// 缺点: a 链接等可获取焦点的元素的默认行为无法使用,需要手动添加事件绑定
var aNodes = document.querySelectorAll("a")
for(var i = 0; i < aNodes.length; i++) {
aNodes[i].addEventListener("touchstart", function() {
this.isMoved = false;
})
aNodes[i].addEventListener("touchmove", function() {
this.isMoved = true
})
aNodes[i].addEventListener("touchend", function() {
if(!this.isMoved) {
window.location.href = this.href;
}
})
}
导航拖拽效果 - 橡皮筋效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no" />
<title></title>
<style>
* { margin: 0; padding: 0; }
li, ol { list-style: none; }
html, body { 100%; overflow: hidden; height: 100%; }
body { font-size: 14px; }
.slide-nav {
height: 1rem;
background: #f4f6fd;
font-size: 16px;
}
.slide-nav > ul {
float: left;
white-space: nowrap;
display: flex;
align-items: center;
height: 100%;
}
.slide-nav > ul > li {
display: inline-block;
padding: 0 0.3rem;
}
</style>
<script>
// 动态设置html的字体
(function (win, doc) {
if (!win.addEventListener) return;
function setHtmlFontSize() {
var html = document.documentElement;
var k = 750;
html.style.fontSize = (html.clientWidth / k) * 100 + "px";
}
doc.addEventListener("DOMContentLoaded", setHtmlFontSize, false);
win.addEventListener("resize", setHtmlFontSize, false);
win.addEventListener("load", setHtmlFontSize, false);
})(window, document);
/**
* 封装设置样式和获取样式的方法
*/
function css(node, type, val) {
var filedStr = "transform"
if (typeof node === "object" && typeof node[filedStr] === "undefined") {
node[filedStr] = {}
}
if(arguments.length >= 3) {
// 设置
var text = ''
node[filedStr][type] = val;
for(item in node[filedStr]) {
if(node[filedStr].hasOwnProperty(item)) {
switch (item) {
case "translateX":
case "translateY":
text += item + "("+node[filedStr][item]+"px)"
break;
case "scale":
text += item + "("+node[filedStr][item]+")"
break;
case "rotate":
text += item + "("+node[filedStr][item]+"deg)"
break;
}
}
}
node.style[filedStr] = node.style.webkitTransform = text;
} else if(arguments.length == 2) {
// 读取
var val = node[filedStr][type];
if (typeof val === "undefined") {
switch (type) {
case "translateX":
case "translateY":
case "rotate":
val = 0;
break;
case "scale":
val = 1
break;
}
}
return val;
}
}
window.onload = function () {
// 滑动导航
drag();
function drag() {
var slideEle = document.querySelector(".slide-nav"),
slideItem = document.querySelector(".items"),
// 记录元素开始位置, 手指开始位置
startX = 0,
elementX = 0,
// (可视区宽 - 滑动内容宽)
minX = slideEle.clientWidth - slideItem.offsetWidth;
// 快速滑屏:
var lastTime = 0,
lastPoint = 0,
timeDis = 0,
pointDis = 0;
slideEle.addEventListener("touchstart", function (ev) {
ev = ev || event;
var touchC = ev.changedTouches[0]
startX = touchC.clientX;
elementX = css(slideItem, 'translateX')
slideItem.style.transition = "none";
lastTime = new Date().getTime();
lastPoint = touchC.clientX
// 清楚速度
pointDis = 0;
});
slideEle.addEventListener("touchmove", function(ev) {
ev = ev || event;
var touchC = ev.changedTouches[0]
var nowX = touchC.clientX;
var disX = nowX - startX;
var translateX = elementX + disX
var winW = document.documentElement.clientWidth
var nowTime = new Date().getTime();
var nowPoint = touchC.clientX;
timeDis = nowTime - lastTime;
pointDis = nowPoint - lastPoint;
lastTime = nowTime;
lastPoint = nowPoint;
slideItem.handMove = false;
// 范围限制
if (translateX > 0) {
slideItem.handMove = true; // 用于判断是快速滑动还是普通滑动
var scale = winW/((winW + translateX) * 2); // (0, .5)
translateX = css(slideItem, "translateX") + pointDis * scale;
} else if (translateX < minX){
slideItem.handMove = true;
var overW = minX - translateX;
var scale = winW/((winW + overW) * 2); // (0, .5)
translateX = css(slideItem, "translateX") + pointDis * scale;
}
css(slideItem, "translateX", translateX)
})
slideEle.addEventListener("touchend", function() {
var translateX = css(slideItem, "translateX");
if (!slideItem.handMove) {
// 快速滑动 + 橡皮筋效果
var speed = pointDis/timeDis; // 速度越大,位移越远
speed = Math.abs(speed) < 0.5 ? 0 : speed; //
var targetX = translateX + speed * 200;
var time = Math.abs(speed) * 0.2;
time = time < 0.8 ? 0.8 : time;
time = time > 2 ? 2 : time;
var bsr = '';
if (targetX > 0) {
targetX = 0
bsr = 'cubic-bezier(.33,1.27,.58,1.42)'
} else if (targetX < minX){
targetX = minX
bsr = 'cubic-bezier(.33,1.27,.58,1.42)'
}
slideItem.style.transition = time + "s " + bsr + " transform";
css(slideItem, "translateX", targetX)
} else {
// 普通滑动
if (translateX > 0) {
translateX = 0
} else if (translateX < minX){
translateX = minX
}
slideItem.style.transition = "1s transform";
css(slideItem, "translateX", translateX)
}
})
}
};
</script>
</head>
<body>
<div class="slide-nav">
<ul class="items">
<li>新闻</li>
<li>电视剧</li>
<li>在线热点</li>
<li>预览</li>
<li>我</li>
<li>职场信息</li>
<li>最新资讯</li>
<li>新风向</li>
<li>娱乐圈</li>
<li>信用</li>
<li>周边房价</li>
</ul>
</div>
</body>
</html>
CSS 实现 贝塞尔曲线(cubic-bezier) 运动
animation: 1s cubic-bezier(.31,1.13,.41,1.39) transform;
媒体查询
什么是媒体查询:查询屏幕类型和屏幕大小;
为何要媒体查询:为了兼容,根据屏幕大小写样式
媒体类型:
- all:默认类型,表示全部的
- screen:浏览器页面
- print:打印页面
- speech:正对残障人士设计的
// min-width规则为: 当媒体类型 大于或等于 指定的宽度时, 大括号内的样式生效
@media screen and (min- 900px) {
...
}
// max-width规则为: 当媒体类型 小于或等于 指定的宽度时,大括号内的样式生效
@media screen and (max- 900px) {
...
}
媒体查询中的逻辑:
- 与 (and)
- 或 (,)
- 非 (not)
// 同时设置多个媒体特性
// 最大宽度为1000px, 最小宽度为700px。大于等于700px且小于等于1000px的范围内设置生效
@media screen and (max- 1000px) and (min- 700px) {
...
}
//
根据设备尺寸加载不同的样式表:
// 根据屏幕设备的尺寸来设置相应的样式
<link rel="stylesheet" media="screen and (max-device-weidth:480px)" href="iphone.css" />