06、手把手教Vue--移动webapp适配方案--rem

PS:转载请注明出处
作者: TigerChain
地址: https://www.jianshu.com/p/443c6704d8d8
本文出自 TigerChain 简书 手把手教 Vue 系列

大纲

教程简介

  • 1、阅读对象
    本篇教程适合新手阅读,老手直接略过
  • 2、教程难度
    初级,本人水平有限,文章内容难免会出现问题,如果有问题欢迎指出,谢谢
  • 3、Demo 地址:https://github.com/tigerchain/vue-lesson 请看 05、移动webapp适配--rem 这一节

正文

一、media query「媒体查询」

在聊 rem 之前,我们先看看什么是 media query?

为了适配多种屏幕大到电脑,小到手机等, css3 中有了多媒体查询这个功能「是继承 css2 多媒体类型的思想」,通过 media query 就可以做响应式的开发

1、media query 的作用

  • 可以检测 viewport(视窗) 的宽度与高度
  • 可以检测设备的宽度与高度
  • 可以检测设备的分辨率

2、media query 的语法

@media not|only mediatype and (expressions) {
    CSS 代码...;
}

我们可以看到 media query 由四部分组成

  • 1、关键字:@media
  • 2、操作符:not|only|all 「默认不写就是 all」
  • 3、媒体类型:mediatype
  • 4、表达式:expressions

这里的媒体类型有以下几种:

描述
all 用于所有多媒体类型设备
print 用于打印机
screen 用于电脑屏幕,平板,智能手机等。
speech 用于屏幕阅读器

一般情况下我们使用 screen 的媒体类型是最多的

举个例子

我们想让在屏幕尺寸大于 375px 的设备上让 class 为 div1 的背景显示成红色,media query 哪下定义

@media screen and (min-device-width : 375px){
    .div1 {
        background-color:red;
    }
}

我们可以针对不同的设备宽度来设置不同的样式 ,这样就达到了响应式布局的效果,现在我们来一个例子说明吧

3、demo 验证 media query

效果如下

media query 效果

从上面的效果图我们可以看到,我们针对不同屏幕宽度就会显示不同的效果,这就是响应式布局,下面我们使用 media query 来实现这一效果

撸码实现上述效果

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>media-query</title>
  <!-- 重置默认的 css 样式 ,类似于 reset.css -->
  <link rel="stylesheet" href="../css/normalize.css">
  <!-- https://necolas.github.io/normalize.css/7.0.0/normalize.css -->

  <style>
    .box {
      width:100% ;
      height:80px;
      background-color: red;
    }

    /* 屏幕小于 375 px 则是下面的样式 */
    @media screen and (max-device-width : 375px){
      .div1 {
        width:25%;
        background-color: green;
        height:80px;
      }
    }

    /* 屏幕大于 376 小于 414 px 则使用下面的样式 */
    @media screen and (min-device-width : 376px) and (max-device-width:414px){
      .div1 {
        width:50%;
        background-color: blue;
        height:80px;
      }
    }

    /* 小于等于 375px 使用以下样式  */
    @media screen and (max-device-width: 375px) {
      .menuitem1 {
        height: 100px;
        width: 100%;
        background-color: yellow;
      }
      .menuitem2 {
        height: 100px;
        width: 100%;
        background-color: blue;
      }
      .menuitem3 {
        height: 100px;
        width: 100%;
        background-color: #cceedd;
      }

      .menuitem4 {
        height: 100px;
        width: 100%;
        background-color: black;
      }
    }

    /* 大于等于 376px 使用以下样式 */
    @media screen and (min-device-width: 376px) {
      .menu {
        display: flex;
      }
      .menuitem1 {
        height: 100px;
        width: 100%;
        background-color: yellow;
      }
      .menuitem2 {
        height: 100px;
        width: 100%;
        background-color: blue;
      }
      .menuitem3 {
        height: 100px;
        width: 100%;
        background-color: #cceedd;
      }
      .menuitem4 {
        height: 100px;
        width: 100%;
        background-color: black;
      }
    }
  </style>
</head>
<body>

  <div id="contnainer" class="box">
    <div class="div1"></div>
  </div>
  <!-- mediaquery 实现响应式布局 -->
  <div class="menu">
    <div class="menuitem1"></div>
    <div class="menuitem2"></div>
    <div class="menuitem3"></div>
    <div class="menuitem4"></div>
  </div>

</body>
</html>

以上代码就实现了上述效果图,代码注释清楚,这里也不多说了

二、rem「font size of the root element」

1、什么是 rem

