移动端适配方案(手机专用的自适应方案)

区分:px em rem vh/vw

首先都是单位

  • px 在缩放页面时,使用px作为单位的字体、按钮等的大小不会自适应;
  • em 的值并不是固定的,基于父元素的 font-size ,代表倍数;
  • rem 的值并不是固定的,始终是基于根元素 <html> 的`font-size`,也代表倍数。
  • vw/vh 是浏览器视口宽度 / 视口高度(viewport width/viewport height)的 1/100。在手机端,vw/vh 的值是固定的,因为用户不能在手机上缩放浏览器。100 vw 就是浏览器视口宽度。100 vh 就是浏览器视口高度。

注意:

  • chrome 字体 font-size 最小为 12px
  • 浏览器的默认字体的 font-size 是 16px,未经字体大小调整的浏览器显示 1em = 16px。
  • 元素的 font-size 属性可继承,子元素的 font-size 默认继承 父元素的 font-size。
  • 1em == the font-size of father-element
  • 1 rem == the font-size of html-element == 100 viewport width

手机端方案的特点

  1. 所有手机显示的界面内容都是一样的,只是内容大小不同,要求页面内容根据设备宽度可以等比例放大,完美还原设计稿。
  2. 不同型号的手机,屏幕宽度不同,也就是浏览器视口宽度不同,可以理解为展示网页的窗口大小不同。但是型号定了,移动设备宽度不会改变,而PC端用户可以改变浏览器窗口大小。至少要记20种 手机型号的屏幕宽度。
  3. 1rem === 10 vw

百分比布局的缺点

百分比布局是元素 的宽度使用了百分比,但是这样做最大的缺点是 元素的高度未知,元素的宽度和高度没有办法建立关联、配合使用,比如让你做一个 宽高1:1 的图,宽高 1:2 ?百分比布局根本做不了,设置 height: 20% 并不会根据元素的宽度去计算。

引入 REM

引入 REM 方案到布局中,就是为了解决百分比布局中元素宽高无法建立起联系的问题。

移动端适配的目标

要求页面内容根据设备宽度可以等比例放大,所有型号的手机浏览器视口展示的内容完全一样,完美还原设计稿。

移动端适配方案

  1. 开发时,网页中使用的单位一切以宽度为准,就能完美还原设计稿。

其实 px em rem 都与宽度无关,只有 vw 与 宽度有关,但是 vw 的兼容性不好。退而求其次,想办法建立 视口宽度 和 rem 联系,而 rem 始终以 html 的 font-size 为标准,因此 使用 JS 将 html 的 font-size 设置为 浏览器视口宽度(100 vw),那么 1 rem === 100vw

  1. 使用 JS 动态调整 REM 的 心路历程,完整 code
  1. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  2. <script>
  3. var pageWidth = window.innerWidth // window.innerWidth 是浏览器视口宽度
  4. document.write('<style>html{font-size:'+pageWidth+'px;}</style>')
  5. </script>

在上面代码中,因为 html 是根元素,其它元素默认继承了 html 的 font-size 。

注意,因为 直接 1rem === 100vw,导致在网页开发过程中很多单位都是小数,因此我们可以改成 1rem === 1vw,如:

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 <script>
     var pageWidth = window.innerWidth
     document.write('<style>html{font-size:'+pageWidth/100 +'px;}</style>')
 </script>

但是呢,上面是不对的。因为当浏览器视口宽度较小时,比如很多手机,如 视口宽度只有 320px,百分之一只有3.2px,因此我们用JS 将 html 根元素的 font-size 改成了 3.2px,大错特错,我们忽略了 chrome 浏览器限制元素的 font-size 最小为 12px ,结果就是 用JS 将 html 根元素的 font-size 改成了 3.2px 的操作失败!!!!

取不了百分之一,取十分之一可以吧!最终,1rem === 10 vw,也就是 html 根元素的 font-size 是 浏览器视口宽度的 1/10。

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 <script>
     var pageWidth = window.innerWidth
     document.write('<style>html{font-size:'+pageWidth/10 +'px;}</style>')
 </script>

总结:1rem === 100vw 太大,1 rem === 1vw 太小, 1rem === 10vw 刚好合适。

  1. rem 方案 实质是使用 rem 单位 模拟 vw 单位, vw 单位其实是最好的,奈何兼容性不好。
  2. 使用 REM 方案就可以 实现任意宽高比例的 div
  3. REM 做自适应布局 单位使用规则:通常 border 、文字的font-size 太小,就直接使用 px 单位,数字大才使用 rem 单位。
 font-size: 16px;
 border: 1px solid red;
 width: 0.5rem;

第一个完整的 移动端页面

code 1

code2

为什么不在 PC 端使用 动态REM 做自适应布局?

  1. 可以用

