移动端开发问题(300ms延迟、1px边框问题、图片资源适配...)

一.viewport

<!-- 设置移动端视窗 -->
  <meta name="viewport"
    content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,u ser-scalable=no">

二、解决点击响应延时 0.3s 问题

大多数移动端触摸屏设备上点击的时候都会有0.3秒的延迟问题,我们做移动端web app开发的时候应该都遇到过这个问题,通过以下代码可以轻松解决这个问题

FastClick 是专门为解决移动端浏览器 300 毫秒点击延迟问题的一个轻量级的库。咱们需要引入fastclick.js中的方法并进行操作

原生js

<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
<script type="text/javascript">
  if ('addEventListener' in document) {
    document.addEventListener('DOMContentLoaded', function () {
      FastClick.attach(document.body)
    }, false);
  }
  if (!window.Promise) {
    document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"' + '>' + '<' + '/' + 'script>');
  }
</script>

jq

$(function() {
    FastClick.attach(document.body);
});

vue

npm install fastclick -save

如何你是vue项目可以在main.js里面直接引入,当然这样是全局的,如果你需要某个页面用到,那就单个页面引入。

//引入移动端点击300ms延迟
import FastClick from 'fastclick'
//初始化FastClick实例。在页面的DOM文档加载完成后
FastClick.attach(document.body)

如果你用过FastClick在移动端,就会发现有一个体验很不好的问题,某些ios上,点击输入框想唤启软键盘,触点不是很灵敏,必须重压或长按才能成功唤启,快速点击是不会唤启软键盘的。

如何解决ios input框唤启软键盘不灵敏问题?

/**
  * @param {EventTarget|Element} targetElement
  */
FastClick.prototype.focus = function(targetElement) {
  var length;
  // Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
  if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month' && targetElement.type !== 'email') {
      length = targetElement.value.length;
      targetElement.focus();
      targetElement.setSelectionRange(length, length);
  } else {
      targetElement.focus();
  }
};

完整版

//引入移动端点击300ms延迟
import FastClick from 'fastclick'
//初始化FastClick实例。在页面的DOM文档加载完成后
FastClick.attach(document.body)
/**
  * @param {EventTarget|Element} targetElement
  */
FastClick.prototype.focus = function (targetElement) {
  var length;
  if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month' && targetElement.type !== 'email') {
    length = targetElement.value.length;
    targetElement.focus();// 加入这一句话
    targetElement.setSelectionRange(length, length);
  } else {
    targetElement.focus();
  }
};

三、图片资源适配

由于需要兼容dpr为2.0以及3.0的设备,常常需要使用2倍图或3倍图资源。但是这样会导致在dpr为1.0的设备也会使用质量较高,文件较大的2倍图或3倍图资源。
当然这样并不可取,会造成大量带宽的浪费。现代浏览器,提供了更好的方式,让我们能够根据设备 dpr 的不同,提供不同尺寸的图片。

1:img元素的srcset和sizes属性:

<div class="illustration">
    <img src="illustration-small.png"
            srcset="images/illustration-small.png 1x,
                    images/illustration-big.png 2x"
    style="max-width: 500px"/>
</div>

上面 srcset 里的 1x,2x 表示 像素密度描述符,表示

    当屏幕的 dpr = 1 时,使用 images/illustration-small.png 这张图

    当屏幕的 dpr = 2 时,使用 images/illustration-big.png 这张图

    不符合上述任一条件的,则默认使用src属性指向的图片资源

srcset属性单独使用只适用设备dpr的适配,只适合显示区域一样大小的图像。如果希望不同尺寸的屏幕,显示不同大小的图像,srcset属性就不够用了,必须搭配sizes属性来说设置不同设备下的图像显示大小。

<img srcset="foo-160.jpg 160w,
             foo-320.jpg 320w,
             foo-640.jpg 640w,
             foo-1280.jpg 1280w"
     sizes="(max-width: 440px) 100vw,
            (max-width: 900px) 33vw,
            254px"
     src="foo-1280.jpg">

