纵横研究院前端基础技术专题社区视觉艺术

网页的自适应布局和px转rem方案

2020-02-14  本文已影响0人  北风吹_yfy

一、CSS3 Media Queries

  1. 方式一:直接在link中判断设备的尺寸,然后引用不同的css文件:
// 当屏幕的宽度大于600小于800时,应用styleB.css
 <link rel="stylesheet" type="text/css" href="styleB.css"  media="screen and (min-width: 600px) and (max-width: 800px)">
在media属性里:
(1)screen 是媒体类型里的一种,CSS2.1定义了10种媒体类型;
(2)and 被称为关键字,其他关键字还包括 not(排除某种设备),only(限定某种设备);
(3)(min-width: 400px) 就是媒体特性,其被放置在一对圆括号中。
  1. 方式二:即是直接写在<style>标签里:
@media screen and (max-width: 600px) { /*当屏幕尺寸小于600px时,应用下面的CSS样式*/
      .class {
          background: #ccc;
       }          
  }

写法是前面加@media,其它跟link里的media属性相同。

其实基本上就是样式覆盖~,判断设备,然后引用不同的样式文件覆盖。 
要注意的是由于网页会根据屏幕宽度调整布局,所以不能使用绝对宽度的布局,也不能使用具有绝对宽度的元素。这一条非常重要,否则会出现横向滚动条。

二、calc()

calc()使用通用的数学运算规则,但是也提供更智能的功能:

>使用“+”、“-”、“*” 和 “/”四则运算;
>可以使用百分比、px、em、rem等单位;
>可以混合使用各种单位进行计算;
>表达式中有“+”和“-”时,其前后必须要有空格,如"widht: calc(12%+5em)"这种没有空格的写法是错误的;
>表达式中有“*”和“/”时,其前后可以没有空格,但建议留有空格。

例如 :设置div元素的高度为当前窗口高度-80px
 div{
   height: calc(100vh - 80px);     
}
或者利用%计算宽度
如: width: calc(100% - 10px);

vw Viewport宽度, 1vw 等于viewport宽度的1%
vh Viewport高度, 1vh 等于viewport高的的1%

三、rem

在JS引入rem,动态改变html的font-size。用rem动态改变字体大小:

;(function(win) {
    var tid;
    function refreshRem() {
        let designSize = 1920; // 设计图尺寸
        let html = document.documentElement;
        let wW = html.clientWidth;// 窗口宽度
        let rem = wW * 100 / designSize; 
        document.documentElement.style.fontSize = rem + 'px';
    }
    win.addEventListener('resize', function() {
        clearTimeout(tid);
        tid = setTimeout(refreshRem, 300);
    }, false);
    win.addEventListener('pageshow', function(e) {
        if (e.persisted) {
            clearTimeout(tid);
            tid = setTimeout(refreshRem, 300);
        }
    }, false);
    refreshRem();
})(window);

四、px 转 rem 方案

  1. less
 //定义一个变量和一个mixin
 @baseFontSize: 75;//基于视觉稿横屏尺寸/100得出的基准font-size
 .px2rem(@name, @px){
     @{name}: @px / @baseFontSize * 1rem;
 }

//使用示例:
.container {
   .px2rem(height, 240);
}

//less翻译结果:
.container {
   height: 3.2rem;
}
  1. sass
//定义一个变量和一个mixin
$baseFontSize: 16;//默认基准font-size
@mixin px2rem($name, $px){
  #{$name}: $px / $baseFontSize * 1rem;
}
 
// 使用示例:
 .container {
   @include px2rem(height, 240);
 }
 
//  scss翻译结果:
  .container {
    height: 3.2rem;
  }
  1. stylus
//定义一个变量和一个mixin
$baseFontSize = 16; //默认基准font-size
px2rem(name, px){
{name}: px / $baseFontSize * 1rem;
}
 
// 使用示例:
.container {
  px2rem('height', 240);
}
 
//  stylus翻译结果:
.container {
  height: 3.2rem;
}

建议将mixin放入单独文件夹下,例如webpack中的common,之后使用只需要在style中引入,以scss为例:

@import "../common/scss/mixin.scss";
 
  .all {
    @include px2rem(padding, 32);
  }
  1. 安装
npm i lib-flexible --save

2.引入lib-flexible
在main.js中引入lib-flexible:

import 'lib-flexible'
  1. 使用px2rem-loader自动将css中的px转换成rem
