当前位置: > 投稿>正文

移动端布局适配心得,关于移动端适配

04-14 互联网 未知 投稿

关于【移动端布局适配心得】,今天涌涌小编给您分享一下,如果对您有所帮助别忘了关注本站哦。

1、移动端布局适配心得:关于移动端适配,你必须要知道的

导读

移动端适配,是我们在开发中经常会遇到的,这里面可能会遇到非常多的问题:

  • 1px问题
  • UI图完美适配方案
  • iPhoneX适配方案
  • 横屏适配
  • 高清屏图片模糊问题
  • ...

上面这些问题可能我们在开发中已经知道如何解决,但是问题产生的原理,以及解决方案的原理可能会模糊不清。在解决这些问题的过程中,我们往往会遇到非常多的概念:像素、分辨率、 PPI、 DPI、 DP、 DIP、 DPR、视口等等,你真的能分清这些概念的意义吗?

本文将从移动端适配的基础概念出发,探究移动端适配各种问题的解决方案和实现原理。

一、英寸

一般用英寸描述屏幕的物理大小,如电脑显示器的 17、 22,手机显示器的 4.8、 5.7等使用的单位都是英寸。

需要注意,上面的尺寸都是屏幕对角线的长度:

移动端布局适配心得,关于移动端适配

英寸( inch,缩写为 in)在荷兰语中的本意是大拇指,一英寸就是指甲底部普通人拇指的宽度。

英寸和厘米的换算: 1英寸=2.54厘米

二、分辨率

2.1 像素

像素即一个小方块,它具有特定的位置和颜色。

图片、电子屏幕(手机、电脑)就是由无数个具有特定颜色和特定位置的小方块拼接而成。

像素可以作为图片或电子屏幕的最小组成单位。

下面我们使用 sketch打开一张图片:

移动端布局适配心得,关于移动端适配

将这些图片放大即可看到这些像素点:

移动端布局适配心得,关于移动端适配

通常我们所说的分辨率有两种,屏幕分辨率和图像分辨率。

2.2 屏幕分辨率

屏幕分辨率指一个屏幕具体由多少个像素点组成。

下面是 apple的官网上对手机分辨率的描述:

移动端布局适配心得,关于移动端适配

iPhone XSMax 和 iPhone SE的分辨率分别为 2688x1242和 1136x640。这表示手机分别在垂直和水平上所具有的像素点数。

当然分辨率高不代表屏幕就清晰,屏幕的清晰程度还与尺寸有关。

2.3 图像分辨率

我们通常说的 图片分辨率其实是指图片含有的 像素数,比如一张图片的分辨率为 800x400。这表示图片分别在垂直和水平上所具有的像素点数为 800和 400。

同一尺寸的图片,分辨率越高,图片越清晰。

移动端布局适配心得,关于移动端适配

2.4 PPI

PPI(PixelPerInch):每英寸包括的像素数。

PPI可以用于描述屏幕的清晰度以及一张图片的质量。

使用 PPI描述图片时, PPI越高,图片质量越高,使用 PPI描述屏幕时, PPI越高,屏幕越清晰。

在上面描述手机分辨率的图片中,我们可以看到: iPhone XSMax 和 iPhone SE的 PPI分别为 458和 326,这足以证明前者的屏幕更清晰。

由于手机尺寸为手机对角线的长度,我们通常使用如下的方法计算 PPI:

$$ \frac{\sqrt{水平像素点数^2+垂直像素点数^2}}{尺寸}$$

iPhone6的 PPI为 $ \frac{\sqrt{1334^2+750^2}}{4.7}=325.6$,那它每英寸约含有 326个物理像素点。

2.5 DPI

DPI(DotPerInch):即每英寸包括的点数。

这里的点是一个抽象的单位,它可以是屏幕像素点、图片像素点也可以是打印机的墨点。

平时你可能会看到使用 DPI来描述图片和屏幕,这时的 DPI应该和 PPI是等价的, DPI最常用的是用于描述打印机,表示打印机每英寸可以打印的点数。

一张图片在屏幕上显示时,它的像素点数是规则排列的,每个像素点都有特定的位置和颜色。

当使用打印机进行打印时,打印机可能不会规则的将这些点打印出来,而是使用一个个打印点来呈现这张图像,这些打印点之间会有一定的空隙,这就是 DPI所描述的:打印点的密度。

移动端布局适配心得,关于移动端适配

在上面的图像中我们可以清晰的看到,打印机是如何使用墨点来打印一张图像。

所以,打印机的 DPI越高,打印图像的精细程度就越高,同时这也会消耗更多的墨点和时间。

三、设备独立像素

实际上,上面我们描述的像素都是 物理像素,即设备上真实的物理单元。

下面我们来看看 设备独立像素究竟是如何产生的:

智能手机发展非常之快,在几年之前,我们还用着分辨率非常低的手机,比如下面左侧的白色手机,它的分辨率是 320x480,我们可以在上面浏览正常的文字、图片等等。

但是,随着科技的发展,低分辨率的手机已经不能满足我们的需求了。很快,更高分辨率的屏幕诞生了,比如下面的黑色手机,它的分辨率是 640x940,正好是白色手机的两倍。

理论上来讲,在白色手机上相同大小的图片和文字,在黑色手机上会被缩放一倍,因为它的分辨率提高了一倍。这样,岂不是后面出现更高分辨率的手机,页面元素会变得越来越小吗?

移动端布局适配心得,关于移动端适配

然而,事实并不是这样的,我们现在使用的智能手机,不管分辨率多高,他们所展示的界面比例都是基本类似的。乔布斯在 iPhone4的发布会上首次提出了 RetinaDisplay(视网膜屏幕)的概念,它正是解决了上面的问题,这也使它成为一款跨时代的手机。

移动端布局适配心得,关于移动端适配

在 iPhone4使用的视网膜屏幕中,把 2x2个像素当 1个像素使用,这样让屏幕看起来更精致,但是元素的大小却不会改变。

移动端布局适配心得,关于移动端适配

如果黑色手机使用了视网膜屏幕的技术,那么显示结果应该是下面的情况,比如列表的宽度为 300个像素,那么在一条水平线上,白色手机会用 300个物理像素去渲染它,而黑色手机实际上会用 600个物理像素去渲染它。

我们必须用一种单位来同时告诉不同分辨率的手机,它们在界面上显示元素的大小是多少,这个单位就是设备独立像素( DeviceIndependentPixels)简称 DIP或 DP。上面我们说,列表的宽度为 300个像素,实际上我们可以说:列表的宽度为 300个设备独立像素。

移动端布局适配心得,关于移动端适配

打开 chrome的开发者工具,我们可以模拟各个手机型号的显示情况,每种型号上面会显示一个尺寸,比如 iPhone X显示的尺寸是 375x812,实际 iPhone X的分辨率会比这高很多,这里显示的就是设备独立像素。

移动端布局适配心得,关于移动端适配

3.1 设备像素比

设备像素比 device pixel ratio简称 dpr,即物理像素和设备独立像素的比值。

在 web中,浏览器为我们提供了 window.devicePixelRatio来帮助我们获取 dpr。

在 css中,可以使用媒体查询 min-device-pixel-ratio,区分 dpr:

@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2){ }

在 ReactNative中,我们也可以使用 PixelRatio.get()来获取 DPR。

当然,上面的规则也有例外, iPhone6、7、8Plus的实际物理像素是 1080x1920,在开发者工具中我们可以看到:它的设备独立像素是 414x736,设备像素比为 3,设备独立像素和设备像素比的乘积并不等于 1080x1920,而是等于 1242x2208。

实际上,手机会自动把 1242x2208个像素点塞进 1080*1920个物理像素点来渲染,我们不用关心这个过程,而 1242x2208被称为屏幕的 设计像素。我们开发过程中也是以这个 设计像素为准。

实际上,从苹果提出视网膜屏幕开始,才出现设备像素比这个概念,因为在这之前,移动设备都是直接使用物理像素来进行展示。

紧接着, Android同样使用了其他的技术方案来实现 DPR大于 1的屏幕,不过原理是类似的。由于 Android屏幕尺寸非常多、分辨率高低跨度非常大,不像苹果只有它自己的几款固定设备、尺寸。所以,为了保证各种设备的显示效果, Android按照设备的像素密度将设备分成了几个区间:

移动端布局适配心得,关于移动端适配

当然,所有的 Android设备不一定严格按照上面的分辨率,每个类型可能对应几种不同分辨率,所以,每个 Android手机都能根据给定的区间范围,确定自己的 DPR,从而拥有类似的显示。当然,仅仅是类似,由于各个设备的尺寸、分辨率上的差异,设备独立像素也不会完全相等,所以各种 Android设备仍然不能做到在展示上完全相等。

