css

css - rem和vw

物理像素

物理像素在不同的设备中1px里可以容纳的像素颗粒是不相同的,所以1px这个单位其实也是有N个像素颗粒填充的。同一尺寸屏幕的每个像素点所能容纳的像素颗粒越多显示效果越清晰、分辨率越高。也即1个像素点所有容纳的颗粒越多,效果越好。现在的手机屏幕用肉眼已经看不到颗粒,这是由于设备支持越来越细小的像素颗粒,这些屏幕被称为retina(视网膜屏幕)。现在假设有一个1px的图片,该图片的1px容纳了1个像素颗粒,现在将该图片放进支持1px可容纳2个颗粒的屏幕中,这会将图片的那个颗粒拆分成两半放进设备的1个px里,而由于该设备的1px必须有两个颗粒才能填满,现在它的两个颗粒都没有被填满,这就会造成图片显示效果模糊。所以不是1px的图片在某个屏幕上显示是非常清楚的,那么它在另一个屏幕上就一定也清楚,清楚不清楚要看屏幕的物理像素。

像素比

像素比指的是1个px单位可以容纳的像素颗粒

分辨率

分辨率=宽*高*像素比。

简单区分屏幕的各种概念,以iphone6 plus的屏幕为例:

1.414、736是屏幕的宽高、尺寸

2.414*3*736*3是屏幕的物理像素总量、物理尺寸、物理分辨率

3.该手机屏幕的总物理像素是414*3*736*3=‭2742336‬,即1242*2208=‭2742336‬,这个尺寸的屏幕可容纳‭2742336‬个像素颗粒。pc的像素比是1,所以pc的分辨率是1920*10808*1,结果是1920*1080*1=2073600,整个pc屏幕容纳了2073600个像素颗粒。

pc与手持设备的物理像素差别

在pc屏幕里,css的1px只占用一个像素单位,这1个像素在具有大于1的像素比的手机屏幕里会变小,因为pc的1px小于手机屏幕的1px,pc的1px不能填满手机屏幕的1px。pc端的像素比是1:1,也就是说如果为某个元素设定一个16px的fontsize,那么在屏幕上就有16个像素颗粒。而手持设备的像素比是1:3及其以上,1个px单位必须填充3个px颗粒,那么把pc端的16像素放进手持设备后会发现16个像素颗粒只有5.3个物理像素(16÷3=5.3),单位太小就会导致文字太小看不清楚。

body{
    font-size:16px;
    background:#0094ff;
}

为了让手持设备正常显示16px的字号,可以改成48px(16*3)

body{
    font-size:48px;
    background:#0094ff;
}

viewport

viewport是一个视口容器,viewport可以在不改变pc端对元素的尺寸设置就可以立即实现pc端与手机端呈现相同的显示效果。也即viewport可以自动计算从而保证pc端和手持设备的分辨率一致。比如一个pc端的16px的字体,在手机端自动呈现为48px的,不需要手动更改字号大小。

声明viewport

 <meta name="viewport" />

通过content设置viewport的各个配置

<meta name="viewport" content="width=device-width,height=device-height,initial-scale=2,user-scalable=yes,maximum-scale=1.0" />  
width height :指定了视口的宽高为手持设备的宽高
initial-scale:缩放比是2倍(自动将pc端的网页放大两倍,这会导致pc端整体尺寸变大两倍,比如字号16px,将pc端浏览器放大200%就是在手机端呈现的效果)
user-scalable:允许或禁止用户缩放网页
maximum-scale:允许用户在浏览器上操作网页的最大缩放比

使用viewport通常都是将自动缩放比设为1,让pc端和手持设备的分辨率保持一致

<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1,user-scalable=no" />  

viewport的问题

viewport的优点是不需要我们手动去计算像素比,它包办让pc端和手持设备分辨率看起来一致。但它也有缺点,比如图片在手持设备中会失真。这是由于页面每个元素都计算了像素比,一个16px的文字在手机端被viewport呈现为16*3=48,现在假设一张图片的真实像素是100px,它在pc端正常显示,如果放到手持设备上,那么它会被viewport暴力拉大,100*3=300px,这就会导致图片模糊失真。所以很多程序在手持设备上都把图片做成了字体以避免失真。

