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

一、CSS3 Media Queries

  • 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 方案

  • less,sass,stylus三种预处理器px2rem
  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);
  }
  • flexible插件
    此处案例属于vue项目中引用
  1. 安装
npm i lib-flexible --save

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

import 'lib-flexible'
  1. 使用px2rem-loader自动将css中的px转换成rem
  • 安装px2rem-loader:
npm install px2rem-loader --save-dev
  • 配置px2rem-loader:
    (1)打开build/utils.js文件,找到exports.cssLoaders方法,在里面添加如下代码:
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的值
} 
  • 如果是大屏需要修改flexible源码
    打开./node_modules/lib-flexible/flexible.js,找到如下片段源码:
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;
}
  • 重启,完成
    修改完成后,重启项目,则会适配到相应的尺寸。此外还有一个提示,当脱离掉node_modules重新npm install项目依赖时还是需要重新修改一遍的,千万别忘了!
  • 为解决重新安装依赖需要再次配置,按以下方法:
    先把flexible.js源码文件拷贝到项目下,然后修改改文件,此处提到了src文件下,然后需要修改main.js里的引入路劲:
import './flexible'

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

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

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

  • 使用px2rem配合scss时,/px/、/no/失效:
    (1)可以把px写成大写PX,这样px2rem也不会转换,同时大写在浏览器上也是生效的。
    (2)使用普通css写,也可以生效。

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

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

  • 安装
npm install postcss-pxtorem --save-dev
  • 配置
    可以通过3个地方来添加配置,配置文件皆位于vue 项目根目录中,若文件不存在可以自行建立。
  • 权重
    vue.config.js > .postcssrx.js > postcss.config.js
    其中 postcssrc.js 和 postcss.config.js 可以热更新, vue.config.js 中做的修改要重启devServer。
  • 属性
    rootValue (Number)

根元素的值,即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单位的小数位数上限.

  • 配置示例
    vue.config.js
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();
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335