npm install px2rem-loader --save-dev
const px2remLoader = {
    loader: 'px2rem-loader',
    options: {
      remUint: 75,  //设计稿宽度/10, 以设计稿750为例, 750 / 10 = 75
    }
  }

(2)打开build/utils.js文件,找到generateLoaders方法, 添加px2remLoader 插件:

function generateLoaders (loader, loaderOptions) {
   const loaders = options.usePostCSS ? [cssLoader, postcssLoader, px2remLoader] : [cssLoader, px2remLoader]

   if (loader) {
     loaders.push({
       loader: loader + '-loader',
       options: Object.assign({}, loaderOptions, {
         sourceMap: options.sourceMap
       })
     })
   }
//...

(3)build/utils.js文件 添加 generateSassResourceLoader方法:

function generateSassResourceLoader () {                
       const loaders = [
          cssLoader,
          px2remLoader,
          'less-loader'
       ]
       if (options.extract) {
          return ExtractTextPlugin.extract({
             use: loaders,
             fallback: 'vue-style-loader'
          })
       } else {
           return ['vue-style-loader'].concat(loaders)
       }
    }

(4)修改 build/utils.js文件 return

return {
     css: generateLoaders(),
     postcss: generateLoaders(),
     less: generateSassResourceLoader()                //  修改less的值
} 
function refreshRem(){
    var width = docEl.getBoundingClientRect().width;
    if (width / dpr > 540) {
        width = width * dpr;
    }
    var rem = width / 10;
    docEl.style.fontSize = rem + 'px';
    flexible.rem = win.rem = rem;
}
import './flexible'

此处在提出的文件如出现eslint报错问题,可在文件顶部加上/* eslint-disable */即可。

//对于有些地方不用转换的我们可以在样式后面添加/*no*/这样就不会给我们转化了;
.box{
        width:200px;
        height:200px;
        border-radius: 50%;
        border:1px solid red;/*no*/
    }

在px后面添加/no/,不会转化px,会原样输出。 — 一般border需用这个
在px后面添加/px/,会根据dpr的不同,生成三套代码。—- 一般字体需用这个

但是使用px2rem-loader修改build/utils.js文件之后会影响css样式中的背景图片的加载,为解决该问题选择卸载px2rem-loader,使用postcss-pxtorem。

postcss-pxtorem是PostCSS的插件,用于将像素单元生成rem单位。

npm install postcss-pxtorem --save-dev

根元素的值,即1rem的值
用于设计稿元素尺寸/rootValue
比如 rootValue = 192 时,设计稿是1920*1080比例,在css中width: 960px; 最终会换算成width: 5rem;
还有一些其他的配置:

propList (Array) 需要做单位转化的属性.

必须精确匹配
用 * 来选择所有属性. Example: ['']
在句首和句尾使用 * (['
position'] 会匹配 background-position-y)
使用 ! 来配置不匹配的属性. Example: ['
', '!letter-spacing']
组合使用. Example: ['', '!font']
minPixelValue(Number) 可以被替换的最小像素.
unitPrecision(Number) rem单位的小数位数上限.

module.exports = {
  //...其他配置
  css: {
   loaderOptions: {
    postcss: {
     plugins: [
      require('postcss-pxtorem')({
       rootValue: 192,
       minPixelValue: 2,
       propList: ['*'],
      })
     ]
    }
   }
  },
 }

.postcssrc.js

module.exports = {
  plugins: {
    'postcss-pxtorem': {
      rootValue: 16,
      minPixelValue: 2,
      propList: ['*'],
    }
  }
}

postcss.config.js

module.exports = {
 plugins: {
  'postcss-pxtorem': {
   rootValue: 192,
   minPixelValue: 2,
   propList: ['*'],
  }
 }
}

这样配合flexible即可实现px转rem的适配。
如果不适用flexible,则新建rem.js文件,于main.js中引用。

// 设计稿以1920px为宽度,而我把页面宽度设计为10rem的情况下
 
const baseSize = 192; // 这个是设计稿中1rem的大小,此处要和postcss-pxtorem配置中的rootValue一致。
function setRem() {
  // 实际设备页面宽度和设计稿的比值
  const scale = document.documentElement.clientWidth / 1920 || document.body.clientWidth / 1920;
  // 计算实际的rem值并赋予给html的font-size
  document.documentElement.style.fontSize = (baseSize * scale) + 'px';
}
setRem();
window.addEventListener('resize', () => {
  setRem();
});
上一篇下一篇

猜你喜欢

热点阅读