本例中srcest属性的单位为w的数值表示图像的原始图片显示大小

sizes属性的值是一个逗号分隔的字符串,除了最后一部分,前面每个部分都是一个放在括号里面的媒体查询表达式,后面是一个空格,再加上图像的显示宽度。

同时有了srcset和sizes属性后,浏览器根据当前设备的宽度,从sizes属性获得图像的显示宽度,然后从srcset属性找出最接近该宽度的图像,进行加载。

假定当前设备的屏幕宽度是480px CSS像素,那么上面代码表示,浏览器从sizes属性查询得到,图片的显示宽度是33vw(即33%),等于160px。srcset属性里面,正好有宽度等于160px的图片,于是加载foo-160.jpg。254px则是当前设备不符合size的任一条件时的默认图片显示大小

    sizes属性必须与srcset属性搭配使用。单独使用sizes属性是无效的。

2:picture元素和source元素

img元素分别使用srcset和size属性时,解决了像素密度和屏幕大小的适配,但是如果要同时适配不同像素密度、不同大小的屏幕,应该怎么办呢?

这时,就要用到picture标签。它是一个容器标签,内部使用source和img,指定不同情况下加载的图像

<picture>
  <source srcset="homepage-person@desktop.png,
                  homepage-person@desktop-2x.png 2x"       
          media="(min-width: 990px)">
  <source srcset="homepage-person@tablet.png,
                  homepage-person@tablet-2x.png 2x" 
          media="(min-width: 750px)">
  <img srcset="homepage-person@mobile.png,
               homepage-person@mobile-2x.png 2x" 
       alt="Shopify Merchant, Corrine Anestopoulos">
</picture>

上面代码中,picture标签内部有两个source标签和一个img标签。

source标签的media属性给出媒体查询表达式,srcset属性就是img标签的srcset属性,给出加载的图像文件。sizes属性这里也可以用。

浏览器按照source标签出现的顺序,依次判断当前设备是否满足media属性的媒体查询表达式,如果满足就加载srcset属性指定的图片文件,并且不再执行后面的source标签和img标签。

img标签是默认情况下加载的图像,用来满足上面所有source都不匹配的情况。

picture标签还可以用来选择不同格式的图像。比如,如果当前浏览器支持 Webp 格式,就加载这种格式的图像,否则加载 PNG 图像。

<picture>
  <source type="image/svg+xml" srcset="logo.xml">
  <source type="image/webp" srcset="logo.webp"> 
  <img src="logo.png" alt="ACME Corp">
</picture>

上面代码中,标签的type属性给出图像的 MIME 类型,srcset是对应的图像 URL。

浏览器按照source标签出现的顺序,依次检查是否支持type属性指定的图像格式,如果支持就加载图像,并且不再检查后面的source标签了。上面例子中,图像加载优先顺序依次为 svg 格式、webp 格式和 png 格式。

图片懒加载
 

四、1px边框问题

@charset "utf-8";
.border,
.border-top,
.border-right,
.border-bottom,
.border-left,
.border-topbottom,
.border-rightleft,
.border-topleft,
.border-rightbottom,
.border-topright,
.border-bottomleft {
  position: relative;
}
.border::before,
.border-top::before,
.border-right::before,
.border-bottom::before,
.border-left::before,
.border-topbottom::before,
.border-topbottom::after,
.border-rightleft::before,
.border-rightleft::after,
.border-topleft::before,
.border-topleft::after,
.border-rightbottom::before,
.border-rightbottom::after,
.border-topright::before,
.border-topright::after,
.border-bottomleft::before,
.border-bottomleft::after {
  content: "\0020";
  overflow: hidden;
  position: absolute;
}
/* border
 * 因,边框是由伪元素区域遮盖在父级
 * 故,子级若有交互,需要对子级设置
 * 定位 及 z轴
 */