rem 就是根据网页根元素「html」来设置字体大小,这有什么用呢?这是移动 webapp 的最佳的适配方案「目前来说」,既然说是最佳的适配方案,那肯定还有别的适配方案,先看看都有那些适配方案吧

  • 1、viewport缩放「被废弃了」
  • 2、宽度固定两边留白「体验很差」
  • 3、响应式布局「工作量太大,针对不同的分辨率写一套 android 下估计开发者就疯了」

2、如何适配

我们先来看一个简单的例子吧,然后就能得到一些启发和感悟

  • 1、新建一个 rem.html 然后输入以下内容
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <!-- 重置默认的 css 样式 ,类似于 reset.css -->
  <link rel="stylesheet" href="../css/normalize.css">
  <title>rem demo</title>

  <style>
    .box {
      width: 100px;
      height: 100px;
      background-color: red;
      text-align: center;
    }
    .test {
      font-size: 16px;
      line-height: 100px;
    }
  </style>
</head>
<body>
  
  <div class='box'>
    <span class="test">测试</span>
  </div>

</body>
</html>

很简单就是一个宽高为 100px 的 div 并且里面有一个居中的文字大小为 16px

  • 2、运行查看结果
px 显示效果

从图中我们可以看到,不管我们是什么分辨率的机型下,div 宽高都为 100px,这是不合理的,根本就没有适配「就是写死的呀」

  • 3、由于 2 中的效果是写死的,我们来看看 rem 是如何适配的,稍微把代码改一下

我们知道 rem 和 html 下的 font-size 有关,我们来改代码吧

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <!-- 重置默认的 css 样式 ,类似于 reset.css -->
  <link rel="stylesheet" href="../css/normalize.css">
  <title>rem demo</title>

  <style>
     html {
       font-size: 16px;
     }
    .box {
      width: 10rem;
      height: 10rem;
      background-color: red;
      text-align: center;
    }
    .test {
      font-size: 1rem;
      line-height: 10rem;
    }
  </style>
</head>
<body>
  <div class='box'>
    <span class="test">测试</span>
  </div>
</body>
</html>

ps: 这里说明几点

为什么这里 font-size 要写成 16px ,因为大部分浏览的默认字体都是显示 16px,我们从 chrome 调试工具中可以看到

chrome 默认的 font-size

html 默认的 font-size 大小就 = 1rem , 从上面代码我们可以看到 box 的宽高都为 10rem 即 160px ,我们来验证一下,运行看结果

没有改变 rem

果然是 160px「肯定在别的分辨率上也是 160px」,这有个毛用呀,不就是把 100px 转化成 160px 了吗?还不是没有适配呀「大家是不是有这个疑问」,别急马上揭晓答案

我们可以想一下,rem 和 font-size 有关,那么如果我们能动态的修改 font-size 的大小,那么以 rem 为单位的宽高等不就自动适配了吗。我们来一下修改 font-size 的效果

修改 font-size

看到了吧,我们手动修改 font-size 的值 div 的宽高就会动态改变「如果在不同分辨率的手机上设置不同和 font-size 那不就达到适配的效果了」

三、适配手段

我们知道只要动态的修改 font-size 使用 rem 就可以适配多种手机了

  • 1、通过 media query 来设置 font-size,比如:
html {
    font-size : 20px;
}
@media only screen and (min-width: 401px){
    html {
        font-size: 25px !important;
    }
}
@media only screen and (min-width: 450px){
    html {
        font-size: 26.75px !important;
    }
}
@media only screen and (min-width: 481px){
    html {
        font-size: 30px !important; 
    }
}
  • 2、通过 js 来设置

估计上面的方法能把人写疯,特别对于 android 这个多样机型来说「一般只适配常用的分辨率」,那就有了下面的方法,使用 js 来动态设置 font-size

再说 js 动态修改 font-size 之前,先推导下 px 转化成 rem 的公式:

比如:1rem = 16px「rem 的基准值」 ; 48px = 48/16 = 3rem,

所以得出:

rem = 需要转化的px/rem基准值

rem 基准值「和 html 的 font-size 有关」如何算,这里给出一个比较常见的做法,就是用设计稿的屏幕宽度/10 ,原则上除以多少都可以,除以 10 是为了好除「业界基本上也是这样做的」,比如以 iPhone 6p「414*736」 为例子,那么 rem 的基准值就是 414/10 = 41.4px,然后我们就是要不停的改变这个页面基准值的值即可,我们只要记住一点,rem 的基准值是根据设计稿来决定的

我们也知道了,如果把一个 px 转化成 rem 那么就是使用 px/rem基准值,这样界面中的 css 中有太多的 px ,如果一个个除下来人头发都白了「也不一定能除完,当然网上也有在线转换网站,就是这样也累呀」,我们可以使用 sass「css 扩展语言」 来解决这个问题