首先,PC端也是可以使用 动态REM做自适应布局的,但是还是推荐在移动端使用动态REM 做自适应布局。

  1. 怎么用

PC端用rem首先要用resize()函数把平常用的remjs包含起来,因为手机屏幕宽度固定,而pc端用户可以改变浏览器窗口大小。PC端用rem做响应式,应该动态监听窗口的resize动作,当窗口的分辨率变化时,动态计算html的font-size大小

参考:pc端与移动端适配解决方案之rem

(function (doc, win) {
        var docEl = doc.documentElement,
            resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
            recalc = function () {
                var clientWidth = docEl.clientWidth;
                if (!clientWidth) return;
                if(clientWidth>=640){
                    docEl.style.fontSize = '100px';
                }else{
                    docEl.style.fontSize = 100 * (clientWidth / 640) + 'px';
                }
            };

        if (!doc.addEventListener) return;
        win.addEventListener(resizeEvt, recalc, false);
        doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);

使用:在html页面开头,引入上面的原生js代码。

代码意思是:如果页面的宽度超过了640px,那么页面中html的font-size恒为100px,否则,页面中html的font-size的大小为: 100 * (当前页面宽度 / 640)

  1. 为什么不用?

PC端一般不用rem主要是对低版本浏览器的兼容性问题,比如从ie9才开始支持rem,但是只是部分支持。ie11才全部支持。IE7、IE8不支持;IE9、IE10部分支持例如:rem用在伪元素和缩写样式上就不支持

  1. 若非要用

PC端检查一下是否浏览器是否支持rem,如果不支持的话提示升级浏览器。否则,只能使用兼容的”库”。

  1. PC页面制作建议

单位建议使用 px、百分比 ,em不建议使用,不好用。

REM 方案的痛点

  • 单位转换!因为我们通常收到的设计稿是以 px 为单位的,难道前端开发时候还要手动改成 rem 单位???
  • 解决办法:在 style.scss 文件 里使用 px2rem 函数 自动将 px 装换成 rem。
  • 安装 scss 是前端一大难点,要 fq。官网安装 sass 方式要逆天。下面是 window 的 命令行安装方式
  • npm config set registry https://registry.npm.taobao.org/
  • vi .bashrc
  • 在 vim 模式下,输入export SASS_BINARY_SITE="https://npm.taobao.org/mirrors/node-sass"
  • 按下 Esc键,输入 :wq 退出命令行的 vim 模式。
  • npm i -g node-sass
  • 然后等待安装,就能看到 + node-sass@4.12.0 安装成功提示。
  • mkdir scss-demo
  • cd scss-demo
  • mkdir scss css
  • touch scss/style.scss
  • touch css/style.css
  • 保证你的 index.html 文件里面有用 JS动态修改 html 根元素的 font-size。即写了下面代码
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<script>
     var pageWidth = window.innerWidth
     document.write('<style>html{font-size:'+pageWidth/10 +'px;}</style>')
</script>
  • 打开 style.scss,在 scss 文件里添加```scss @function px( $px ){ @return $px/$designWidth*10 + rem;
    }

$designWidth : 640; // 640 是设计稿的宽度,你要根据设计稿的宽度填写。如果设计师的设计稿宽度不统一,就杀死设计师,换个新的。

.child{ width: px(320); height: px(160); margin: px(40) px(40); border: 1px solid red; float: left; font-size: 1.2em; }


- `node-sass scss/style.scss css/style.css`,使用命令自动编译 scss 文件,得到 css 文件。<br />命令行反应

Rendering Complete, saving .css file… Wrote CSS to G:\frontend\sass-demo\css\style.css

<br />然后打开  style.css 文件就可以看到  px 变成 rem。这时候你就可以开服务器验收 网页的,注意 index.html 要引入 style.css 文件。
- 解释一下上面的代码,更开始还很迷糊,走了点弯路。`$px/$designWidth*10`是指用设计稿上元素的宽度(单位px) / 设计稿的宽度((单位px) * 10  得到 rem 倍数,而 rem 是动态的,rem 具体是多少 px 由设备视口宽度决定,我们需要同时使用 js 动态修改 html 元素 的 font-size。**也就是通过设计稿我们得到一个比例,基数还得由设备决定,这样实现的缩放。**

<a name="ec442b2c"></a>
### SASS 使用

1. 安装 node-sass
2. 建立 sass-demo 项目,  项目下需要有 scss/style.scss  和 css/style.css 两个目录,及 index.html 。
3. 每一次 更改了 style.css 文件都要 手动编译。执行下面这行命令

node-sass scss/style.scss css/style.css ```

为什么你学不好 LESS/SASS/Webpack

  1. 你不会命令行,你非要用 Windows。 LESS/SASS/Webpack 使用方式都是命令行。
  2. 你不会英语(有些内容可以看中文翻译)
  3. 你不会看文档(很重要的能力),你要强制自己去看文档。