rem布局

尺寸单位的对比

px:固定单位

em:相对单位,根据当前元素的字体大小进行运算得出一个px的值,计算方法是:em*自身的font-size 

rem:相对单位,根据当前文档的根节点<html>节点的字体大小进行运算得出一个px的值,计算方法是:rem*根元素html的font-size  

em与rem都有灵活性,适合在移动端布局,两者区别仅在于em看自身的字体大小决定最终尺寸,而rem只看根html元素字体大小决定最终尺寸。浏览器都有默认字体大小,如chrome的默认字体大小是16px,16px=1rem,除非你用css去控制元素的字体大小,否则你页面上的根元素即<html>元素的字体大小就是浏览器的默认字号16px。

rem布局原理

相对于em来说,rem明显更容易计算。使用em来设置元素尺寸,如果当前元素没有设置fontSize,那么你还需要逐层找到当前元素继承的字号大小,而rem只需要知道html节点的字体大小即可。我们主要利用方便计算的rem来实现移动端的布局,这个原理就是通过媒体查询获取当前屏幕的尺寸,然后根据不同的尺寸动态设置html根节点的fontSize,然后rem可以乘以不同屏幕尺寸的fontSize,实现等比例缩放。

@media screen and (min-width:320px) {
    html {
        font-size50px
    }
}
@media screen and (min-width:414px) {
    html {
        font-size64.6875px
    }
}
@media screen and (min-width:640px) {
    html {
        font-size100px
    }
}

div {
    font-size:0.48rem; //48px字体。48÷100=0.48
    width2rem; //200px的盒子 200÷100=2
    height:2rem;
    background#ff6a00;
}

<div>鸷鸟</div>
less rem适配

手持设备的尺寸太多,用less进行计算比较方便 

@charset "UTF-8";
/*主流屏幕尺寸列表*/
@screen-size-list320px,360px,375px,384px,400px,411px,414px,424px,480px,540px,640px,720px,750px,768px;
/*主流屏幕尺寸列表总长度*/
@secreen-size-list-lengthlength(@screen-size-list);
/*photoshop设计图尺寸*/
@phtoshop-size768px;
/*基字号*/
@base-font-size100px;
//主题色
@subject-color#ff6a00;
//白色
@font-color-white#fff;
//白色
@font-color-gray#373737;
//input底色
@input-bg-color#fa8e65;

/*媒体查询,根据屏幕尺寸设置基font-size*/
.set-screen-font-size(@i) when ( @i =< @secreen-size-list-length ) {
    @array-childextract(@screen-size-list,@i)
    @media ( min-width@array-child ) {
        html {
            font-size@array-child / ( @phtoshop-size / @base-font-size );
        }
    }
    .set-screen-font-size( @i + 1 );
}
.set-screen-font-size(1);
dpr rem适配

阿里高清方案

这个是阿里巴巴的rem布局,算法利用了屏幕的dpr,拷贝以下代码在head元素里,这个方案同样是1rem = 100px,设置元素尺寸的时候直接width÷100得到rem值

<script>!function (e) { function t(a) { if (i[a]) return i[a].exports; var n = i[a] = { exports: {}, id: a, loaded: !1 }; return e[a].call(n.exports, n, n.exports, t), n.loaded = !0, n.exports } var i = {}; return t.m = e, t.c = i, t.p = "", t(0) }([function (e, t) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var i = window; t["default"] = i.flex = function (normal, e, t) { var a = e || 100, n = t || 1, r = i.document, o = navigator.userAgent, d = o.match(/Android[Ss]+AppleWebkit/(d{3})/i), l = o.match(/U3/((d+|.){5,})/i), c = l && parseInt(l[1].split(".").join(""), 10) >= 80, p = navigator.appVersion.match(/(iphone|ipad|ipod)/gi), s = i.devicePixelRatio || 1; p || d && d[1] > 534 || c || (s = 1); var u = normal ? 1 : 1 / s, m = r.querySelector('meta[name="viewport"]'); m || (m = r.createElement("meta"), m.setAttribute("name", "viewport"), r.head.appendChild(m)), m.setAttribute("content", "width=device-width,user-scalable=no,initial-scale=" + u + ",maximum-scale=" + u + ",minimum-scale=" + u), r.documentElement.style.fontSize = normal ? "50px" : a / 2 * s * n + "px" }, e.exports = t["default"] }]); flex(false, 100, 1);</script>