1、sass 的安装

gem install sass
gem install compass

以上安装速度如果慢的话,可以切换成淘宝的 gem「安装基于ruby的软件」源

  • 3、查看是否安装成功
sass-v

如果看到这个,就证明 sass 安装成功了

2、写个 demo 感受一下

  • 1、新建一个 usesass.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="../css/normalize.css">
  <link rel="stylesheet" href="../css/usesass.css">
  <title>使用 sass </title>
</head>
<body>

  <div class="box">
    <div class="item"><span>1</span></div>
  </div>

</body>
</html>

细心的朋友会发现,我们这里引入了一个 usesass.css 样式文件,哪来的?目前这个文件是不存在的,完后我们使用 sass 直接转换成普通的 css 文件即可

  • 2、在 css 目录下新建 usesass.scss 文件

scss 和 sass 文件区别,前者对格式没有严格要求,后者对格式有严格的要求「没有大括号等,这里我们使用 scss」

.box{
  background-color: red;
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.item {
  background-color: yellow;
  width:50px;
  height:50px;
}
  • 3、scss 肯定是直接不能使用的,我们要转化一下,使用 sass 命令

我们进入到 css 目录下使用如下命令

sass usesass.scss usesass.css

这样就会在 css 目录下创建一个 usesass.css 文件并且把 sass 转化成 css 了,我们看看这个 css 文件

.box {
  background-color: red;
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center; }

.item {
  background-color: yellow;
  width: 50px;
  height: 50px; }

看起来和上面的 sass 文件是一毛一样的「原因是我们没有使用 sass 的扩展语法,sass 是兼容所有的版本的 css 的」

  • 4、运行一下看结果
sass 转 css

没有什么毛病,sass 成功转化成 css 并且显示出结果了

3、使用 sass 来转化 px--rem ,并且使用 js 动态设置 font-size

  • 1、提供 px2rem() 函数

在 sass 中我们可以使用函数,我们定义一个函数用来转化 px 到 rem,这里以视觉稿为 iphone 6p「414*736」 为例子,那么 rem 的基准值就是 41.4px ,我们在 usesass.sass 中添加如下代码,并且修改 box 的宽高 px 为 rem「调用 px2rem()方法」

@function px2rem($px){
  // rem基准值
    $rem : 41.4px;
    @return ($px/$rem) + rem;
}

.box{
  background-color: red;
  width: px2rem(100px);
  height: px2rem(100px);
  display: flex;
  justify-content: center;
  align-items: center;
}
.item {
  background-color: yellow;
  width:px2rem(50px);
  height:px2rem(50px);
}
  • 2、使用 js 动态的修改 font-size 的值

在 usesass.html 添加以下动态修改 font-size 的代码

<script>
  // 取得屏幕宽度
  var devicewidth = document.documentElement.clientWidth || document.body.clientWidth
  //动态设置 html font-size 值
  document.getElementsByTagName('html')[0].style.fontSize = devicewidth / 10 + 'px';
</script>
  • 3、记得一定要把 sass 转化成 css
sass usesass.scss usesass.css

我们再看看 usesass.css 文件

.box {
  background-color: red;
  width: 2.4154589372rem;
  height: 2.4154589372rem;
  display: flex;
  justify-content: center;
  align-items: center; }

.item {
  background-color: yellow;
  width: 1.2077294686rem;
  height: 1.2077294686rem; }

我们看 px 成功的转化成 rem 了,这样我们就可以动态的修改 rem 了

  • 4、看看效果吧

先看效果之前,我们为了方便测试,来给动态修改 rem 添加一个事件吧,否则每次修改分辨率都要重新刷新一下浏览器「这里是为了演示添加的代码」

// 窗口大小改变时的回调
window.onresize = function(){
  // 取得屏幕宽度
  var devicewidth = document.documentElement.clientWidth || document.body.clientWidth
  //动态设置 html font-size 值
  document.getElementsByTagName('html')[0].style.fontSize = devicewidth / 10 + 'px';
}
使用 js 动态修改 font-size

依据前面我们知道,我们是以设计稿为 iphone 6p 基准来设置的「在此手机上宽高就是 100 px」,从上图可以看到确实在不同的分辨率手机下 box 的宽高等比缩放,这就达到了适配的目的,基本上 rem 适配手机 webapp 方法就说完了

四、参考资料

腾讯全端AlloyTeam团队--移动web适配利器--rem:http://www.alloyteam.com/2016/03/mobile-web-adaptation-tool-rem/


点赞富一生,转发富五代,更多文章请关注我的微信公号来查阅

公众号:TigerChain

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

推荐阅读更多精彩内容