移动端H5开发常用技巧

写在最前:本文转自掘金
类似文章掘金

html篇

常用的meta属性

meta 对于移动端的一些特殊属性,可以根据需要自行设置

// 页面的布局视口(layout viewport)的宽度等于视觉视口(virsual viewport)的宽度,此时页面元素会以设备逻辑像素宽度做为文档宽度进行布局
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, width=device-width"> 
<meta name="screen-orientation" content="portrait"> //Android 禁止屏幕旋转
<meta name="full-screen" content="yes">             //全屏显示
<meta name="browsermode" content="application">     //UC应用模式,使用了application这种应用模式后,页面讲默认全屏,禁止长按菜单,禁止收拾,标准排版,以及强制图片显示。
<meta name="x5-orientation" content="portrait">     //QQ强制竖屏
<meta name="x5-fullscreen" content="true">          //QQ强制全屏
<meta name="x5-page-mode" content="app">            //QQ应用模式

电话号码识别(ios)

在 iOS Safari (其他浏览器和 Android 均不会)上会对那些看起来像是电话号码的数字处理为电话链接,比如:

  • 7 位数字,形如:1234567
  • 带括号及加号的数字,形如:(+86)123456789
  • 双连接线的数字,形如:00-00-00111
  • 11 位数字,形如:13800138000

关闭识别

<meta name="format-detection" content="telephone=no" />

开启识别

<a href="tel:123456">123456</a>

邮箱识别(Android)

安卓上会对符合邮箱格式的字符串进行识别,我们可以通过如下的 meta 来管别邮箱的自动识别:

<meta content="email=no" name="format-detection" />

同样地,我们也可以通过标签属性来开启长按邮箱地址弹出邮件发送的功能:

<a mailto:dooyoe@gmail.com">dooyoe@gmail.com</a>

css篇

移动端click屏幕产生200-300 ms的延迟响应

html {touch-action: manipulation;}

0.5px细线

移动端 H5 项目越来越多,设计师对于 UI 的要求也越来越高,比如 1px 的边框。在高清屏下,移动端的 1px 会很粗。下面介绍最常用的方法.

/* 四条边 */
.setBorderAll {
  position: relative;
  &:after {
    content: ' ';
    position: absolute;
    top: 0;
    left: 0;
    width: 200%;
    height: 200%;
    transform: scale(0.5);
    transform-origin: left top;
    box-sizing: border-box;
    border: 1px solid #e5e5e5;
    border-radius: 4px;
  }
}

屏蔽用户选择

禁止用户选择页面中的文字或者图片

div {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

清除输入框内阴影(ios)

div {
  -webkit-appearance: none;
}

输入框placeholder字体颜色

input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder {
  color: #c7c7c7;
}
input:-moz-placeholder,
textarea:-moz-placeholder {
  color: #c7c7c7;
}
input:-ms-input-placeholder,
textarea:-ms-input-placeholder {
  color: #c7c7c7;
}

用户设置字号放大或者缩小导致页面布局错误

body {
  -webkit-text-size-adjust: 100% !important;
  text-size-adjust: 100% !important;
  -moz-text-size-adjust: 100% !important;
}

android系统中元素被点击时产生边框

部分android系统点击一个链接,会出现一个边框或者半透明灰色遮罩, 不同生产商定义出来额效果不一样。去除代码如下

a,button,input,textarea{
  -webkit-tap-highlight-color: rgba(0,0,0,0)
  -webkit-user-modify:read-write-plaintext-only; 
}

js篇

audio 和 video 在 ios 和 andriod 中自动播放

由于自动播放网页中的音频或视频,会给用户带来一些困扰或者不必要的流量消耗,所以苹果系统和安卓系统通常都会禁止自动播放和使用 JS 的触发播放,必须由用户来触发才可以播放。加入自动触发播放的代码

$('html').one('touchstart', function() {
  audio.play()
})

ios软键盘问题

移动端使用vue开发注意事项

分辨率rem

首先我们在项目中引入 lib-flexible:

npm install lib-flexible -S
// main.js 全局引入
...
import 'lib-flexible/flexible'
...

此时我们可以重启项目,看看 html 标签有没有 font-size 属性:
在项目根目录下新建 .postcssrc.js 配置文件,配置代码如下:

module.exports = {
  plugins: {
    'autoprefixer': {
      browsers: ['Android >= 4.0', 'iOS >= 7'] /
    },
    'postcss-pxtorem': {
      rootValue: 37.5, // vant-UI的官方根字体大小是37.5
      propList: ['*']
    }
  }
}

1rem 为 37.5px,75px 等于 2rem,而 html 根节点的 font-size 属性大小会根据移动端的分辨率动态变化,所以单位的换算也会随之变化。这里要注意的是,大些的 PX,可以避开被编译成 rem 单位,用在字体和圆角上比较方便。

页面转场动画

Vue 提供了 transition 的封装组件,在切换路由的时候,可以给任何元素和组件添加进入/离开过渡。项目中具体实现如下:

// src/App.vue
<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <transition :name="transitionName">
      <router-view class="router-view" />
    </transition>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        transitionName: 'slide-left'
      }
    },
    watch: {
      $route(to, from) {
        // 由主级到次级
        // to.meta 能取到 route 路由参数中的 meta 属性
        if (to.meta.index > from.meta.index) {
          // 通过改变变量名称控制左右滑动
          this.transitionName = 'slide-left' // 向左滑动
        } else if (to.meta.index < from.meta.index) {
          // 由次级到主级
          this.transitionName = 'slide-right'
        } else {
          this.transitionName = ''   //同级无过渡效果
        }
      }
    }
  }
