移动端问题总结

移动端 1px 问题

产生原因

简单点说就是因为 Retine 屏的分辨率始终是普通屏幕的 2 倍,1px 的边框在devicePixelRatio=2的 retina 屏下会显示成 2px,所以在高清屏下 1px 就显得和 2px 差不多,具体细节可以参考这篇文章

解决方案

  • 使用媒体查询
.border_1px {
  border: 1px solid #f1f1f1;
}

@media (-webkit-min-device-pixel-ratio: 2) {
  .border_1px {
    border: 0.5px solid #f1f1f1;
  }
}

缺点

兼容性差,有的 retina 屏会将 0.5 识别成 0px

  • 伪类配合 transform
border-1px($color = #ccc, $radius = 2px, $style = solid)
  position relative

  &:after
    content ''
    pointer-events none // 解决iphone上的点击无效Bug
    display block
    position absolute
    left 0
    top 0
    transform-origin 0 0
    border 1px $style $color
    border-radius $radius
    box-sizing border-box
    width 100%
    height 100%

    @media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2)
      width 200%
      height 200%
      border-radius $radius * 2
      transform scale(0.5) translateZ(0)

    @media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3)
      width 300%
      height 300%
      border-radius $radius * 3
      transform scale(0.33) translateZ(0)

缺点

如果碰上其他伪类并存,则需要多层嵌套

  • 使用 box-shadow 模拟
.border_1px {
  box-shadow: inset 0px -1px 1px -1px #f1f1f1;
}

缺点

边框有阴影,颜色略浅

  • 使用 view-port

对于devicePixelRatio=2的:

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

对于devicePixelRatio=3的:

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

可以使用js判断后动态插入:

let dpr = 1;
let ratio = window.devicePixelRatio;
let doc = document;
let head = doc.querySelector("head");
if (ratio === 2) {
  dpr = 2;
} else if (ratio === 3) {
  dpr = 3;
}
let scale = 1 / dpr;
let meta = doc.createElement("meta");
meta.setAttribute("name", "viewport");
meta.setAttribute(
  "content",
  `initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}, user-scalable=no`
);
head.appendChild(meta);

rempx 的取舍

如果项目只适配手机端,pxrem可以根据个人习惯自主选择。

如果项目适配多种设备,比如手机和 pad 设备,分辨率差的比较大的情况下,使用rem最优

移动端点击背景图/链接有底色

/* 点击的时候底色透明即可 */
-webkit-tap-highlight-color: transparent;

禁止选择文字/图片

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

禁止复制/保存图片

img {
  -webkit-touch-callout: none;
}

页面动画容易出现闪烁白屏

使用translate3d优化

-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);

transform 和 fixed

在父元素使用transform下使用fixed,将会使fixed失效。

解决方案是:

  • 在使用了transform的容器中不使用fixed,换absolute,并需要通过 js 计算固定位置
  • 依然使用fixed,不过使用fixed的容器放在使用transform的容器之外。

遮罩层滚动点透问题

在出现遮罩层的时候,我们可以使用@touchmove.prevent来防止点透的问题出现,也就是遮罩层背后的内容还能滚动的问题。但是如果这样的话,如果遮罩层内有需要滚动的容器,那将使容器的滚动也失效。

通过自身的了解和网上的收集,主要解决方案有以下几种:

  • body设置 css{overflow:hidden}

    问题

    IOS 上无效

  • body,html都设置 css{overflow:hidden}

    问题

    a - 滚动位置会丢失,需要通过 js 设置 scrollTop

    b - 没效果

  • 目前比较完美的解决方案

    (function() {
      var scrollTop = 0;
    
      // 显示弹出层
      open.onclick = function() {
        // 在弹出层显示之前,记录当前的滚动位置
        scrollTop = getScrollTop();
    
        // 使body脱离文档流
        document.body.classList.add("dialog-open");
    
        // 把脱离文档流的body拉上去!否则页面会回到顶部!
        document.body.style.top = -scrollTop + "px";
    
        mask.style.display = "block";
      };
    
      // 隐藏弹出层
      close.onclick = function() {
        mask.style.display = "none";
    
        // body又回到了文档流中(我胡汉三又回来啦!)
        document.body.classList.remove("dialog-open");
    
        // 滚回到老地方
        to(scrollTop);
      };
    
      function to(scrollTop) {
        document.body.scrollTop = document.documentElement.scrollTop = scrollTop;
      }
      function getScrollTop() {
        return document.body.scrollTop || document.documentElement.scrollTop;
      }
    })();
    
    function fixedBody(){
      var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
      document.body.style.cssText += 'position:fixed;top:-'+scrollTop+'px;';
    }
    
    function looseBody() {
      var body = document.body;
      body.style.position = '';
      var top = body.style.top;
      document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top);
      body.style.top = '';
    }
    
    

不过这样依旧会有点问题,就是如果在遮罩层中滚动的时候,做点击操作,会容易出现卡死的现象,就是滚动后需要进行两次点击,再能进行对应的点击操作。对此的解决方案是,改click事件为touchstart事件。

使用webkit-overflow-scrolling:touch的坑

今天遇到的了一个问题就是内容滚动有时候会出现卡住的情况,尤其是当滚动条位于最顶端或者最底下的时候,继续下拉或者上拉会导致页面卡住,这样的情况颇为频繁,找了很久都没发现问题所在,所以在尝试的情况下注释掉了webkit-overflow-scrolling后,发现居然好了!!!居然好了!!!

然后就针对这个问题谷歌上找了下,发现其实也很很多:

  • 取消webkit-overflow-scrolling:touch,但是这样会导致滚动时手指离开就马上停住滚动,没有了惯性滚动

  • 让子内容的高度+1px,比如父容器使用了webkit-overflow-scrolling:touch,那么子内容的容器设置高度height:calc(100% + 1px)既可以解决。

SPA路由使用history模式下的微信分享bug

会出现的一个情况是,我已进入页面是可以分享的,当时如果这时候路由变化,比如replace或者push操作之后,那么分享就会出现问题,并不会如同配置那样分享出来。因为报了invaild signature的错误。

这主要还区分安卓和苹果,两者的情况不同。

出现这个的原因是:

history模式下,vue-router操作的是浏览器的历史记录,从而改变URL的变化。

而官方JSSDK文档中也有提到:

同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复

但是坑爹的是,android中出现的问题不多,因为每次URL变化后,微信记录的都是当前那个URL,而IOS则不然,IOS是微信只记录页面第一次加载进来的URL地址。

举个栗子:

一进入系统的地址是https://a.com,然后先后进入ab,也就是https://a.com/ahttps://a.com/b,然后停在b页面,在android中,微信记录的是https://a.com/b这个地址,而IOS中记录的却是https://a.com,也就是第一次进来的路由地址。

这个时候我们刷新页面,那么https://a.com/b就是IOS第一次进来的地址了,所以IOS微信中记录的地址也就变成了https://a.com/b了。

解决方式:

注册一个全局变量,比如可以在window下挂在一个wxSignURL的变量,当一进入页面的时候保存第一次记录的地址:window.wxSignURL = location.href

这段代码可以写在main.js里,也可以写在router.js的钩子函数中,不过要区别对待,如果是android,则使用每次跳转后的路由,如果是IOS则使用记录的wxSignURL

然后获取微信签名的时候,把这个URL传过去即可。

IOSandroid的判断使用浏览器的ua判断即可。根据资料,微信会在window下挂载一个__wxjs_is_wkwebview属性,如果是在IOS中,该值为true,也可以通过这个属性去判断。

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