Junwen's home
  • ES6

    • ES6 Decorator
    • ES6核心特性
    • Promise&Generator
  • js原理

    • 简单实现bind、apply和call
    • 如何遍历一个dom tree
    • 实现函数currying
    • 实现一个event
    • 详解js的继承
    • 详解requestAnimationFrame
    • Canvas api详解
    • DOM事件
    • EventLoop详解
    • JavaScript的内存管理
    • JavaScript的运行机制
    • Math对象
    • new操作符都做了什么
    • create基本实现原理
    • Set、Map、WeakSet和WeakMap
    • web worker原理
    • WebGL教程(MDN)
  • jsInfoSeries

    • 简介
    • JavaScript基础知识
    • 基础知识2
    • 基础知识3
    • 基础知识4
  • 技巧

    • 5个js解构有趣用途
    • 如何使用set提高代码性能
    • cordova构建项目时的问题
    • js中轻松遍历对象属性的几种方式
  • 怎么写出更好的css
  • BFC详解
  • box-shadow详解
  • CSS小技巧
  • Grid布局详解
HTML
  • IP十问
  • http笔试
  • http协议
  • 浏览器原理
  • 浏览器缓存其实就这么一回事儿
  • 浏览器兼容性问题
  • 移动端开发兼容性适配
  • 前端性能优化
  • 前端如何进行seo优化
  • webpack

    • webpack HMR
    • webpack优化基本方法
  • leetcode题解

    • 两数之和
    • 判断整数是否为回文串
    • 无重复字符的最长子串
  • Js链表
  • JavaScript排序
  • React

    • 虚拟DOM原理理解
    • React Hook
    • 组件复用指南
  • Vue

    • Vue举一反三
面试题
读书笔记
GitHub (opens new window)

Syun0216

多读书多种树
  • ES6

    • ES6 Decorator
    • ES6核心特性
    • Promise&Generator
  • js原理

    • 简单实现bind、apply和call
    • 如何遍历一个dom tree
    • 实现函数currying
    • 实现一个event
    • 详解js的继承
    • 详解requestAnimationFrame
    • Canvas api详解
    • DOM事件
    • EventLoop详解
    • JavaScript的内存管理
    • JavaScript的运行机制
    • Math对象
    • new操作符都做了什么
    • create基本实现原理
    • Set、Map、WeakSet和WeakMap
    • web worker原理
    • WebGL教程(MDN)
  • jsInfoSeries

    • 简介
    • JavaScript基础知识
    • 基础知识2
    • 基础知识3
    • 基础知识4
  • 技巧

    • 5个js解构有趣用途
    • 如何使用set提高代码性能
    • cordova构建项目时的问题
    • js中轻松遍历对象属性的几种方式
  • 怎么写出更好的css
  • BFC详解
  • box-shadow详解
  • CSS小技巧
  • Grid布局详解
HTML
  • IP十问
  • http笔试
  • http协议
  • 浏览器原理
  • 浏览器缓存其实就这么一回事儿
  • 浏览器兼容性问题
  • 移动端开发兼容性适配
  • 前端性能优化
  • 前端如何进行seo优化
  • webpack

    • webpack HMR
    • webpack优化基本方法
  • leetcode题解

    • 两数之和
    • 判断整数是否为回文串
    • 无重复字符的最长子串
  • Js链表
  • JavaScript排序
  • React

    • 虚拟DOM原理理解
    • React Hook
    • 组件复用指南
  • Vue

    • Vue举一反三
面试题
读书笔记
GitHub (opens new window)
  • 浏览器原理
  • 浏览器缓存其实就这么一回事儿
  • 浏览器兼容性问题
  • 移动端开发兼容性适配
    • 移动端开发的屏幕、图像、字体与布局的兼容适配
    • 移动端屏幕适配方案
    • vw(更好的方案)
    • 图片适配及优化
    • 字体适配方案
  • 前端性能优化
  • 前端如何进行seo优化
  • lerna学习笔记
  • 用nodejs搭建api网关
  • etcd学习
  • webpack

    • webpack HMR
    • webpack优化基本方法
  • CI/CD

    • 如何从0到1一步步成体系地搭建CI
    • 如何建立前端标准化研发流程
    • 如何打造全链路项目生命周期的统一交付平台
  • project
junwen
2020-05-18

移动端开发兼容性适配