</script>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 1000;
}

.router-view{
    width: 100%;
    height: auto;
    position: absolute;
    top: 0;
    bottom: 0;
    margin: 0 auto;
    -webkit-overflow-scrolling: touch;
}

.slide-right-enter-active,
.slide-right-leave-active,
.slide-left-enter-active,
.slide-left-leave-active{
    height: 100%;
    will-change: transform;
    transition: all 500ms;
    position: absolute;
    backface-visibility: hidden;
}
.slide-right-enter{
    opacity: 0;
    transform: translate3d(-100%, 0, 0);
}
.slide-right-leave-active{
    opacity: 0;
    transform: translate3d(100%, 0, 0);
}
.slide-left-enter{
    opacity: 0;
    transform: translate3d(100%, 0, 0);
}
.slide-left-leave-active{
    opacity: 0;
    transform: translate3d(-100%, 0, 0);
}
</style>

随后在router.js中标记页面层级关系

// src/router/index.js
...
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    meta: {
      index: 1 // 添加 meta 属性,约定 1 为第一级
    }
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
    meta: {
      index: 2 // 添加 meta 属性,约定 2 为第二级
    }
  }
]
...

reset样式

@charset "utf-8";html{touch-action: manipulation;background-color:#fff;color:#000;font-size:12px;}
body,ul,ol,dl,dd,h1,h2,h3,h4,h5,h6,figure,form,fieldset,legend,input,textarea,button,p,blockquote,th,td,pre,xmp{margin:0;padding:0}
body,#app{height: 100%;}
body,input,textarea,button,select,pre,xmp,tt,code,kbd,samp{line-height:1.5;font-family:tahoma,arial,"Hiragino Sans GB",simsun,sans-serif}
h1,h2,h3,h4,h5,h6,small,big,input,textarea,button,select{font-size:100%}
h1,h2,h3,h4,h5,h6{font-family:tahoma,arial,"Hiragino Sans GB","微软雅黑",simsun,sans-serif}
h1,h2,h3,h4,h5,h6,b{font-weight:normal}
address,cite,dfn,em,i,optgroup,var{font-style:normal}
table{border-collapse:collapse;border-spacing:0;text-align:left}
caption,th{text-align:inherit}
ul,ol,menu{list-style:none}
fieldset,img{border:0}
img,object,input,textarea,button,select{vertical-align:middle}
article,aside,footer,header,section,nav,figure,figcaption,hgroup,details,menu{display:block}
audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
blockquote:before,blockquote:after,q:before,q:after{content:"\0020"}
textarea{overflow:auto;resize:vertical}
input,textarea,button,select,a{outline:0 none;border: none;}
button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
mark{background-color:transparent}
a,ins,s,u,del{text-decoration:none}
sup,sub{vertical-align:baseline}
html {height: 100%;font-size: 50px;-webkit-tap-highlight-color: transparent;}
body {font-family: Arial, "Microsoft Yahei", "Helvetica Neue", Helvetica, sans-serif;color: #313131;font-size: .28em;line-height: 1;-webkit-text-size-adjust: none;}
#app{height: 100%;}

使用less中mixin快捷方法

// mixin.less
@import './base.less';
@primary: #1baeae; // 主题色
@orange: #FF6B01; 
@bc: #F7F7F7;
@fc:#fff;

// // 背景图片地址和大小
.bis(@url) {
  background-image: url(@url);
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

// //圆角
.borderRadius(@radius) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  -ms-border-radius: @radius;
  -o-border-radius: @radius;
  border-radius: @radius;
}

// //1px底部边框
.border-1px(@color){
  position: relative;
  &:after{
    display: block;
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    border-top: 1px solid @color;
    content: '';
  }
}
// //定位全屏
.allcover{
  position:absolute;
  top:0;
  right:0;
}

// //定位上下左右居中
.center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

// //定位上下居中
.ct {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

// //定位左右居中
.cl {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

// //宽高
.wh(@width, @height){
  width: @width;
  height: @height;
}

// //字体大小,颜色
.sc(@size, @color){
  font-size: @size;
  color: @color;
}

.boxSizing {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

// //flex 布局和 子元素 对其方式
.fj(@type: space-between){
  display: flex;
  justify-content: @type;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容