以上js代码会自动生成一个viewport,不要再手动设置。具体参考:dpr rem适配

*iphone5的屏幕宽只有320,按照dpr=2计算,它最大只有640的宽度,如果你在css中设置了7rem(700px)的尺寸,那么iphone5的屏幕上就会出现横向滚动条,这种情况逐一要使用100%解决。

*高清屏幕dpr = 2用普通图片会模糊,因为四个物理像素要共享一个设备独立像素,会导致模糊效果,请用分辨率是两倍的图片来解决。 

hotcss高清方案

具体参考:移动端布局终极解决方案

此包需要支持scss才能起效。scss是sass的升级版,需要sass支持,而且需要全局的scss支持。如果你是在vue-cil and webpack中使用,你可以参考:全局引入scss(vue-cil + webpack适用),sass相关支持的包安装完成后,再使用cnpm hotcss安装hotcss包或直接下载hotcss包后放到src/assets目录里

css目录中的main.scss是你自己创建的全局scss文件,你可以在这个文件中导入hotcss的px2rem.scss文件,以下在main.scss中导入了hotcss的相关文件,然后定义了一个变量存储颜色

@import "../hotcss/src/px2rem.scss";
$color:red;

在main.js中导入hotcss.js,必须把这个js文件放在其它导入文件之前。

import hotcss from "hotcss"; //npm装的包的导入方式,不要在index.html入口文件中导入hotcss,直接在此处导入最佳
import hotcss from './assets/hotcss/src/hotcss' //手动下载的包的导入方式

操作完以上几步后,由于你的全局main.scss文件在任何组件文件里都有定义,hotcss的px2rem也已经导入到main.scss里,所以现在在你的.vue文件中可以如下使用它们

<style scoped lang="scss">
h1h2 {   
  font-size:px2rem(40);   //所有需要长度单位的地方都用px2rem来设置(hotcss提供的),px2rem(100)表示100px
  color:$color; //调用了全局的main.scss的变量
}
</style>

vw适配

关于vw单位,可以参考:css3自适应布局单位vwvh 

在vue-cil项目中已经自动配置好了.postcssrc.js文件,这个文件是各种处理你的css文件的插件(比如为打包后的css添加各种css属性前缀、转换px单位)的集中配置处,目前有超过几百个针对css的插件可以使用,你只需要安装它们,然后在.postcssrc.js中注册它们即可。vw适配需要安装以下插件:

npm i 
postcss-aspect-ratio-mini 
postcss-px-to-viewport 
postcss-write-svg 
postcss-cssnext 
postcss-viewport-units 
cssnano 
cssnano-preset-advanced --S
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
  "plugins": {
    "postcss-import": {},
    "postcss-url": {},
    "postcss-aspect-ratio-mini": {},
    "postcss-write-svg": {
      utf8: false
    },
    "postcss-cssnext": {},
    "postcss-px-to-viewport": {
      viewportWidth: 750,   // 视窗的宽度,对应的是我们设计稿的宽度,一般是750
      viewportHeight: 1334, // 视窗的高度,根据750设备的宽度来指定,一般指定1334,也可以不配置
      unitPrecision: 3,     // 指定`px`转换为视窗单位值的小数位数
      viewportUnit: "vw",   //指定需要转换成的视窗单位,建议使用vw
      selectorBlackList: ['.ignore', '.hairlines'],// 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
      minPixelValue: 1,     // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
      mediaQuery: false     // 允许在媒体查询中转换`px`
    },

    "postcss-viewport-units": {},
    "cssnano": {
      preset: "advanced",
      autoprefixer: false,
      "postcss-zindex": false
    }
  }
}

配置完成后,你只需要按照曾经在pc端的写法为元素添加px值即可,插件会在打包时自动计算你的px,将其转换为vw。  

 

参考

postcss真的太好用了!

CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport

css - 学习总目录

原文地址:https://www.cnblogs.com/myrocknroll/p/11068051.html