# 移动端开发的屏幕、图像、字体与布局的兼容适配

参考自chokcoco (opens new window)的移动端开发的屏幕、图像、字体与布局的兼容适配 (opens new window),对部分内容进行摘抄

# 响应式设计(Responsive Web Design)

Content is like water,响应式界面能够适应不同的设备

# 响应式界面的基本规则

  • 可伸缩的内容区块
  • 可自由排布的内容区块
  • 适应页面尺寸的边距: 根据页面尺寸进行放大缩小
  • 能够适应比例变化的图片
  • 能够自动隐藏/显示部分内容
  • 能够自动折叠的导航菜单
  • 放弃使用像素作为尺寸单位:能够在分辨率相差很大的设备上,看起来也能保持一致。

归结为

  • 媒体查询,边界断点的规则设定(media queries and break point)
  • 内容的可伸缩性效果(Flexibel visuals)
  • 流失网格布局(Fluid grids)
  • 主要内容呈现及图片的高质量(Main content and high quality)

# 响应式(RWD)和自适应(AWD)

RWD:一切能用来为各种分辨率和设备性能优化视觉体验的技术(多端一套代码)。AWD:除了用媒体查询技术,,还要用js和HTML来适应影动设备的能力。AWD有可能会针对移动端用户减去内容,减去功能(多端多套代码)。

# 渐进增强(progressive enhancement)和优雅降级(graceful degradation)

  • 渐进增强:保证基本功能,针对高级浏览器进行效果交互改进(朝前看)
  • 优雅降级:构建完整功能,针对低版本浏览器进行兼容 (往回看)

# 移动端屏幕适配方案

# 设备逻辑像素

设备独立像素 = CSS 像素 = 逻辑像素

chrome 上的iphone6、7、8  375*667
1

# 物理像素

物理像素,既设备像素,又称分辨率。显示屏由一个个物理像素点组成,1334*750表示垂直和水平上具有的像素点。单位为pt

# DPR(Device Pixel Ratio) 设备像素比

公式: DPR = 物理像素 /设备像素

750 / 375 = 2 或者是 1334 / 667 = 2

我们需要解决的问题:

  1. 适配不同的屏幕大小,也就是适配不同屏幕下的css像素
  2. 适配不同的像素密度,适配不同屏幕下的dpr不一致导致的问题

# 适配不同的屏幕大小

  • css媒体查询
  • 按比例还原设计稿

但是如果我们使用百分比作为全局通用的基准单位,在css中每个单位的参照值不统一

百分比总要相对于另外一个量,比如长度。每个允许使用百分比值的属性,同时也要定义百分比值参照的那个量。这个量可以是相同元素的另一个属性的值,也可以是祖先元素的某个属性的值,甚至是格式化上下文的一个度量(比如包含块的宽度)。

具体来说:

  • 宽度width和间距margin、padding,支持百分比,但是默认的相对参考值是包含块的宽度
  • 高度height百分比的大小是相对于其父级元素高的大小
  • 边框border不支持百分比
  • 边框圆角半径(border-radius)支持百分比值,但水平方向相对参考值是盒子的宽度,垂直方向相对参考值是盒子的高度;
  • 文本大小(font-size)支持百分比值,但相对参考值是父元素的font-size的值;
  • 盒阴影(box-shadow)和文本阴影(text-shadow)不支持百分比值;

# rem适配方案

rem(font size of the root element),在 CSS Values and Units Module Level 3中的定义就是, 根据网页的根元素来设置字体大小,和 em(font size of the element)的区别是,em 是根据其父元素的字体大小来设置,而 rem 是根据网页的跟元素(html)来设置字体大小。

# flexible

淘宝推行的基于rem 的库:lib-flexible,它可以根据document.documentElement.clientWidth动态修改html的font-size,页面其他元素使用rem作为长度单位进行布局,从而实现等比例缩放

# hotcss

它是一个移动端布局开发解决方案。使用 hotcss 可以让移动端布局开发更容易。

# rem方案总结

存在的问题:

  • 动态修改viewport的风险,viewport改变页面缩放后,会使innerWidth/innerHeight也会随之变化。
  • 需要引入一定js代码
  • rem 进行页面的宽度适配多少有一种 hack 的感觉
  • 安卓4.4以下版本不支持viewport缩放

# vw(更好的方案)