3.2 移动端开发

在 iOS、 Android和 ReactNative开发中样式单位其实都使用的是设备独立像素。

iOS的尺寸单位为 pt, Android的尺寸单位为 dp, ReactNative中没有指定明确的单位,它们其实都是设备独立像素 dp。

在使用 ReactNative开发 App时, UI给我们的原型图一般是基于 iphone6的像素给定的。

为了适配所有机型,我们在写样式时需要把物理像素转换为设备独立像素:例如:如果给定一个元素的高度为 200px(这里的 px指物理像素,非 CSS像素), iphone6的设备像素比为 2,我们给定的 height应为 200px/2=100dp。

当然,最好的是,你可以和设计沟通好,所有的 UI图都按照设备独立像素来出。

我们还可以在代码( ReactNative)中进行 px和 dp的转换:

import {PixelRatio } from 'react-native';const dpr = PixelRatio.get();/** * px转换为dp */export function pxConvertTodp(px) { return px / dpr;}/** * dp转换为px */export function dpConvertTopx(dp) { return PixelRatio.getPixelSizeForLayoutSize(dp);}

3.3 WEB端开发

在写 CSS时,我们用到最多的单位是 px,即 CSS像素,当页面缩放比例为 100%时,一个 CSS像素等于一个设备独立像素。

但是 CSS像素是很容易被改变的,当用户对浏览器进行了放大, CSS像素会被放大,这时一个 CSS像素会跨越更多的物理像素。

页面的缩放系数=CSS像素/设备独立像素。

3.4 关于屏幕

这里多说两句 Retina屏幕,因为我在很多文章中看到对 Retina屏幕的误解。

Retina屏幕只是苹果提出的一个营销术语:

在普通的使用距离下,人的肉眼无法分辨单个的像素点。

为什么强调 普通的使用距离下呢?我们来看一下它的计算公式:

$$ a=2arctan(h/2d) $$

a代表人眼视角, h代表像素间距, d代表肉眼与屏幕的距离,符合以上条件的屏幕可以使肉眼看不见单个物理像素点。

它不能单纯的表达分辨率和 PPI,只能一种表达视觉效果。

让多个物理像素渲染一个独立像素只是 Retina屏幕为了达到效果而使用的一种技术。而不是所有 DPR>1的屏幕就是 Retina屏幕。

比如:给你一块超大尺寸的屏幕,即使它的 PPI很高, DPR也很高,在近距离你也能看清它的像素点,这就不算 Retina屏幕。

移动端布局适配心得,关于移动端适配

我们经常见到用 K和 P这个单位来形容屏幕:

P代表的就是屏幕纵向的像素个数, 1080P即纵向有 1080个像素,分辨率为 1920X1080的屏幕就属于 1080P屏幕。

我们平时所说的高清屏其实就是屏幕的物理分辨率达到或超过 1920X1080的屏幕。

K代表屏幕横向有几个 1024个像素,一般来讲横向像素超过 2048就属于 2K屏,横向像素超过 4096就属于 4K屏。

四、视口

视口( viewport)代表当前可见的计算机图形区域。在 Web浏览器术语中,通常与浏览器窗口相同,但不包括浏览器的 UI, 菜单栏等——即指你正在浏览的文档的那一部分。

一般我们所说的视口共包括三种:布局视口、视觉视口和理想视口,它们在屏幕适配中起着非常重要的作用。

4.1 布局视口

移动端布局适配心得,关于移动端适配

布局视口( layout viewport):当我们以百分比来指定一个元素的大小时,它的计算值是由这个元素的包含块计算而来的。当这个元素是最顶级的元素时,它就是基于布局视口来计算的。

所以,布局视口是网页布局的基准窗口,在 PC浏览器上,布局视口就等于当前浏览器的窗口大小(不包括 borders 、 margins、滚动条)。

在移动端,布局视口被赋予一个默认值,大部分为 980px,这保证 PC的网页可以在手机浏览器上呈现,但是非常小,用户可以手动对网页进行放大。

我们可以通过调用 document.documentElement.clientWidth/clientHeight来获取布局视口大小。

4.2 视觉视口

移动端布局适配心得,关于移动端适配

视觉视口( visual viewport):用户通过屏幕真实看到的区域。

视觉视口默认等于当前浏览器的窗口大小(包括滚动条宽度)。

当用户对浏览器进行缩放时,不会改变布局视口的大小,所以页面布局是不变的,但是缩放会改变视觉视口的大小。

例如:用户将浏览器窗口放大了 200%,这时浏览器窗口中的 CSS像素会随着视觉视口的放大而放大,这时一个 CSS像素会跨越更多的物理像素。

所以,布局视口会限制你的 CSS布局而视觉视口决定用户具体能看到什么。

我们可以通过调用 window.innerWidth/innerHeight来获取视觉视口大小。

4.3 理想视口

移动端布局适配心得,关于移动端适配

布局视口在移动端展示的效果并不是一个理想的效果,所以理想视口( ideal viewport)就诞生了:网站页面在移动端展示的理想大小。

如上图,我们在描述设备独立像素时曾使用过这张图,在浏览器调试移动端时页面上给定的像素大小就是理想视口大小,它的单位正是设备独立像素。

上面在介绍 CSS像素时曾经提到 页面的缩放系数=CSS像素/设备独立像素,实际上说 页面的缩放系数=理想视口宽度/视觉视口宽度更为准确。

所以,当页面缩放比例为 100%时, CSS像素=设备独立像素, 理想视口=视觉视口。

我们可以通过调用 screen.width/height来获取理想视口大小。

4.4 Meta viewport

<meta> 元素表示那些不能由其它 HTML元相关元素之一表示的任何元数据信息,它可以告诉浏览器如何解析页面。

我们可以借助 <meta>元素的 viewport来帮助我们设置视口、缩放等,从而让移动端得到更好的展示效果。

<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">

上面是 viewport的一个配置,我们来看看它们的具体含义:

Value| 可能值| 描述

-|-|- width| 正整数或 device-width | 以 pixels(像素)为单位, 定义布局视口的宽度。 height| 正整数或 device-height | 以 pixels(像素)为单位, 定义布局视口的高度。 initial-scale| 0.0-10.0|定义页面初始缩放比率。 minimum-scale| 0.0-10.0|定义缩放的最小值;必须小于或等于 maximum-scale的值。 maximum-scale| 0.0-10.0|定义缩放的最大值;必须大于或等于 minimum-scale的值。 user-scalable| 一个布尔值( yes或者 no)| 如果设置为 no,用户将不能放大或缩小网页。默认值为 yes。

4.5 移动端适配

为了在移动端让页面获得更好的显示效果,我们必须让布局视口、视觉视口都尽可能等于理想视口。

device-width就等于理想视口的宽度,所以设置 width=device-width就相当于让布局视口等于理想视口。

由于 initial-scale=理想视口宽度/视觉视口宽度,所以我们设置 initial-scale=1;就相当于让视觉视口等于理想视口。

这时,1个 CSS像素就等于1个设备独立像素,而且我们也是基于理想视口来进行布局的,所以呈现出来的页面布局在各种设备上都能大致相似。

4.6 缩放

上面提到 width可以决定布局视口的宽度,实际上它并不是布局视口的唯一决定性因素,设置 initial-scale也有肯能影响到布局视口,因为布局视口宽度取的是 width和视觉视口宽度的最大值。

例如:若手机的理想视口宽度为 400px,设置 width=device-width, initial-scale=2,此时 视觉视口宽度=理想视口宽度/initial-scale即 200px,布局视口取两者最大值即 device-width 400px。

若设置 width=device-width, initial-scale=0.5,此时 视觉视口宽度=理想视口宽度/initial-scale即 800px,布局视口取两者最大值即 800px。

4.7 获取浏览器大小

浏览器为我们提供的获取窗口大小的 API有很多,下面我们再来对比一下:

移动端布局适配心得,关于移动端适配

  • window.innerHeight:获取浏览器视觉视口高度(包括垂直滚动条)。
  • window.outerHeight:获取浏览器窗口外部的高度。表示整个浏览器窗口的高度,包括侧边栏、窗口镶边和调正窗口大小的边框。
  • window.screen.Height:获取获屏幕取理想视口高度,这个数值是固定的, 设备的分辨率/设备像素比
  • window.screen.availHeight:浏览器窗口可用的高度。
  • document.documentElement.clientHeight:获取浏览器布局视口高度,包括内边距,但不包括垂直滚动条、边框和外边距。
  • document.documentElement.offsetHeight:包括内边距、滚动条、边框和外边距。
  • document.documentElement.scrollHeight:在不使用滚动条的情况下适合视口中的所有内容所需的最小宽度。测量方式与 clientHeight相同:它包含元素的内边距,但不包括边框,外边距或垂直滚动条。

