移动端适配,是咱们在开发中常常会遇到的,这里面可能会遇到很是多的问题:css
1px
问题UI
图完美适配方案iPhoneX
适配方案上面这些问题可能咱们在开发中已经知道如何解决,可是问题产生的原理,以及解决方案的原理可能会模糊不清。在解决这些问题的过程当中,咱们每每会遇到很是多的概念:像素、分辨率、PPI
、DPI
、DP
、DIP
、DPR
、视口等等,你真的能分清这些概念的意义吗?html
本文将从移动端适配的基础概念出发,探究移动端适配各类问题的解决方案和实现原理。前端
通常用英寸描述屏幕的物理大小,如电脑显示器的17
、22
,手机显示器的4.8
、5.7
等使用的单位都是英寸。react
须要注意,上面的尺寸都是屏幕对角线的长度:git
英寸(inch
,缩写为in
)在荷兰语中的本意是大拇指,一英寸就是指甲底部普通人拇指的宽度。github
英寸和厘米的换算:1英寸 = 2.54 厘米
web
像素即一个小方块,它具备特定的位置和颜色。chrome
图片、电子屏幕(手机、电脑)就是由无数个具备特定颜色和特定位置的小方块拼接而成。react-native
像素能够做为图片或电子屏幕的最小组成单位。浏览器
下面咱们使用sketch
打开一张图片:
将这些图片放大便可看到这些像素点:
一般咱们所说的分辨率有两种,屏幕分辨率和图像分辨率。
屏幕分辨率指一个屏幕具体由多少个像素点组成。
下面是apple
的官网上对手机分辨率的描述:
iPhone XS Max
和 iPhone SE
的分辨率分别为2688 x 1242
和1136 x 640
。这表示手机分别在垂直和水平上所具备的像素点数。
固然分辨率高不表明屏幕就清晰,屏幕的清晰程度还与尺寸有关。
咱们一般说的图片分辨率
实际上是指图片含有的像素数
,好比一张图片的分辨率为800 x 400
。这表示图片分别在垂直和水平上所具备的像素点数为800
和400
。
同一尺寸的图片,分辨率越高,图片越清晰。
PPI(Pixel Per Inch)
:每英寸包括的像素数。
PPI
能够用于描述屏幕的清晰度以及一张图片的质量。
使用PPI
描述图片时,PPI
越高,图片质量越高,使用PPI
描述屏幕时,PPI
越高,屏幕越清晰。
在上面描述手机分辨率的图片中,咱们能够看到:iPhone XS Max
和 iPhone SE
的PPI
分别为458
和326
,这足以证实前者的屏幕更清晰。
因为手机尺寸为手机对角线的长度,咱们一般使用以下的方法计算PPI
:
iPhone 6
的PPI
为 ,那它每英寸约含有
326
个物理像素点。
DPI(Dot Per Inch)
:即每英寸包括的点数。
这里的点是一个抽象的单位,它能够是屏幕像素点、图片像素点也能够是打印机的墨点。
平时你可能会看到使用DPI
来描述图片和屏幕,这时的DPI
应该和PPI
是等价的,DPI
最经常使用的是用于描述打印机,表示打印机每英寸能够打印的点数。
一张图片在屏幕上显示时,它的像素点数是规则排列的,每一个像素点都有特定的位置和颜色。
当使用打印机进行打印时,打印机可能不会规则的将这些点打印出来,而是使用一个个打印点来呈现这张图像,这些打印点之间会有必定的空隙,这就是DPI
所描述的:打印点的密度。
在上面的图像中咱们能够清晰的看到,打印机是如何使用墨点来打印一张图像。
因此,打印机的DPI
越高,打印图像的精细程度就越高,同时这也会消耗更多的墨点和时间。
实际上,上面咱们描述的像素都是物理像素
,即设备上真实的物理单元。
下面咱们来看看设备独立像素
到底是如何产生的:
智能手机发展很是之快,在几年以前,咱们还用着分辨率很是低的手机,好比下面左侧的白色手机,它的分辨率是320x480
,咱们能够在上面浏览正常的文字、图片等等。
可是,随着科技的发展,低分辨率的手机已经不能知足咱们的需求了。很快,更高分辨率的屏幕诞生了,好比下面的黑色手机,它的分辨率是640x940
,正好是白色手机的两倍。
理论上来说,在白色手机上相同大小的图片和文字,在黑色手机上会被缩放一倍,由于它的分辨率提升了一倍。这样,岂不是后面出现更高分辨率的手机,页面元素会变得愈来愈小吗?
然而,事实并非这样的,咱们如今使用的智能手机,无论分辨率多高,他们所展现的界面比例都是基本相似的。乔布斯在iPhone4
的发布会上首次提出了Retina Display
(视网膜屏幕)的概念,它正是解决了上面的问题,这也使它成为一款跨时代的手机。
在iPhone4
使用的视网膜屏幕中,把2x2
个像素当1
个像素使用,这样让屏幕看起来更精致,可是元素的大小却不会改变。
若是黑色手机使用了视网膜屏幕的技术,那么显示结果应该是下面的状况,好比列表的宽度为300
个像素,那么在一条水平线上,白色手机会用300
个物理像素去渲染它,而黑色手机实际上会用600
个物理像素去渲染它。
咱们必须用一种单位来同时告诉不一样分辨率的手机,它们在界面上显示元素的大小是多少,这个单位就是设备独立像素(Device Independent Pixels
)简称DIP
或DP
。上面咱们说,列表的宽度为300
个像素,实际上咱们能够说:列表的宽度为300
个设备独立像素。
打开chrome
的开发者工具,咱们能够模拟各个手机型号的显示状况,每种型号上面会显示一个尺寸,好比iPhone X
显示的尺寸是375x812
,实际iPhone X
的分辨率会比这高不少,这里显示的就是设备独立像素。
设备像素比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){ }
复制代码
在React Native
中,咱们也可使用PixelRatio.get()
来获取DPR
。
固然,上面的规则也有例外,iPhone 六、七、8 Plus
的实际物理像素是1080 x 1920
,在开发者工具中咱们能够看到:它的设备独立像素是414 x 736
,设备像素比为3
,设备独立像素和设备像素比的乘积并不等于1080 x 1920
,而是等于1242 x 2208
。
实际上,手机会自动把1242 x 2208
个像素点塞进1080 * 1920
个物理像素点来渲染,咱们不用关心这个过程,而1242 x 2208
被称为屏幕的设计像素
。咱们开发过程当中也是以这个设计像素
为准。
实际上,从苹果提出视网膜屏幕开始,才出现设备像素比这个概念,由于在这以前,移动设备都是直接使用物理像素来进行展现。
紧接着,Android
一样使用了其余的技术方案来实现DPR
大于1
的屏幕,不过原理是相似的。因为Android
屏幕尺寸很是多、分辨率高低跨度很是大,不像苹果只有它本身的几款固定设备、尺寸。因此,为了保证各类设备的显示效果,Android
按照设备的像素密度将设备分红了几个区间:
固然,全部的Android
设备不必定严格按照上面的分辨率,每一个类型可能对应几种不一样分辨率,因此,每一个Android
手机都能根据给定的区间范围,肯定本身的DPR
,从而拥有相似的显示。固然,仅仅是相似,因为各个设备的尺寸、分辨率上的差别,设备独立像素也不会彻底相等,因此各类Android
设备仍然不能作到在展现上彻底相等。
在iOS
、Android
和React Native
开发中样式单位其实都使用的是设备独立像素。
iOS
的尺寸单位为pt
,Android
的尺寸单位为dp
,React Native
中没有指定明确的单位,它们其实都是设备独立像素dp
。
在使用React Native
开发App
时,UI
给咱们的原型图通常是基于iphone6
的像素给定的。
为了适配全部机型,咱们在写样式时须要把物理像素转换为设备独立像素:例如:若是给定一个元素的高度为200px
(这里的px
指物理像素,非CSS
像素),iphone6
的设备像素比为2
,咱们给定的height
应为200px/2=100dp
。
固然,最好的是,你能够和设计沟通好,全部的UI
图都按照设备独立像素来出。
咱们还能够在代码(React Native
)中进行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);
}
复制代码
在写CSS
时,咱们用到最多的单位是px
,即CSS像素
,当页面缩放比例为100%
时,一个CSS像素
等于一个设备独立像素。
可是CSS像素
是很容易被改变的,当用户对浏览器进行了放大,CSS像素
会被放大,这时一个CSS像素
会跨越更多的物理像素。
页面的缩放系数 = CSS像素 / 设备独立像素
。
这里多说两句Retina
屏幕,由于我在不少文章中看到对Retina
屏幕的误解。
Retina
屏幕只是苹果提出的一个营销术语:
在普通的使用距离下,人的肉眼没法分辨单个的像素点。
为何强调普通的使用距离下
呢?咱们来看一下它的计算公式:
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
, 菜单栏等——即指你正在浏览的文档的那一部分。
通常咱们所说的视口共包括三种:布局视口、视觉视口和理想视口,它们在屏幕适配中起着很是重要的做用。
布局视口(layout viewport
):当咱们以百分比来指定一个元素的大小时,它的计算值是由这个元素的包含块计算而来的。当这个元素是最顶级的元素时,它就是基于布局视口来计算的。
因此,布局视口是网页布局的基准窗口,在PC
浏览器上,布局视口就等于当前浏览器的窗口大小(不包括borders
、margins
、滚动条)。
在移动端,布局视口被赋予一个默认值,大部分为980px
,这保证PC
的网页能够在手机浏览器上呈现,可是很是小,用户能够手动对网页进行放大。
咱们能够经过调用document.documentElement.clientWidth / clientHeight
来获取布局视口大小。
视觉视口(visual viewport
):用户经过屏幕真实看到的区域。
视觉视口默认等于当前浏览器的窗口大小(包括滚动条宽度)。
当用户对浏览器进行缩放时,不会改变布局视口的大小,因此页面布局是不变的,可是缩放会改变视觉视口的大小。
例如:用户将浏览器窗口放大了200%
,这时浏览器窗口中的CSS像素
会随着视觉视口的放大而放大,这时一个CSS
像素会跨越更多的物理像素。
因此,布局视口会限制你的CSS
布局而视觉视口决定用户具体能看到什么。
咱们能够经过调用window.innerWidth / innerHeight
来获取视觉视口大小。
布局视口在移动端展现的效果并非一个理想的效果,因此理想视口(ideal viewport
)就诞生了:网站页面在移动端展现的理想大小。
如上图,咱们在描述设备独立像素时曾使用过这张图,在浏览器调试移动端时页面上给定的像素大小就是理想视口大小,它的单位正是设备独立像素。
上面在介绍CSS像素时
曾经提到页面的缩放系数 = CSS像素 / 设备独立像素
,实际上说页面的缩放系数 = 理想视口宽度 / 视觉视口宽度
更为准确。
因此,当页面缩放比例为100%
时,CSS像素 = 设备独立像素
,理想视口 = 视觉视口
。
咱们能够经过调用screen.width / height
来获取理想视口大小。
<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。 |
为了在移动端让页面得到更好的显示效果,咱们必须让布局视口、视觉视口都尽量等于理想视口。
device-width
就等于理想视口的宽度,因此设置width=device-width
就至关于让布局视口等于理想视口。
因为initial-scale = 理想视口宽度 / 视觉视口宽度
,因此咱们设置initial-scale=1;
就至关于让视觉视口等于理想视口。
这时,1个CSS
像素就等于1个设备独立像素,并且咱们也是基于理想视口来进行布局的,因此呈现出来的页面布局在各类设备上都能大体类似。
上面提到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
。
浏览器为咱们提供的获取窗口大小的API
有不少,下面咱们再来对比一下:
window.innerHeight
:获取浏览器视觉视口高度(包括垂直滚动条)。window.outerHeight
:获取浏览器窗口外部的高度。表示整个浏览器窗口的高度,包括侧边栏、窗口镶边和调正窗口大小的边框。window.screen.Height
:获取获屏幕取理想视口高度,这个数值是固定的,设备的分辨率/设备像素比
window.screen.availHeight
:浏览器窗口可用的高度。document.documentElement.clientHeight
:获取浏览器布局视口高度,包括内边距,但不包括垂直滚动条、边框和外边距。document.documentElement.offsetHeight
:包括内边距、滚动条、边框和外边距。document.documentElement.scrollHeight
:在不使用滚动条的状况下适合视口中的全部内容所需的最小宽度。测量方式与clientHeight
相同:它包含元素的内边距,但不包括边框,外边距或垂直滚动条。为了适配各类屏幕,咱们写代码时通常使用设备独立像素来对页面进行布局。
而在设备像素比大于1
的屏幕上,咱们写的1px
其实是被多个物理像素渲染,这就会出现1px
在有些屏幕上看起来很粗的现象。
基于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;
}
}
复制代码
和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;
}
}
复制代码
上面两种都须要单独准备图片,并且圆角不是很好处理,可是能够应对大部分场景。
基于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
便可。
上面咱们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; }
复制代码
上面的方案是大漠在他的文章中推荐使用的,基本能够知足全部场景,并且不须要外部引入,这是我我的比较喜欢的一种方案。
经过设置缩放,让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
来帮助咱们进行适配。
尽管咱们可使用设备独立像素来保证各个设备在不一样手机上显示的效果相似,但这并不能保证它们显示彻底一致,咱们须要一种方案来让设计稿获得更完美的适配。
flexible
方案是阿里早期开源的一个移动端适配解决方案,引用flexible
后,咱们在页面上统一使用rem
来布局。
它的核心代码很是简单:
// set 1rem = viewWidth / 10
function 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 resize
window.addEventListener('resize', setRemUnit)window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit()
}
})
复制代码
因为viewport
单位获得众多浏览器的兼容,上面这种方案如今已经被官方弃用:
lib-flexible这个过渡方案已经能够放弃使用,无论是如今的版本仍是之前的版本,都存有必定的问题。建议你们开始使用viewport来替代此方案。
下面咱们来看看如今最流行的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
发布后,许多厂商相继推出了具备边缘屏幕的手机。
这些手机和普通手机在外观上无外乎作了三个改动:圆角(corners
)、刘海(sensor housing
)和小黑条(Home Indicator
)。为了适配这些手机,安全区域这个概念变诞生了:安全区域就是一个不受上面三个效果的可视窗口范围。
为了保证页面的显示效果,咱们必须把页面限制在安全范围内,可是不影响总体效果。
viewport-fit
是专门为了适配iPhoneX
而诞生的一个属性,它用于限制网页如何在安全区域内进行展现。
contain
: 可视窗口彻底包含网页内容
cover
:网页内容彻底覆盖可视窗口
默认状况下或者设置为auto
和contain
效果相同。
咱们须要将顶部和底部合理的摆放在安全区域内,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);
}
复制代码
不少视口咱们要对横屏和竖屏显示不一样的布局,因此咱们须要检测在不一样的场景下给定不一样的样式:
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('横屏');
}
});
复制代码
@media screen and (orientation: portrait) {
/*竖屏...*/
}
@media screen and (orientation: landscape) {
/*横屏...*/
}
复制代码
咱们平时使用的图片大多数都属于位图(png、jpg...
),位图由一个个像素点构成的,每一个像素都具备特定的位置和颜色值:
理论上,位图的每一个像素对应在屏幕上使用一个物理像素来渲染,才能达到最佳的显示效果。
而在dpr > 1
的屏幕上,位图的一个像素可能由多个物理像素来渲染,然而这些物理像素点并不能被准确的分配上对应位图像素的颜色,只能取近似值,因此相同的图片在dpr > 1
的屏幕上就会模糊:
为了保证图片质量,咱们应该尽量让一个屏幕像素来渲染一个图片像素,因此,针对不一样DPR
的屏幕,咱们须要展现不一样分辨率的图片。
如:在dpr=2
的屏幕上展现两倍图(@2x)
,在dpr=3
的屏幕上展现三倍图(@3x)
。
使用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);
}
}
复制代码
只适用于背景图
使用image-set
:
.avatar {
background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x );
}
复制代码
只适用于背景图
使用img
标签的srcset
属性,浏览器会自动根据像素密度匹配最佳显示图片:
<img src="conardLi_1x.png" srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
复制代码
使用window.devicePixelRatio
获取设备像素比,遍历全部图片,替换图片地址:
const dpr = window.devicePixelRatio;
const images = document.querySelectorAll('img');
images.forEach((img)=>{
img.src.replace(".", `@${dpr}x.`);
})
复制代码
SVG
的全称是可缩放矢量图(Scalable Vector Graphics
)。不一样于位图的基于像素,SVG
则是属于对图像的形状描述,因此它本质上是文本文件,体积较小,且无论放大多少倍都不会失真。
除了咱们手动在代码中绘制svg
,咱们还能够像使用位图同样使用svg
图片:
<img src="conardLi.svg">
<img src="data:image/svg+xml;base64,[data]"> .avatar { background: url(conardLi.svg); } 复制代码
但愿你阅读本篇文章后能够达到如下几点:
文中若有错误,欢迎在评论区指正,若是这篇文章帮助到了你,欢迎点赞和关注。
想阅读更多优质文章、可关注个人github博客,你的star✨、点赞和关注是我持续创做的动力!
推荐关注个人微信公众号【code秘密花园】,天天推送高质量文章,咱们一块儿交流成长。
关注公众号后回复【加群】拉你进入优质前端交流群。