使用vw和vh不需要js辅助,根据 CSS Values and Units Module Level 4,vw等于初始包含块html元素宽度的1%,适配容器,文本,大于1px边框、圆角、阴影,内距和外距

  • 1vw = window.innerWidth*0.01
  • 1vh = window.innerHeight*0.01

参考地址 (opens new window)

# vw的自动转换函数

// 假设设计稿的宽度是 375px

@function px2vw($px) {
	@return $px / 375 * 100vw;
}
1
2
3
4
5

或者使用插件postcss-px-to-vieport (opens new window)

# vw polyfill

降级处理:

  • CSS Houdini:通过CSS Houdini针对vw做处理,调用CSS Typed OM Level1 提供的 CSSUnitValue API。
  • CSS Polyfill:通过相应的Polyfill做相应的处理,目前针对于 vw 单位的 Polyfill 主要有:vminpoly、Viewport Units Buggyfill、vunits.js和 Modernizr

存在的问题:

  • 1px在高清屏显示问题
  • 无法限制最大最小宽度

# 1px线

在不同dpr下,物理像素宽不等于css像素宽

  • 在 dpr = 1 时,此时 1 物理像素等于 1 CSS 像素宽度
  • 在 dpr = 2 时,此时 1 物理像素等于 0.5 CSS 宽度像素,可以认为 border-width: 1px 这里的 1px 其实是 1 CSS像素宽度,等于 2 像素物理宽度,设计师其实想要的是 border-width: 0.5px;
  • 在 dpr = 3 时,此时 1 物理像素等于 0.33 CSS 宽度像素,设计师其实想要的是 border: 0.333px

解决方法:

  • 渐变实现
  • 使用缩放实现
  • 使用图片实现(base64)
  • 使用svg实现(嵌入background url)

Retina 屏幕下 1px 线的实现 (opens new window)

# 图片适配及优化

通常做法

  1. 消除多余的图像资源
  2. 尽可能利用 CSS3\SVG 矢量图像替代某些光栅图像
  3. 谨慎使用字体图标,使用网页字体取代在图像中进行文本编码
  4. 选择正确的图片格式
  5. 为不同 DPR 屏幕提供最适合的图片尺寸

# 无脑多倍图

不管设备dpr统一使用最高的3倍图,这样在dpr=1,dpr=2的设备上也能非常好的展示图片,但是会浪费大量带宽

# srcset 配合 1x 2x 像素密度描述符

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

# srcset 属性配合 sizes 属性 w 宽度描述符

<img 
        sizes = “(min-width: 600px) 600px, 300px" 
        src = "photo.png" 
        srcset = “photo@1x.png 300w,
                       photo@2x.png 600w,
                       photo@3x.png 1200w,
>
1
2
3
4
5
6
7

sizes = “(min-width: 600px) 600px, 300px"的意思是,如果屏幕当前的 CSS 像素宽度大于或者等于 600px,则图片的 CSS 宽度为 600px,反之,则图片的 CSS 宽度为 300px。

srcset = “photo@1x.png 300w, photo@2x.png 600w, photo@3x.png 1200w

# 当前屏幕dpr=2,css宽度为375px,当屏幕dpr=3,css宽度为414px

当前屏幕宽度为375px||414px,则图片css宽度为300px。分别用上述 3 个宽度描述符的数值除以 300。

  1. 300/300 = 1
  2. 600/300 = 2
  3. 1200/300 = 4

上面计算得到的 1、 2、 4 即是算出的有效的像素密度,所以dpr=2会选择600w,而dpr=3则会选择1200w

# 当前屏幕dpr = 1,css宽度为1920px

则我们需要选择600px的图片,因为min-width为600,显然1920大于600,再次计算得:

  1. 300/600 = .5
  2. 600/600 = 1
  3. 1200/300 = 4

所以dpr=1,会选择600w对应的图片

详细demo (opens new window) 响应式图片srcset全新释义sizes属性w描述符 (opens new window) Google Web Fundamentals -- Web Responsive Images (opens new window)

# 字体适配方案

浏览器的最小字体限制:

  • pc: 12px
  • 手机: 8px

很多早期的文章规范都建议不要使用奇数级单位来定义字体大小(如13px、15px),容易在一些低端设备上造成字体模糊

# 字体的选择展示

我们应该从性能和展示效果去考虑;一个完整的字体资源太大,我们应该尽量使用用户设备上的字体,而不是额外去下载字体资源

