背景:当屏幕大小不同时,元素动态缩放,凸显大屏更清晰的优势
1.百分比:层级多时,需要计算
2.flex:需要计算
3.单位rem:固定地将html的font-size设置成屏幕宽度的某一个百分比值,当需要定义宽高时,以rem为单位去设置
4.单位vw,vh:把屏幕宽高分成100份,1份就是1vw(宽)或1vh(高),如20vw代表占屏幕宽度的20%;不用设置html的font-size,用起来更方便。
同样是用巧妙的方式使用屏幕的百分比,但避开了直接使用百分比的动态复杂计算(逐渐推荐使用)
rem VS em:
rem和em都是单位,html的font-size设置多大,1rem就是多大;而父级的font-size多大,1em就是多大
html {
font-size : 30px;
}
.wrapper {
font-size:60px;
}
<div class="wrapper">
<div class="container">123div>
div>
此时1rem=30px;.container的font-size是60px
rem与等比缩放:
假设html的font-size是屏幕宽度的10%,某div的宽度设置2rem
当屏幕是600px宽时,font-size为60,该div宽占比260/600=1/5;
当屏幕是400px宽时,font-size是40,该div宽占比240/400=1/5;
相当于换了个固定宽度算百分比
用js动态地设置font-size的值:
window.onload = function() {
var w = document.documentElement.clientWidth;
document.documentElement.style.fontSize = w / 10 + 'px';
}
<style>
body {
margin: 0;
}
div {
font-size: 1rem;
height: 2rem;
width: 2rem;
color: #fff;
background-color: pink;
}
style>
<body>
<div>pppdiv>
body>
效果:
当屏幕是ipone5/SE时,屏幕宽度320px,此时div的大小是64*64
当屏幕是Galaxy Fold时,屏幕宽度280px,此时div大小是56 * 56
(当改变手机型号时,要刷新一下,要不然数据是上一个手机的)
1.物理像素:物理像素又被称为设备像素,它是显示设备中一个最小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度
2.逻辑像素:一个可以由程序使用的虚拟像素(如CSS像素),然后由相关系统转换位物理像素
3.设备像素比(dpr)=物理像素/逻辑像素
一个物理像素≠一个逻辑像素,不同系统对应的逻辑像素不同
随着科技不断发展,屏幕的像素越来越高,原本一个逻辑像素对应一个物理像素,现在可能一个逻辑像素对应2-3个物理像素,可能375px的宽,物理像素达到了700个,考虑长*宽,可能需要4或9个物理像素为1px服务
安卓手机的dpr有多种,每种可能都不一样,兼容起来比较难
背景:1px问题:
当页面追求更精细的样式效果,即:对一个物理像素做样式的设置,如果用0.5px甚至更小的px,有些浏览器不能识别,直接抹零,样式就不能生效
这里拿苹果手机的屏幕做例子,它的dpr一般是2或者3
如果dpr=2,我设置border时只想设置1个物理像素,就想写0.5px,
但有的浏览器不识别0.5px,会直接抹掉,变成0px,就没有border了,这时候就需要用viewport视窗来实现这个效果了
viewport就是浏览器上,用来显示网页的那一部分的区域。
viewport严格等于浏览器的窗口,在桌面浏览器中,viewport就是浏览器窗口的宽度高度,但在移动端设备上,需要考虑逻辑像素与物理像素,精细样式如何体现等等
IOS及新版本浏览器默认viewport为980px
把html页面默认写好的viewport注释掉,再看移动端页面大小:
可以看到,并不是屏幕多大,页面就是多大的,可以看到,宽度是980px,是默认预设的宽度:
设置980px是因为一开始的页面都是展示在电脑上的,浏览器多大,页面就怎么显示,但是放在手机显示,可能会因为屏幕大小差距大,页面被缩小到用户无法看清内容,需要手动放大,后来设置手机页面默认宽度980px,手机屏幕放不下就用横向滚动条,滚动着看
viewport默认有6个属性:
1.width:设置viewport宽度,可以为一个整数,或字符串"device-width"设备宽度
2.initial-scale:页面初始的缩放值,为数字,可以是小数,写小数num,就相当于放大1/num,可以将逻辑像素拓展到与物理像素是1:1状态,就可以不用写小于1的px(如0.5px)来表示一个物理像素了
3.minimun-scale:允许用户的最小缩放值,为数字,可以是小数
4.maximun-scale:允许用户的最大所防止,为数字,可以是小数
5.height:设置viewport的高度(一般用不到)
6.user-scalable:是否允许用户进行缩放,'no’为不允许,‘yes’为允许;现在是用响应式布局,默认会根据页面大小缩放元素,用户不需要自己缩放,此项写’no’,且将initial-scale、minimun-scale、maximun-scale三个设置成一样的
解决办法
比如在ipone6/7/8上设置initial-scale为0.5,屏幕宽度从375变成了750,ipone6/7/8的dpr=2,此时再在html等文件里写1px,就是指的一个物理像素,就不用写0.5px了
iponeX的dpr=3,initial-scale就可以写成0.3333
为了兼容各设备的dpr,用js判断dpr,然后动态设置initial-scale
var oMeta = document.createElement('meta');
oMeta.setAttribute('name','viewport');
if (window.devicePixelRatio == 3) {
oMeta.setAttribute('content', 'width=device-width, initial-scale=0.333,minimun-scale=0.333,maximun-scale=0.333,user-scalable=no');
}
if (window.devicePixelRatio == 2) {
oMeta.setAttribute('content', 'width=device-width, initial-scale=0.5,minimun-scale=0.5,maximun-scale=0.5,user-scalable=no');
}
document.getElementsByTagName('head')[0].appendChild(oMeta);
window.devicePixelRatio的值可能不会是整数,可以在console里看看
等比缩放与1px问题结合
viewport和上面的rem可以结合起来使用,这样既解决1px的问题,又等比缩放
设置1rem=页面宽十分之一,div宽2rem,高100px;
ipone6/7/8的dpr=2,设置了viewport之后,body宽为750px,div宽为750/102 = 150,再加border,宽152px
iponeX的dpr=3,设置了viewport之后,body宽为1125px,div宽约为1125/102 = 225,再加border,宽227px
关于这个方法,手淘将这个功能扩展并封装成js文件
方案:手淘解决方案flexible
http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js
功能效果:
1.根据屏幕大小动态改变html的fontSize,解决等比缩放问题
2.给body设置fontSize,字体大小可以直接继承body的font-size
3.给html标签添加data-dpr属性,可以通过查找该属性,给不同dpr设备设置个性化属性,如:
[data-dpr='2'] div{
font-size: 26px;
}
用css的解决办法:
另一种解决1px问题的办法,就是使用css3中的transform,先把宽高都写大一些,然后再用transform缩小(meta的initial-scale恢复默认的1.0)
当我设置宽高100px,border为1px时:
div {
width: 100px;
height: 100px;
border: 1px solid black;
color: #fff;
background-color: pink;
}
当我用transform时:
div {
width: 200px;
height: 200px;
border: 1px solid black;
color: #fff;
background-color: pink;
transform: scale(0.5, 0.5);
transform-origin: 0 0;/* 中心点是左上角 */
}
可以看到,border是有差别的,第二个border的1px对应的就是1个物理像素(ipone 6/7/8的dpr是2)
解决办法3:
还有一种解决等比和1px的方法,用vw,
vw+postcss(插件)(推荐)
根据设计稿(如宽度750px的设计稿,以px为单位写大小),转换成vw,解决等比缩放问题
对于小于1px的线,以px为单位,不转成vw。
postcss-write-svg插件主要用来处理移动端1px的问题,主要使用border-image和background来做1px的相关处理,编译出来是border-image或者background
对于等比缩放功能:
比如,设计稿是750px的,里面有一个100px的btn,1vw = 7.5px,求?vw = 100px;这样就可以解决等比缩放的问题
有插件专门可以计算在设计稿宽度下,px与vw的换算
install后点击右下角的齿轮------设置------修改设计稿的宽度
默认750,如果是其他宽度,如1125px,就可以在这里改
效果:
也有插件可以解决rem与vw的换算,一般只使用rem或vw中的一种,两种插件一个使用,一个禁用(启用禁用后要重启vscode)
默认html的font-size是16px:
在首选项----设置(file----preference----setting)-----搜索插件名,可以看到和修改html的font-size:
效果:
最后:dpr不同的设备上图片的适配问题
分辨率大的图放在dpr小的设备上,会被降采样,图片不会模糊,但不那么锐利了,色彩不那么丰富,分辨率小的图放在dpr大的设备上,每一块像素会被分解成多块,图片会变模糊
解决办法:
用meta动态匹配,或用js动态匹配,当dpr小的情况,放分辨率较低的图;当dpr大的情况,放分辨率高的图
或者都使用高清图即可
用meta:
@media
only screen and (-webkit-min-device-pixel-ratio:2),
only screen and (min--moz-device-pixel-ratio:2),
only screen and (-o-min-device-pixel-ratio:2/1),
only screen and (min-resolution:192pdi),
only screen and (min-resolution:2dppx){
/*判断dpr*/
div{
img:...
}
}
用js:
window.onload = function() {
if (window.devicePixelRatio > 1){
var images = Array.prototype.slice.call(document.getElementsByTagName('img'));
images.forEach(function (ele, index) {
var lowers = images[index].getAttribute('src');/*logo.png*/
var highers = lowers.replace('.','@2x.');/*[email protected]*/
images[index].setAttribute('src',highers);
});
}
}