五、1px问题

为了适配各种屏幕,我们写代码时一般使用设备独立像素来对页面进行布局。

而在设备像素比大于 1的屏幕上,我们写的 1px实际上是被多个物理像素渲染,这就会出现 1px在有些屏幕上看起来很粗的现象。

5.1 border-image

基于 media查询判断不同的设备像素比给定不同的 border-image:

.border_1px{ border-bottom: 1px solid #000; } @media only screen and (-webkit-min-device-pixel-ratio:2){ .border_1px{ border-bottom: none; border-width: 0 0 1px 0; border-image: url(../img/1pxline.png) 0 0 2 0 stretch; } }

5.2 background-image

和 border-image类似,准备一张符合条件的边框背景图,模拟在背景上。

.border_1px{ border-bottom: 1px solid #000; } @media only screen and (-webkit-min-device-pixel-ratio:2){ .border_1px{ background: url(../img/1pxline.png) repeat-x left bottom; background-size: 100% 1px; } }

上面两种都需要单独准备图片,而且圆角不是很好处理,但是可以应对大部分场景。

5.3 伪类 + transform

基于 media查询判断不同的设备像素比对线条进行缩放:

.border_1px:before{ content: ''; position: absolute; top: 0; height: 1px; width: 100%; background-color: #000; transform-origin: 50% 0%; } @media only screen and (-webkit-min-device-pixel-ratio:2){ .border_1px:before{ transform: scaleY(0.5); } } @media only screen and (-webkit-min-device-pixel-ratio:3){ .border_1px:before{ transform: scaleY(0.33); } }

这种方式可以满足各种场景,如果需要满足圆角,只需要给伪类也加上 border-radius即可。

5.4 svg

上面我们 border-image和 background-image都可以模拟 1px边框,但是使用的都是位图,还需要外部引入。

借助 PostCSS的 postcss-write-svg我们能直接使用 border-image和 background-image创建 svg的 1px边框:

@svg border_1px { height: 2px; @rect { fill: var(--color, black); width: 100%; height: 50%; } } .example { border: 1px solid transparent; border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; }

编译后:

.example { border: 1px solid transparent; border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }

上面的方案是大漠在他的文章中推荐使用的,基本可以满足所有场景,而且不需要外部引入,这是我个人比较喜欢的一种方案。

5.5 设置viewport

通过设置缩放,让 CSS像素等于真正的物理像素。

例如:当设备像素比为 3时,我们将页面缩放 1/3倍,这时 1px等于一个真正的屏幕像素。

const scale = 1 / window.devicePixelRatio; const viewport = document.querySelector('meta[name="viewport"]'); if (!viewport) { viewport = document.createElement('meta'); viewport.setAttribute('name', 'viewport'); window.document.head.appendChild(viewport); } viewport.setAttribute('content', 'width=device-width,user-scalable=no,initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale);

实际上,上面这种方案是早先 flexible采用的方案。

当然,这样做是要付出代价的,这意味着你页面上所有的布局都要按照物理像素来写。这显然是不现实的,这时,我们可以借助 flexible或 vw、vh来帮助我们进行适配。

六、移动端适配方案

尽管我们可以使用设备独立像素来保证各个设备在不同手机上显示的效果类似,但这并不能保证它们显示完全一致,我们需要一种方案来让设计稿得到更完美的适配。

6.1 flexible方案

flexible方案是阿里早期开源的一个移动端适配解决方案,引用 flexible后,我们在页面上统一使用 rem来布局。

它的核心代码非常简单:

// set 1rem = viewWidth / 10function setRemUnit () { var rem = docEl.clientWidth / 10 docEl.style.fontSize = rem + 'px'}setRemUnit();

rem 是相对于 html节点的 font-size来做计算的。

我们通过设置 document.documentElement.style.fontSize就可以统一整个页面的布局标准。

上面的代码中,将 html节点的 font-size设置为页面 clientWidth(布局视口)的 1/10,即 1rem就等于页面布局视口的 1/10,这就意味着我们后面使用的 rem都是按照页面比例来计算的。

这时,我们只需要将 UI出的图转换为 rem即可。

以 iPhone6为例:布局视口为 375px,则 1rem=37.5px,这时 UI给定一个元素的宽为 75px(设备独立像素),我们只需要将它设置为 75/37.5=2rem。

当然,每个布局都要计算非常繁琐,我们可以借助 PostCSS的 px2rem插件来帮助我们完成这个过程。

下面的代码可以保证在页面大小变化时,布局可以自适应,当触发了 window的 resize和 pageShow事件之后自动调整 html的 fontSize大小。

// reset rem unit on page resizewindow.addEventListener('resize', setRemUnit)window.addEventListener('pageshow', function (e) { if (e.persisted) { setRemUnit() }})

由于 viewport单位得到众多浏览器的兼容,上面这种方案现在已经被官方弃用:

lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。

下面我们来看看现在最流行的 vh、vw方案。

6.2 vh、vw方案

vh、vw方案即将视觉视口宽度 window.innerWidth和视觉视口高度 window.innerHeight等分为 100 份。

上面的 flexible方案就是模仿这种方案,因为早些时候 vw还没有得到很好的兼容。

  • vw(Viewport's width): 1vw等于视觉视口的 1%
  • vh(Viewport's height) : 1vh 为视觉视口高度的 1%
  • vmin : vw 和 vh 中的较小值
  • vmax : 选取 vw 和 vh 中的较大值

移动端布局适配心得,关于移动端适配

如果视觉视口为 375px,那么 1vw=3.75px,这时 UI给定一个元素的宽为 75px(设备独立像素),我们只需要将它设置为 75/3.75=20vw。

这里的比例关系我们也不用自己换算,我们可以使用 PostCSS的 postcss-px-to-viewport 插件帮我们完成这个过程。写代码时,我们只需要根据 UI给的设计图写 px单位即可。

当然,没有一种方案是十全十美的, vw同样有一定的缺陷:

  • px转换成 vw不一定能完全整除,因此有一定的像素差。
  • 比如当容器使用 vw, margin采用 px时,很容易造成整体宽度超过 100vw,从而影响布局效果。当然我们也是可以避免的,例如使用 padding代替 margin,结合 calc()函数使用等等...

七、适配iPhoneX

iPhoneX的出现将手机的颜值带上了一个新的高度,它取消了物理按键,改成了底部的小黑条,但是这样的改动给开发者适配移动端又增加了难度。

7.1 安全区域

在 iPhoneX发布后,许多厂商相继推出了具有边缘屏幕的手机。

移动端布局适配心得,关于移动端适配

这些手机和普通手机在外观上无外乎做了三个改动:圆角( corners)、刘海( sensor housing)和小黑条( HomeIndicator)。为了适配这些手机,安全区域这个概念变诞生了:安全区域就是一个不受上面三个效果的可视窗口范围。

为了保证页面的显示效果,我们必须把页面限制在安全范围内,但是不影响整体效果。

7.2 viewport-fit

viewport-fit是专门为了适配 iPhoneX而诞生的一个属性,它用于限制网页如何在安全区域内进行展示。

移动端布局适配心得,关于移动端适配

contain: 可视窗口完全包含网页内容

cover:网页内容完全覆盖可视窗口

默认情况下或者设置为 auto和 contain效果相同。

7.3 env、constant

移动端布局适配心得,关于移动端适配

我们需要将顶部和底部合理的摆放在安全区域内, iOS11新增了两个 CSS函数 env、constant,用于设定安全区域与边界的距离。

函数内部可以是四个常量:

  • safe-area-inset-left:安全区域距离左边边界距离
  • safe-area-inset-right:安全区域距离右边边界距离
  • safe-area-inset-top:安全区域距离顶部边界距离
  • safe-area-inset-bottom:安全区域距离底部边界距离

注意:我们必须指定 viweport-fit后才能使用这两个函数:

<meta name="viewport" content="viewport-fit=cover">

constant在 iOS<11.2的版本中生效, env在 iOS>=11.2的版本中生效,这意味着我们往往要同时设置他们,将页面限制在安全区域内:

body { padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom);}

当使用底部固定导航栏时,我们要为他们设置 padding值:

{ padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom);}

八、横屏适配

移动端布局适配心得,关于移动端适配

很多视口我们要对横屏和竖屏显示不同的布局,所以我们需要检测在不同的场景下给定不同的样式:

8.1 JavaScript检测横屏

window.orientation:获取屏幕旋转方向

window.addEventListener("resize", ()=>{ if (window.orientation === 180 || window.orientation === 0) { // 正常方向或屏幕旋转180度 console.log('竖屏'); }; if (window.orientation === 90 || window.orientation === -90 ){ // 屏幕顺时钟旋转90度或屏幕逆时针旋转90度 console.log('横屏'); } });

8.2 CSS检测横屏

@media screen and (orientation: portrait) { } @media screen and (orientation: landscape) { }

九、图片模糊问题

9.1 产生原因

我们平时使用的图片大多数都属于位图( png、jpg...),位图由一个个像素点构成的,每个像素都具有特定的位置和颜色值:

移动端布局适配心得,关于移动端适配

理论上,位图的每个像素对应在屏幕上使用一个物理像素来渲染,才能达到最佳的显示效果。

而在 dpr>1的屏幕上,位图的一个像素可能由多个物理像素来渲染,然而这些物理像素点并不能被准确的分配上对应位图像素的颜色,只能取近似值,所以相同的图片在 dpr>1的屏幕上就会模糊:

移动端布局适配心得,关于移动端适配

9.2 解决方案

为了保证图片质量,我们应该尽可能让一个屏幕像素来渲染一个图片像素,所以,针对不同 DPR的屏幕,我们需要展示不同分辨率的图片。

如:在 dpr=2的屏幕上展示两倍图 (@2x),在 dpr=3的屏幕上展示三倍图 (@3x)。

移动端布局适配心得,关于移动端适配

9.3 media查询

使用 media查询判断不同的设备像素比来显示不同精度的图片:

.avatar{ background-image: url(conardLi_1x.png); } @media only screen and (-webkit-min-device-pixel-ratio:2){ .avatar{ background-image: url(conardLi_2x.png); } } @media only screen and (-webkit-min-device-pixel-ratio:3){ .avatar{ background-image: url(conardLi_3x.png); } }

只适用于背景图

9.4 image-set

使用 image-set:

.avatar { background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x );}

只适用于背景图

9.5 srcset

使用 img标签的 srcset属性,浏览器会自动根据像素密度匹配最佳显示图片:

<img src="conardLi_1x.png" srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">

9.6 JavaScript拼接图片url

使用 window.devicePixelRatio获取设备像素比,遍历所有图片,替换图片地址:

const dpr = window.devicePixelRatio;const images = document.querySelectorAll('img');images.forEach((img)=>{ img.src.replace(".", `@${dpr}x.`);})

9.7 使用svg

SVG的全称是可缩放矢量图( ScalableVectorGraphics)。不同于位图的基于像素, SVG则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。

移动端布局适配心得,关于移动端适配

除了我们手动在代码中绘制 svg,我们还可以像使用位图一样使用 svg图片:

<img src="conardLi.svg"><img src="data:image/svg+xml;base64,[data]">.avatar { background: url(conardLi.svg);}

2、移动端布局适配心得,移动端上遇到的各种坑与相对解决方案

mobileHack

这里收集了许多移动端上遇到的各种坑与相对解决方案

1.问题:手机端 click 事件会有大约 300ms 的延迟

原因:手机端事件 touchstart –> touchmove –> touchend or touchcancel –> click,因为在touch事件触发之后,浏览器要判断用户是否会做出双击屏幕的操作,所以会等待300ms来判断,再做出是否触发click事件的处理,所以就会有300ms的延迟

解决方法:使用touch事件来代替click事件,如 zepto.js 的tap事件和fastClick,还有我自己也写了个移动端手势操作库mTouch,都有相应的事件可以代替click事件解决这个问题

2.问题:在部分机型下(如小米4、小米2s、中兴) body 设置的 font-size 是用 rem 单位的话,若其他元素没有设置font-size,该font-size值继承于body,则会很高概率出现字体异常变大的情况

原因:估计是跟app的webview默认设置有关,body的font-size使用rem单位,就是相对于当前根节点的font-size来确定的,可能在某些webview的设置下,body用的是webview设置的默认字体大小,因为在我给html设置了一个px单位的默认font-size时,还是会出现字体异常变大的情况,具体webview的一些细节就没有再研究了

解决方法:body设置一个px单位的默认font-size值,不用rem,或者给字体会异常变大的元素设定一个px单位的font-size值

  • width - viewport的宽度

  • height - viewport的高度

  • initial-scale - 初始的缩放比例

  • minimum-scale - 允许用户缩放到的最小比例

  • maximum-scale - 允许用户缩放到的最大比例

  • user-scalable - 用户是否可以手动缩放

  • 第二个meta标签是iphone设备中的safari私有meta标签,它表示:允许全屏模式浏览;

    第三个meta标签也是iphone的私有标签,它指定的iphone中safari顶端的状态条的样式;

    第四个meta标签表示:告诉设备忽略将页面中的数字识别为电话号码

    在设置了initial-scale=1 之后,我们终于可以以1:1 的比例进行页面设计了。

    关于viewport,还有一个很重要的概念是:iphone 的Safari 浏览器完全没有滚动条,而且不是简单的“隐藏滚动条”,

    是根本没有这个功能。iphone 的safari 浏览器实际上从一开始就完整显示了这个网页,然后用viewport 查看其中的一部分。

    当你用手指拖动时,其实拖的不是页面,而是viewport。浏览器行为的改变不止是滚动条,交互事件也跟普通桌面不一样。

    (请参考:指尖的下JS 系列文章)

    更详细的 viewport 相关的知识也可以参考

    此像素非彼像素

    移动开发事件

    手机浏览器常用手势动作监听封装

    手势事件

    • touchstart //当手指接触屏幕时触发

    • touchmove //当已经接触屏幕的手指开始移动后触发

    • touchend //当手指离开屏幕时触发

    • touchcancel

    触摸事件

    • gesturestart //当两个手指接触屏幕时触发

    • gesturechange //当两个手指接触屏幕后开始移动时触发

    • gestureend

    屏幕旋转事件

    • onorientationchange

    检测触摸屏幕的手指何时改变方向

    • orientationchange

    touch事件支持的相关属性

    • touches

    • targetTouches

    • changedTouches

    • clientX    // X coordinate of touch relative to the viewport (excludes scroll offset)

    • clientY    // Y coordinate of touch relative to the viewport (excludes scroll offset)

    • screenX    // Relative to the screen

    • screenY    // Relative to the screen

    • pageX     // Relative to the full page (includes scrolling)

    • pageY     // Relative to the full page (includes scrolling)

    • target     // Node the touch event originated from

    • identifier   // An identifying number, unique to each touch event

    • 屏幕旋转事件:onorientationchange

    判断屏幕是否旋转

    function orientationChange() {

    JS 单击延迟

    click 事件因为要等待单击确认,会有 300ms 的延迟,体验并不是很好。

    开发者大多数会使用封装的 tap 事件来代替click 事件,所谓的 tap 事件由 touchstart 事件 touchmove 判断 touchend 事件封装组成。

    Creating Fast Buttons for Mobile Web Applications

    Eliminate 300ms delay on click events in mobile Safari

    WebKit CSS:

    携程 UED 整理的 Webkit CSS 文档 ,全面、方便查询,下面为常用属性。

    ①“盒模型”的具体描述性质的包围盒块内容,包括边界,填充等等。

    css

    -webkit-border-bottom-left-radius: radius;

    -webkit-border-top-left-radius: horizontal_radius vertical_radius;

    -webkit-border-radius: radius; //容器圆角

    -webkit-box-sizing: sizing_model; 边框常量值:border-box/content-box

    -webkit-box-shadow: hoff voff blur color;

    -webkit-margin-bottom-collapse: collapse_behavior;

    -webkit-margin-start: width;

    -webkit-padding-start: width;

    -webkit-border-image: url(borderimg.gif) 25 25 25 25 round/stretch round/stretch;

    -webkit-appearance: push-button;

    ②“视觉格式化模型”描述性质,确定了位置和大小的块元素。

    direction: rtl

    ③“视觉效果”描述属性,调整的视觉效果块内容,包括溢出行为,调整行为,能见度,动画,变换,和过渡。

    clip: rect(10px, 5px, 10px, 5px)

    ④“生成的内容,自动编号,并列出”描述属性,允许您更改内容的一个组成部分,创建自动编号的章节和标题,和操纵的风格清单的内容。

    content: “Item” counter(section) ” “;

    ⑤“分页媒体”描述性能与外观的属性,控制印刷版本的网页,如分页符的行为。

    page-break-after: auto; 常量:always/auto/avoid/left/right

    ⑥“颜色和背景”描述属性控制背景下的块级元素和颜色的文本内容的组成部分。

    -webkit-background-clip: content; 常量:border/content/padding/text

    ⑦ “字型”的具体描述性质的文字字体的选择范围内的一个因素。报告还描述属性用于下载字体定义。

    unicode-range: U 00-FF, U 980-9FF;

    ⑧“文本”描述属性的特定文字样式,间距和自动滚屏。

    text-shadow: #00FFFC 10px 10px 5px;

    ⑨“表格”描述的布局和设计性能表的具体内容。

    -webkit-border-horizontal-spacing: 2px;

    ⑩“用户界面”描述属性,涉及到用户界面元素在浏览器中,如滚动文字区,滚动条,等等。报告还描述属性,范围以外的网页内容,如光标的标注样式和显示当您按住触摸触摸

    目标,如在iPhone上的链接。

    -webkit-box-align: baseline,center,end,start,stretch 常量:baseline/center/end/start/stretch

    动画过渡

    这是 Webkit 中最具创新力的特性:使用过渡函数定义动画。

    -webkit-animation: title infinite ease-in-out 3s;

    这些同样是可以简写的。但真正让我觉的很爽的是keyframes,它能定义一个动画的转变过程供调用,过程为0%到100%或from(0%)到to(100%)。简单点说,只要你有想法,你想让元素在这个过程中以什么样的方式改变都是很简单的。

    -webkit-transform: 类型(缩放scale/旋转rotate/倾斜skew/位移translate)

    页面描述

    <link rel="apple-touch-icon-precomposed" href="http://www.xxx.com/App_icon_114.png" />

    这个属性是当用户把连接保存到手机桌面时使用的图标,如果不设置,则会用网页的截图。有了这,就可以让你的网页像APP一样存在手机里了

    <link rel="apple-touch-startup-image" href="/img/startup.png" />

    这个是APP启动画面图片,用途和上面的类似,如果不设置,启动画面就是白屏,图片像素就是手机全屏的像素

    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />

    这个描述是表示打开的web app的最上面的时间、信号栏是黑色的,当然也可以设置其它参数,详细参数说明请参照:Safari HTML Reference - Supported Meta Tags

    <meta name="apple-touch-fullscreen" content="yes" />

    常见的 iPhone 和 Android 屏幕参数。

    • 设备 分辨率 设备像素比率

    • Android LDPI 320×240 0.75

    • Iphone 3 & Android MDPI 320×480 1

    • Android HDPI 480×800 1.5

    • Iphone 4 960×640 2.0

    iPhone 4的一个 CSS 像素实际上表现为一块 2×2 的像素。所以图片像是被放大2倍一样,模糊不清晰。

    解决办法:

    1、页面引用

    <link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 0.75)" href="ldpi.css" />

    2、CSS文件里

    #header {

    移动 Web 开发经验技巧

    点击与click事件

    对于a标记的点击导航,默认是在onclick事件中处理的。而移动客户端对onclick的响应相比PC浏览器有着明显的几百毫秒延迟。

    在移动浏览器中对触摸事件的响应顺序应当是:

    ontouchstart -> ontouchmove -> ontouchend -> onclick

    因此,如果确实要加快对点击事件的响应,就应当绑定ontouchend事件。

    使用click会出现绑定点击区域闪一下的情况,解决:给该元素一个样式如下

    -webkit-tap-highlight-color: rgba(0,0,0,0);

    如果不使用click,也不能简单的用touchstart或touchend替代,需要用touchstart的模拟一个click事件,并且不能发生touchmove事件,或者用zepto中的tap(轻击)事件。

    body

    用iphone或ipad浏览很长的网页滚动时的滑动效果很不错吧?不过如果是一个div,然后设置height:200px;overflow:auto;的话,可以滚动但是完全没有那滑动效果,很郁闷吧?

    我看到很多网站为了实现这一效果,用了第三方类库,最常用的是iscroll(包括新浪手机页,百度等)

    我一开始也使用,不过自从用了-webkit-overflow-scrolling: touch;样式后,就完全可以抛弃第三方类库了,把它加在body{}区域,所有的overflow需要滚动的都可以生效了。

    另外有一篇比较全的移动端点击解决方案 http://www.zhihu.com/question/28979857

    锁定 viewport

    ontouchmove="event.preventDefault()" //锁定viewport,任何屏幕操作不移动用户界面(弹出键盘除外)。

    利用 Media Query监听

    Media Query 相信大部分人已经使用过了。其实 JavaScript可以配合 Media Query这么用:

    var mql = window.matchMedia("(orientation: portrait)");

    借助了 Media Query 接口做的事件监听,所以很强大!

    也可以通过获取 CSS 值来使用 Media Query 判断设备情况,详情请看:JavaScript 依据 CSS Media Queries 判断设备的方法。

    rem最佳实践

    rem是非常好用的一个属性,可以根据html来设定基准值,而且兼容性也很不错。不过有的时候还是需要对一些莫名其妙的浏览器优雅降级。以下是两个实践

    1. http://jsbin.com/vaqexuge/4/edit 这有个demo,发现chrome当font-size小于12时,rem会按照12来计算。因此设置基准值要考虑这一点

    2. 可以用以下的代码片段保证在低端浏览器下也不会出问题

      html { font-size: 62.5%; }

      body { font-size: 14px; font-size: 1.4rem; }

      h1 { font-size: 24px; font-size: 2.4rem; }

    被点击元素的外观变化,可以使用样式来设定:

    -webkit-tap-highlight-color: 颜色

    检测判断 iPhone/iPod

    开发特定设备的移动网站,首先要做的就是设备侦测了。下面是使用Javascript侦测iPhone/iPod的UA,然后转向到专属的URL。

    if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) {

    虽然Javascript是可以在水果设备上运行的,但是用户还是可以禁用。它也会造成客户端刷新和额外的数据传输,所以下面是服务器端侦测和转向:

    if(strstr($_SERVER['HTTP_USER_AGENT'],'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'],'iPod')) {

    阻止旋转屏幕时自动调整字体大小

    html, body, form, fieldset, p, div, h1, h2, h3, h4, h5, h6 {-webkit-text-size-adjust:none;}

    模拟:hover伪类

    因为iPhone并没有鼠标指针,所以没有hover事件。那么CSS :hover伪类就没用了。但是iPhone有Touch事件,onTouchStart 类似 onMouseOver,onTouchEnd 类似 onMouseOut。所以我们可以用它来模拟hover。使用Javascript:

    var myLinks = document.getElementsByTagName('a');

    然后用CSS增加hover效果:

    a:hover, a.hover { }

    这样设计一个链接,感觉可以更像按钮。并且,这个模拟可以用在任何元素上。

    Flexbox 布局

    Flex 模板和实例

    深入了解 Flexbox 伸缩盒模型

    CSS Flexbox Intro

    http://www.w3.org/TR/css3-flexbox/

    居中问题

    居中是移动端跟pc端共同的噩梦。这里有两种兼容性比较好的新方案。

    • table布局法

      .box{

      text-align:center;

      display:table-cell;

      vertical-align:middle;

      }

    • 老版本flex布局法

      .box{

      display:-webkit-box;

      -webkit-box-pack: center;

      -webkit-box-align: center;

      text-align:center;

      }

    以上两种其实分别是retchat跟ionic的布局基石。

    这里有更详细的更多的选择http://www.zhouwenbin.com/垂直居中的几种方法/ 来自周文彬的博客

    移动端实现标题文字截断

    http://www.75team.com/archives/611

    处理 Retina 双倍屏幕

    (经典)Using CSS Sprites to optimize your website for Retina Displays

    使用CSS3的background-size优化苹果的Retina屏幕的图像显示

    使用 CSS sprites 来优化你的网站在 Retina 屏幕下显示

    (案例)CSS IMAGE SPRITES FOR RETINA (HIRES) DEVICES

    input类型为date情况下不支持placeholder(来自于江水)

    这其实是浏览器自己的处理。因为浏览器会针对此类型 input 增加 datepicker 模块。

    对 input type date 使用 placeholder 的目的是为了让用户更准确的输入日期格式,iOS 上会有 datepicker 不会显示 placeholder 文字,但是为了统一表单外观,往往需要显示。Android 部分机型没有 datepicker 也不会显示 placeholder 文字。

    桌面端(Mac)

    • Safari 不支持 datepicker,placeholder 正常显示。

    • Firefox 不支持 datepicker,placeholder 正常显示。

    • Chrome 支持 datepicker,显示 年、月、日 格式,忽略 placeholder。

    移动端

    • iPhone5 iOS7 有 datepicker 功能,但是不显示 placeholder。

    • Andorid 4.0.4 无 datepicker 功能,不显示 placeholder

    解决方法:

    <input placeholder="Date" class="textbox-n" type="text" onfocus="(this.type='date')" id="date">

    因为text是支持placeholder的。因此当用户focus的时候自动把type类型改变为date,这样既有placeholder也有datepicker了

    判断照片的横竖排列

    有这样一种需求,需要判断用户照片是横着拍出来的还是竖着拍出来的,这里需要使用照片得exif信息:

    $("input").change(function() {

    可以使用这两个库 来取exif信息http://www.nihilogic.dk/labs/binaryajax/binaryajax.js http://www.nihilogic.dk/labs/exif/exif.js

    Android上当viewport的width大于device-width时出现文字无故折行的解决办法

    http://www.iunbug.com/archives/2013/04/23/798.html

    白屏解决与优化方案

    当前很多无线页面都使用前端模板进行数据渲染,那么在糟糕的网速情况下,一进去页面,看到的不是白屏就是 loading,这成为白屏问题。

    此问题发生的原因基本可以归结为网速跟静态资源

    1、css文件加载需要一些时间,在加载的过程中页面是空白的。 解决:可以考虑将css代码前置和内联。

    2、首屏无实际的数据内容,等待异步加载数据再渲染页面导致白屏。 解决:在首屏直接同步渲染html,后续的滚屏等再采用异步请求数据和渲染html。

    3、首屏内联js的执行会阻塞页面的渲染。 解决:尽量不在首屏html代码中放置内联脚本。(来自翔歌)

    解决方案

    根本原因是客户端渲染的无力,因此最简单的方法是在服务器端,使用模板引擎渲染所有页面。同时

    1减少文件加载体积,如html压缩,js压缩

    2加快js执行速度 比如常见的无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西

    3提供一些友好的交互,比如提供一些假的滚动条

    4使用本地存储处理静态文件。

    如何实现打开已安装的app,若未安装则引导用户安装?

    来自 http://gallery.kissyui.com/redirectToNative/1.2/guide/index.html kissy mobile

    通过iframe src发送请求打开app自定义url scheme,如taobao://home(淘宝首页) 、etao://scan(一淘扫描));

    如果安装了客户端则会直接唤起,直接唤起后,之前浏览器窗口(或者扫码工具的webview)推入后台;

    如果在指定的时间内客户端没有被唤起,则js重定向到app下载地址。

    大概实现代码如下

    goToNative:function(){

    需要注意的是 如果是android chrome 25版本以后,在iframe src不会发送请求,

    原因如下https://developers.google.com/chrome/mobile/docs/intents ,通过location href使用intent机制拉起客户端可行并且当前页面不跳转。

    window.location = 'intent://' schemeUrl '#Intent;scheme=' scheme ';package=' self.package ';end';

    补充一个来自三水清的详细讲解 http://js8.in/2013/12/16/ios使用schema协议调起app/

    active的兼容(来自薛端阳)

    今天发现,要让a链接的CSS active伪类生效,只需要给这个a链接的touch系列的任意事件touchstart/touchend绑定一个空的匿名方法即可hack成功

    <style>

    消除transition闪屏

    两个方法:使用css3动画的时尽量利用3D加速,从而使得动画变得流畅。动画过程中的动画闪白可以通过 backface-visibility 隐藏。

    -webkit-transform-style: preserve-3d;

    测试是否支持svg图片

    document.implementation.hasFeature("http:// www.w3.org/TR/SVG11/feature#Image", "1.1")

    考虑兼容“隐私模式”(from http://blog.youyo.name/archives/smarty-phones-webapp-deverlop-advance.html)

    ios的safari提供一种“隐私模式”,如果你的webapp考虑兼容这个模式,那么在使用HTML5的本地存储的一种————localStorage时,可能因为“隐私模式”下没有权限读写localstorge而使代码抛出错误,导致后续的js代码都无法运行了。

    既然在safari的“隐私模式”下,没有调用localStorage的权限,首先想到的是先判断是否支持localStorage,代码如下:

    if('localStorage' in window){

    测试发现,即使在safari的“隐私模式”下,’localStorage’ in window的返回值依然为true,也就是说,if代码块内部的代码依然会运行,问题没有得到解决。

    接下来只能相当使用try catch了,虽然这是一个不太推荐被使用的方法,使用try catch捕获错误,使后续的js代码可以继续运行,代码如下:

    try{

    所以,提醒大家注意,在需要兼容ios的safari的“隐私模式”的情况下,本地存储相关的代码需要使用try catch包裹并降级兼容。

    安卓手机点击锁定页面效果问题

    有些安卓手机,页面点击时会停止页面的javascript,css3动画等的执行,这个比较蛋疼。不过可以用阻止默认事件解决。详细见

    http://stackoverflow.com/questions/10246305/android-browser-touch-events-stop-display-being-updated-inc-canvas-elements-h

    function touchHandlerDummy(e)

    消除ie10里面的那个叉号

    IE Pseudo-elements

    input:-ms-clear{display:none;}

    关于ios与os端字体的优化(横竖屏会出现字体加粗不一致等)

    mac下网页中文字体优化

    UIWebView font is thinner in portrait than landscape

    判断用户是否是“将网页添加到主屏后,再从主屏幕打开这个网页”的

    navigator.standalone

    隐藏地址栏 & 处理事件的时候,防止滚动条出现:

    // 隐藏地址栏 & 处理事件的时候 ,防止滚动条出现

    ios7 可以通过meta标签的minimal来隐藏地址栏了

    http://darkblue.sdf.org/weblog/ios-7-dot-1-mobile-safari-minimal-ui.html

    判断是否为iPhone:

    // 判断是否为 iPhone :

    localStorage:

    var v = localStorage.getItem('n') ? localStorage.getItem('n') : ""; // 如果名称是 n 的数据存在 ,则将其读出 ,赋予变量 v 。

    使用特殊链接:

    如果你关闭自动识别后 ,又希望某些电话号码能够链接到 iPhone 的拨号功能 ,那么可以通过这样来声明电话链接 ,

    <a href="tel:12345654321">打电话给我</a>

    或用于单元格:

    <td onclick="location.href='tel:122'">

    自动大写与自动修正

    要关闭这两项功能,可以通过autocapitalize 与autocorrect 这两个选项:

    <input type="text" autocapitalize="off" autocorrect="off" />

    不让 Android 识别邮箱

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

    禁止 iOS 弹出各种操作窗口

    -webkit-touch-callout:none

    禁止用户选中文字

    -webkit-user-select:none

    动画效果中,使用 translate 比使用定位性能高

    Why Moving Elements With Translate() Is Better Than Pos:abs Top/left

    拿到滚动条

    window.scrollY

    比如要绑定一个touchmove的事件,正常的情况下类似这样(来自呼吸二氧化碳)

    $('div').on('touchmove', function(){

    而如果中间的code需要处理的东西多的话,fps就会下降影响程序顺滑度,而如果改成这样

    $('div').on('touchmove', function(){

    把代码放在setTimeout中,会发现程序变快.

    关于 iOS 系统中,Web APP 启动图片在不同设备上的适应性设置

    http://stackoverflow.com/questions/4687698/mulitple-apple-touch-startup-image-resolutions-for-ios-web-app-esp-for-ipad/10011893#10011893

    position:sticky与position:fixed布局

    http://www.zhouwenbin.com/positionsticky-粘性布局/

    http://www.zhouwenbin.com/sticky模拟问题/

    关于 iOS 系统中,中文输入法输入英文时,字母之间可能会出现一个六分之一空格

    可以通过正则去掉

    this.value = this.value.replace(/\u2006/g, '');

    关于android webview中,input元素输入时出现的怪异情况

    见下图

    移动端布局适配心得,关于移动端适配

    Android Web 视图,至少在 HTC EVO 和三星的 Galaxy Nexus 中,文本输入框在输入时表现的就像占位符。情况为一个类似水印的东西在用户输入区域,一旦用户开始输入便会消失(见图片)。

    在 Android 的默认样式下当输入框获得焦点后,若存在一个绝对定位或者 fixed 的元素,布局会被破坏,其他元素与系统输入字段会发生重叠(如搜索图标将消失为搜索字段),可以观察到布局与原始输入字段有偏差(见截图)。

    这是一个相当复杂的问题,以下简单布局可以重现这个问题:

    <label for="phone">Phone: *</label>

    解决方法

    -webkit-user-modify: read-write-plaintext-only

    详细参考http://www.bielousov.com/2012/android-label-text-appears-in-input-field-as-a-placeholder/

    注意,该属性会导致中文不能输入词组,只能单个字。感谢鬼哥与飞(游勇飞)贡献此问题与解决方案

    另外,在position:fixed后的元素里,尽量不要使用输入框。更多的bug可参考

    http://www.cosdiv.com/page/M0/S882/882353.html

    依旧无法解决(摩托罗拉ME863手机),则使用input:text类型而非password类型,并设置其设置 -webkit-text-security: disc; 隐藏输入密码从而解决。

    JS动态生成的select下拉菜单在Android2.x版本的默认浏览器里不起作用

    解决方法删除了overflow-x:hidden; 然后在JS生成下来菜单之后focus聚焦,这两步操作之后解决了问题。(来自岛都-小Qi)

    参考http://stackoverflow.com/questions/4697908/html-select-control-disabled-in-android-webview-in-emulator

    Andriod 上去掉语音输入按钮

    input::-webkit-input-speech-button {display: none}

    IE10 的特殊鼠标事件

    IE10 事件监听

    iOS 输入框最佳实践

    Mobile-friendly input of a digits spaces string (a credit card number)

    HTML5 input type number vs tel

    iPhone: numeric keyboard for text input

    Text Programming Guide for iOS - Managing the Keyboard

    HTML5 inputs and attribute support

    往返缓存问题

    点击浏览器的回退,有时候不会自动执行js,特别是在mobilesafari中。这与往返缓存(bfcache)有关系。有很多hack的处理方法,可以参考

    http://stackoverflow.com/questions/24046/the-safari-back-button-problem

    http://stackoverflow.com/questions/11979156/mobile-safari-back-button

    不暂停的计时器(safari的进程冻结)

    https://www.imququ.com/post/ios-none-freeze-timer.html

    或者可以用postmessage方式:

    主页面:

    // 解决ios safari tab在后台会遭遇进程冻结问题

    worker:

    // 解决ios safari tab在后台会遭遇进程冻结问题

    Web移动端Fixed布局的解决方案

    http://efe.baidu.com/blog/mobile-fixed-layout/

    ios上background-attachment:fixed不能正常工作

    参考 http://stackoverflow.com/questions/20443574/fixed-background-image-with-ios7

    如何让音频跟视频在ios跟android上自动播放

    <audio autoplay ><source src="http://img.studyofnet.comaudio/alarm1.mp3" type="audio/mpeg"></audio>

    系统默认情况下 audio的autoplay属性是无法生效的,这也是手机为节省用户流量做的考虑。

    如果必须要自动播放,有两种方式可以解决。

    1.捕捉一次用户输入后,让音频加载,下次即可播放。

    //play and pause it once

    这种方法需要捕获一次用户的点击事件来促使音频跟视频加载。当加载后,你就可以用javascript控制音频的播放了,如调用audio.play()

    2.利用iframe加载资源

    var ifr=document.createElement("iframe");

    这种方式其实跟第一种原理是一样的。当资源加载了你就可以控制播放了,但是这里使用iframe来加载,相当于直接触发资源加载。

    注意,使用创建audio标签并让其加载的方式是不可行的。

    慎用这种方法,会对用户造成很糟糕的影响。。

    iOS 6 跟 iPhone 5 的那些事

    IP5 的媒体查询

    @media (device-height: 568px) and (-webkit-min-device-pixel-ratio: 2) {

    使用媒体查询,提供不同的启动图片:

    <link href="startup-568h.png" rel="apple-touch-startup-image" media="(device-height: 568px)">

    拍照上传

    <input type=file accept="video/*">

    不支持其他类型的文件 ,如音频,Pages文档或PDF文件。 也没有getUserMedia摄像头的实时流媒体支持。

    可以使用的 HTML5 高级 api

    • multipart POST 表单提交上传

    • XMLHttpRequest 2 AJAX 上传(甚至进度支持)

    • 文件 API ,在 iOS 6 允许 JavaScript 直接读取的字节数和客户端操作文件。

    智能应用程序横幅

    有了智能应用程序横幅,当网站上有一个相关联的本机应用程序时,Safari浏览器可以显示一个横幅。 如果用户没有安装这个应用程序将显示“安装”按钮,或已经安装的显示“查看”按钮可打开它。

    在 iTunes Link Maker 搜索我们的应用程序和应用程序ID。

    <meta name="apple-itunes-app" content="app-id=9999999">

    可以使用 app-argument 提供字符串值,如果参加iTunes联盟计划,可以添加元标记数据

    <meta name="apple-itunes-app" content="app-id=9999999, app-argument=xxxxxx">

    横幅需要156像素(设备是312 hi-dpi)在顶部,直到用户在下方点击内容或关闭按钮,你的网站才会展现全部的高度。 它就像HTML的DOM对象,但它不是一个真正的DOM。

    CSS3 滤镜

    -webkit-filter: blur(5px) grayscale (.5) opacity(0.66) hue-rotate(100deg);

    交叉淡变

    background-image: -webkit-cross-fade(url("logo1.png"), url("logo2.png"), 50%);

    Safari中的全屏幕

    除了chrome-less 主屏幕meta标签,现在的iPhone和iPod Touch(而不是在iPad)支持全屏幕模式的窗口。 没有办法强制全屏模式,它需要由用户启动(工具栏上的最后一个图标)。需要引导用户按下屏幕上的全屏图标来激活全屏效果。 可以使用onresize事件检测是否用户切换到全屏幕。

    支持requestAnimationFrameAPI

    支持image-set,retina屏幕的利器

    -webkit-image-set(url(low.png) 1x, url(hi.jpg) 2x)

    应用程序缓存限制增加至25MB。

    Web View(pseudobrowsers,PhoneGap/Cordova应用程序,嵌入式浏览器) 上Javascript运行比Safari慢3.3倍(或者说,Nitro引擎在Safari浏览器是Web应用程序是3.3倍速度)。

    autocomplete属性的输入遵循DOM规范

    来自DOM4的Mutation Observers已经实现。 您可以使用WebKitMutationObserver构造器捕获DOM的变化

    Safari不再总是对用 -webkit-transform:preserve-3d 的元素创建硬件加速

    支持window.selection 的Selection API

    Canvas更新 :createImageData有一个参数,现在有两个新的功能做好准备,用webkitGetImageDataHD和webkitPutImageDataHD提供高分辨率图像 。

    更新SVG处理器和事件构造函数

    IOS7的大更新

    iOS 7 的 Safari 和 HTML5:问题,变化和新 API(张金龙翻译)

    iOS 7 的一些坑(英文)

    ios7的一些坑2(英文)

    webview相关

    Cache开启和设置

    browser.getSettings().setAppCacheEnabled(true);

    LocalStorage相关设置

    browser.getSettings().setDatabaseEnabled(true);

    浏览器自带缩放按钮取消显示

    browser.getSettings().setBuiltInZoomControls(false);

    几个比较好的实践

    使用localstorage缓存html

    使用lazyload,还要记得lazyload占位图虽然小,但是最好能提前加载到缓存

    延时加载执行js

    主要原因就在于Android Webview的onPageFinished事件,Android端一般是用这个事件来标识页面加载完成并显示的,也就是说在此之前,会一直loading,但是Android的OnPageFinished事件会在Javascript脚本执行完成之后才会触发。如果在页面中使用jQuery,会在处理完DOM对象,执行完$(document).ready(function() {});事件自会后才会渲染并显示页面。

    manifest与缓存相关:

    http://www.alloyteam.com/2013/12/web-cache-6-hybrid-app-tailored-cache/

    相关解决方案

    http://mt.tencent.com/

    移动端调适篇

    手机抓包与配host

    在PC上,我们可以很方便地配host,但是手机上如何配host,这是一个问题。

    这里主要使用fiddler和远程代理,实现手机配host的操作,具体操作如下:

    首先,保证PC和移动设备在同一个局域网下;

    PC上开启fiddler,并在设置中勾选“allow remote computers to connect”

    1. 首先,保证PC和移动设备在同一个局域网下;

    2. PC上开启fiddler,并在设置中勾选“allow remote computers to connect”

    3. 手机上设置代理,代理IP为PC的IP地址,端口为8888(这是fiddler的默认端口)。通常手机上可以直接设置代理,如果没有,可以去下载一个叫ProxyDroid的APP来实现代理的设置。

    移动端布局适配心得,关于移动端适配

    1. 此时你会发现,用手机上网,走的其实是PC上的fiddler,所有的请求包都会在fiddler中列出来,配合willow使用,即可实现配host,甚至是反向代理的操作。

    也可以用CCProxy之类软件,还有一种方法就是买一个随身wifi,然后手机连接就可以了!

    高级抓包

    iPhone上使用Burp Suite捕捉HTTPS通信包方法

    mobile app 通信分析方法小议(iOS/Android)

    实时抓取移动设备上的通信包(ADVsock2pipe Wireshark nc tcpdump)

    静态资源缓存问题

    一般用代理软件代理过来的静态资源可以设置nocache避免缓存,但是有的手机比较诡异,会一直缓存住css等资源文件。由于静态资源一般都是用版本号管理的,我们以charles为例子来处理这个问题

    charles 选择静态的html页面文件-saveResponse。之后把这个文件保存一下,修改一下版本号。之后继续发请求,

    刚才的html页面文件 右键选择 –map local 选择我们修改过版本号的html文件即ok。这其实也是fiddler远程映射并修改文件的一个应用场景。

    安卓模拟器和真机区别

    http://www.farsight.com.cn/news/emb105.htm

    http://testerhome.com/topics/388

    http://www.cnblogs.com/zdz8207/archive/2012/01/30/2332436.html

    移动浏览器篇

    微信浏览器

    微信浏览器的各种bug汇总 (x5内核) http://www.qianduan.net/qqliu-lan-qi-x5nei-he-wen-ti-hui-zong/

    因为微信浏览器屏蔽了一部分链接图片,所以需要引导用户去打开新页面,可以用以下方式判断微信浏览器的ua

    function is_weixn(){

    后端判断也很简单,比如PHP

    function is_weixin(){

    https://github.com/maxzhang/maxzhang.github.com/issues/31 微信浏览器踩坑,来自maxZhang https://github.com/maxzhang

    【UC浏览器】video标签脱离文档流

    场景:标签的父元素(祖辈元素)设置transform样式后,标签会脱离文档流。

    测试环境:UC浏览器 8.7/8.6 Android 2.3/4.0 。

    Demo:http://t.cn/zj3xiyu

    解决方案:不使用transform属性。translate用top、margin等属性替代。

    【UC浏览器】video标签总在最前

    场景:标签总是在最前(可以理解为video标签的z-index属性是Max)。

    测试环境:UC浏览器 8.7/8.6 Android 2.3/4.0 。

    【UC浏览器】position:fixed 属性在UC浏览器的奇葩现象

    场景:设置了position: fixed 的元素会遮挡z-index值更高的同辈元素。

    在8.6的版本,这个情况直接出现。

    在8.7之后的版本,当同辈元素的height大于713这个「神奇」的数值时,才会被遮挡。

    测试环境:UC浏览器 8.8_beta/8.7/8.6 Android 2.3/4.0 。

    Demo:http://t.cn/zYLTSg6

    【QQ手机浏览器】不支持HttpOnly

    场景:带有HttpOnly属性的Cookie,在QQ手机浏览器版本从4.0开始失效。JavaScript可以直接读取设置了HttpOnly的Cookie值。

    测试环境:QQ手机浏览器 4.0/4.1/4.2 Android 4.0 。

    【MIUI原生浏览器】浏览器地址栏hash不改变

    场景:location.hash 被赋值后,地址栏的地址不会改变。

    但实际上 location.href 已经更新了,通过JavaScript可以顺利获取到更新后的地址。

    虽然不影响正常访问,但用户无法将访问过程中改变hash后的地址存为书签。

    测试环境:MIUI 4.0

    【Chrome Mobile】fixed元素无法点击

    场景:父元素设置position: fixed;

    子元素设置position: absolute;

    此时,如果父元素/子元素还设置了overflow: hidden 则出现“父元素遮挡该子元素“的bug。

    视觉(view)层并没有出现遮挡,只是无法触发绑定在该子元素上的事件。可理解为:「看到点不到」。

    补充: 页面往下滚动,触发position: fixed;的特性时,才会出现这个bug,在最顶不会出现。

    测试平台: 小米1S,Android4.0的Chrome18

    demo: http://maplejan.sinaapp.com/demo/fixed_chromemobile.html

    解决办法: 把父元素和子元素的overflow: hidden去掉。

    以上来源于 http://www.cnblogs.com/maplejan/archive/2013/04/26/3045928.html

    库的使用实践

    zepto.js

    zepto的一篇使用注意点讲解

    zepto的著名的tap“点透”bug

    zepto源码注释

    使用zeptojs内嵌到android webview影响正常滚动时

    https://github.com/madrobby/zepto/blob/master/src/touch.js 去掉61行,其实就是使用原生的滚动

    iscroll4

    iscroll4 的几个bug(来自 http://www.mansonchor.com/blog/blog_detail_64.html 内有详细讲解)

    1.滚动容器点击input框、select等表单元素时没有响应】

    onBeforeScrollStart: function (e) { e.preventDefault(); }

    改为

    onBeforeScrollStart: function (e) { var nodeType = e.explicitOriginalTarget © e.explicitOriginalTarget.nodeName.toLowerCase():(e.target © e.target.nodeName.toLowerCase():'');if(nodeType !='select'&& nodeType !='option'&& nodeType !='input'&& nodeType!='textarea') e.preventDefault(); }

    2.往iscroll容器内添加内容时,容器闪动的bug

    源代码的

    has3d = 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix()

    改成

    has3d = false

    在配置iscroll时,useTransition设置成false

    3.过长的滚动内容,导致卡顿和app直接闪退

    1. 不要使用checkDOMChanges。虽然checkDOMChanges很方便,定时检测容器长度是否变化来refresh,但这也意味着你要消耗一个Interval的内存空间

    2. 隐藏iscroll滚动条,配置时设置hScrollbar和vScrollbar为false。

    3. 不得已的情况下,去掉各种效果,momentum、useTransform、useTransition都设置为false

    4.左右滚动时,不能正确响应正文上下拉动

    iscroll的闪动问题也与渲染有关系,可以参考

    运用webkit绘制渲染页面原理解决iscroll4闪动的问题

    iscroll4升级到5要注意的问题

    iscroll或者滚动类框架滚动时不点击的方法

    可以使用以下的解决方案(利用data-setapi)

    <a ontouchmove="this.s=1" ontouchend="this.s || window.open(this.dataset.href),this.s=0" target="_blank" data-href="http://www.hao123.com/topic/pig">黄浦江死猪之谜</a>

    也可以用这种方法

    $(document).delegate('[data-target]', 'touchmove', function () {

    移动端字体问题

    知乎专栏 - [无线手册-4] dp、sp、px傻傻分不清楚[完整]

    Resolution Independent Mobile UI

    Pixel density, retina display and font-size in CSS

    Device pixel density tests

    跨域问题

    手机浏览器也是浏览器,在ajax调用外部api的时候也存在跨域问题。当然利用 PhoneGap 打包后,由于协议不一样就不存在跨域问题了。

    但页面通常是需要跟后端进行调试的。一般会报类似

    XMLHttpRequest cannot load XXX

    以及

    XMLHttpRequest cannot load http://. Request header field Content-Type is not allowed by Access-Control-Allow-Headers."

    这时候可以让后端加上两个http头

    Access-Control-Allow-Origin "*"

    第一个头可以避免跨域问题,第二个头可以方便ajax请求设置content-type等配置项

    这个会存在一些安全问题,可以参考这个问题的讨论 http://www.zhihu.com/question/22992229

    PhoneGap 部分

    http://snoopyxdy.blog.163.com/blog/static/60117440201432491123551 这里有一大堆snoopy总结的phonggap开发坑

    Should not happen: no rect-based-test nodes found

    在 Android 项目中的 assets 中的 HTML 页面中加入以下代码,便可解决问题

    window,html,body{

    参考:

    http://stackoverflow.com/questions/12090899/android-webview-jellybean-should-not-happen-no-rect-based-test-nodes-found

    拿联系人的时候报 ContactFindOptions is not defined

    出现这个问题可能是因为 Navigator 取 contacts 时绑定的 window.onload

    注意使用 PhoneGap 的 API 时,一定要在 devicereay 事件的处理函数中使用 API

    document.addEventListener("deviceready", onDeviceReady, false);

    本文关键词:移动端布局移动端兼容,移动端布局rem,移动端布局自适应方案,移动端的布局,移动端布局的相关单位及特点。这就是关于《移动端布局适配心得,关于移动端适配》的所有内容,希望对您能有所帮助!更多的知识请继续关注《犇涌向乾》百科知识网站:http://www.029ztxx.com!

    版权声明: 本站仅提供信息存储空间服务,旨在传递更多信息,不拥有所有权,不承担相关法律责任,不代表本网赞同其观点和对其真实性负责。如因作品内容、版权和其它问题需要同本网联系的,请发送邮件至 举报,一经查实,本站将立刻删除。

    猜你喜欢