# 兼顾各个操作系统

以css-trick网站最新的font-family为例,看看他们是如何在字体选择上做到适配各个操作系统的

{
  font-family: 
    system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,
    Helvetica,Arial,
    sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol;
}
1
2
3
4
5
6

# font-family 关键字

对于 CSS 中的 font-family 而言,它有两类取值。

  1. 一类是类似这样的具体的字体族名定义:font-family: Arial 这里定义了一个具体的字体样式,字体族名为 Arial;
  2. 一类是通用字体族名,它是一种备选机制,用于在指定的字体不可用时给出较好的字体,类似这样:font-family: sans-serif 。

关于通用字体族名,在 CSS Fonts Module Level 3 -- Basic Font Properties (opens new window) 中,定义了 5 个,也就是我们熟知的几个通用字体族名:

  1. serif 衬线字体族
  2. sans-serif 非衬线字体族
  3. monospace 等宽字体,即字体中每个字宽度相同
  4. cursive 草书字体
  5. fantasy 主要是那些具有特殊艺术效果的字体

# 新增通用字体族关键字

而在 CSS Fonts Module Level 4 -- Generic font families (opens new window) 中,新增了几个关键字:

  • system-ui 系统默认字体
  • emoji 用于兼容 emoji 表情符号字符
  • math 适用于数学表达式
  • fangsong 此字体系列用于中文的(仿宋)字体。

# system-ui

font-family:system-ui目的就是在不同的操作系统的web页面下,自动选择本操作系统下的默认字体

# San Francisco Fonts

San Francisco Fonts 又叫旧金山字体,是一款西文字体。随着 iOS 9 更新面世,在 WatchOS 中随 Apple Watch 一起悄然发售,并且还将在 Apple TV 上的新 tvOS 中使用。
San Francisco Fonts 在 iOS 系统上用于替代升级另外一款西文字体 Helvetica Neue。Apple 做了一些重要的改变,使其成为平台上更好的, 甚至是完美的西文字体。

# Segoe UI

Segoe UI 是 Windows 从 Vista 开始的默认西文字体族,只有西文,不支持汉字,属于无衬线体。

# Roboto

Roboto 是为 Android 操作系统设计的一个无衬线字体家族。Google 描述该字体为“现代的、但平易近人”和“有感情”的。

# 总结

{
  font-family: 
    system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,
    Helvetica,Arial,
    sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol;
}
1
2
3
4
5
6
  • system-ui,使用各个支持平台上的默认系统字体
  • -apple-system, 在一些稍低版本 Mac OS X 和 iOS 上,它针对旧版上的 Neue Helvetica 和 Lucida Grande 字体,升级使用更为合适的 San Francisco Fonts
  • BlinkMacSystemFont,针对一些 Mac OS X 上的 Chrome 浏览器,使用系统默认字体
  • segoe ui,在 Windows 及 Windows Phone 上选取系统默认字体
  • Roboto,面向 Android 和一些新版的的 Chrome OS
  • Helvetica,Arial,在针对不同操作系统不同平台设定采用默认系统字体后,针对一些低版本浏览器的降级方案
  • sans-serif,兜底方案,保证字体风格统一,至少也得是无衬线字体

# 前端布局的兼容适配

历程: 表格布局 --> 定位布局 --> 浮动布局 --> flexbox布局 --> gridbox布局

flexbox最便捷的居中方式:

.container {
    display: flex;
}

.item {
    margin: auto;
}
1
2
3
4
5
6
7

# CSS Grid Layout

flexbox 是一维布局,他只能在一条直线上放置你的内容区块;而grid是一个二维布局。它除了可以灵活的控制水平方向之外,还能轻易的控制垂直方向的布局模式。对于上图那样的九宫格布局,它就可以轻而易举的完成。

截取自新时代CSS布局 (opens new window)

在Github上编辑此页 (opens new window)
#移动端
上次更新: 3/22/2021, 3:47:15 AM
浏览器兼容性问题
前端性能优化

← 浏览器兼容性问题 前端性能优化→

最近更新
01
如何打造全链路项目生命周期的统一交付平台
04-10
02
如何建立前端标准化研发流程
04-10
03
如何从0到1一步步成体系地搭建CI
04-10
更多文章>
Theme by Vdoing | Copyright © 2019-2021 Syun
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式