移动端开发兼容性适配
# 移动端开发的屏幕、图像、字体与布局的兼容适配
参考自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
# 物理像素
物理像素,既设备像素,又称分辨率。显示屏由一个个物理像素点组成,1334*750表示垂直和水平上具有的像素点。单位为pt
# DPR(Device Pixel Ratio) 设备像素比
公式: DPR = 物理像素 /设备像素
750 / 375 = 2 或者是 1334 / 667 = 2
我们需要解决的问题:
- 适配不同的屏幕大小,也就是适配不同屏幕下的css像素
- 适配不同的像素密度,适配不同屏幕下的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
# vw的自动转换函数
// 假设设计稿的宽度是 375px
@function px2vw($px) {
@return $px / 375 * 100vw;
}
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)
# 图片适配及优化
通常做法
- 消除多余的图像资源
- 尽可能利用 CSS3\SVG 矢量图像替代某些光栅图像
- 谨慎使用字体图标,使用网页字体取代在图像中进行文本编码
- 选择正确的图片格式
- 为不同 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>
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,
>
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。
- 300/300 = 1
- 600/300 = 2
- 1200/300 = 4
上面计算得到的 1、 2、 4 即是算出的有效的像素密度,所以dpr=2会选择600w,而dpr=3则会选择1200w
# 当前屏幕dpr = 1,css宽度为1920px
则我们需要选择600px的图片,因为min-width为600,显然1920大于600,再次计算得:
- 300/600 = .5
- 600/600 = 1
- 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;
}
2
3
4
5
6
# font-family 关键字
对于 CSS 中的 font-family 而言,它有两类取值。
- 一类是类似这样的具体的字体族名定义:font-family: Arial 这里定义了一个具体的字体样式,字体族名为 Arial;
- 一类是通用字体族名,它是一种备选机制,用于在指定的字体不可用时给出较好的字体,类似这样:font-family: sans-serif 。
关于通用字体族名,在 CSS Fonts Module Level 3 -- Basic Font Properties (opens new window) 中,定义了 5 个,也就是我们熟知的几个通用字体族名:
- serif 衬线字体族
- sans-serif 非衬线字体族
- monospace 等宽字体,即字体中每个字宽度相同
- cursive 草书字体
- 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;
}
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;
}
2
3
4
5
6
7
# CSS Grid Layout
flexbox 是一维布局,他只能在一条直线上放置你的内容区块;而grid是一个二维布局。它除了可以灵活的控制水平方向之外,还能轻易的控制垂直方向的布局模式。对于上图那样的九宫格布局,它就可以轻而易举的完成。