手机版

百科生活 投稿

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

百科 2025-10-20 06:25:12 投稿 阅读:354次

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

  • 内容导航:
  • 1、移动端布局适配心得:关于移动端适配,你必须要知道的
  • 2、移动端布局适配心得,移动端上遇到的各种坑与相对解决方案

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();export function pxConvertTodp(px) { return px / dpr;}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

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

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

上面是 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]'); 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 alt="移动端布局适配心得,关于移动端适配" src="https://p3.toutiaoimg.com/pgc-image/d254a4e4587d48fd944623fd0f41b12f~tplv-tt-large.jpeg" />

如果视觉视口为 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后才能使用这两个函数:

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 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图片:

.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 href="http://www.xxx.com/App_icon_114.png" />

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

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

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

    常见的 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、页面引用

    2、CSS文件里

    #header {

    移动 Web 开发经验技巧

    点击与click事件

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

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

    ontouchstart -> //锁定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 类似>

  • 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

    解决方法:

    因为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成功