.border::before {
  box-sizing: border-box;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  border: 1px solid #eaeaea;
  transform-origin: 0 0;
}
.border-top::before,
.border-bottom::before,
.border-topbottom::before,
.border-topbottom::after,
.border-topleft::before,
.border-rightbottom::after,
.border-topright::before,
.border-bottomleft::before {
  left: 0;
  width: 100%;
  height: 1px;
}
.border-right::before,
.border-left::before,
.border-rightleft::before,
.border-rightleft::after,
.border-topleft::after,
.border-rightbottom::before,
.border-topright::after,
.border-bottomleft::after {
  top: 0;
  width: 1px;
  height: 100%;
}
.border-top::before,
.border-topbottom::before,
.border-topleft::before,
.border-topright::before {
  border-top: 1px solid #eaeaea;
  transform-origin: 0 0;
}
.border-right::before,
.border-rightbottom::before,
.border-rightleft::before,
.border-topright::after {
  border-right: 1px solid #eaeaea;
  transform-origin: 100% 0;
}
.border-bottom::before,
.border-topbottom::after,
.border-rightbottom::after,
.border-bottomleft::before {
  border-bottom: 1px solid #eaeaea;
  transform-origin: 0 100%;
}
.border-left::before,
.border-topleft::after,
.border-rightleft::after,
.border-bottomleft::after {
  border-left: 1px solid #eaeaea;
  transform-origin: 0 0;
}
.border-top::before,
.border-topbottom::before,
.border-topleft::before,
.border-topright::before {
  top: 0;
}
.border-right::before,
.border-rightleft::after,
.border-rightbottom::before,
.border-topright::after {
  right: 0;
}
.border-bottom::before,
.border-topbottom::after,
.border-rightbottom::after,
.border-bottomleft::after {
  bottom: 0;
}
.border-left::before,
.border-rightleft::before,
.border-topleft::after,
.border-bottomleft::before {
  left: 0;
}
@media (max--moz-device-pixel-ratio: 1.49),
  (-webkit-max-device-pixel-ratio: 1.49),
  (max-device-pixel-ratio: 1.49),
  (max-resolution: 143dpi),
  (max-resolution: 1.49dppx) {
  /* 默认值,无需重置 */
}
@media (min--moz-device-pixel-ratio: 1.5) and (max--moz-device-pixel-ratio: 2.49),
  (-webkit-min-device-pixel-ratio: 1.5) and (-webkit-max-device-pixel-ratio: 2.49),
  (min-device-pixel-ratio: 1.5) and (max-device-pixel-ratio: 2.49),
  (min-resolution: 144dpi) and (max-resolution: 239dpi),
  (min-resolution: 1.5dppx) and (max-resolution: 2.49dppx) {
  .border::before {
    width: 200%;
    height: 200%;
    transform: scale(0.5);
  }
  .border-top::before,
  .border-bottom::before,
  .border-topbottom::before,
  .border-topbottom::after,
  .border-topleft::before,
  .border-rightbottom::after,
  .border-topright::before,
  .border-bottomleft::before {
    transform: scaleY(0.5);
  }
  .border-right::before,
  .border-left::before,
  .border-rightleft::before,
  .border-rightleft::after,
  .border-topleft::after,
  .border-rightbottom::before,
  .border-topright::after,
  .border-bottomleft::after {
    transform: scaleX(0.5);
  }
}
@media (min--moz-device-pixel-ratio: 2.5),
  (-webkit-min-device-pixel-ratio: 2.5),
  (min-device-pixel-ratio: 2.5),
  (min-resolution: 240dpi),
  (min-resolution: 2.5dppx) {
  .border::before {
    width: 300%;
    height: 300%;
    transform: scale(0.33333);
  }
  .border-top::before,
  .border-bottom::before,
  .border-topbottom::before,
  .border-topbottom::after,
  .border-topleft::before,
  .border-rightbottom::after,
  .border-topright::before,
  .border-bottomleft::before {
    transform: scaleY(0.33333);
  }
  .border-right::before,
  .border-left::before,
  .border-rightleft::before,
  .border-rightleft::after,
  .border-topleft::after,
  .border-rightbottom::before,
  .border-topright::after,
  .border-bottomleft::after {
    transform: scaleX(0.33333);
  }
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值