PS:转载请注明出处
作者: TigerChain
地址: //www.greatytc.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 | 用于所有多媒体类型设备 |
用于打印机 | |
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 来实现这一效果
撸码实现上述效果
<!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、运行查看结果
从图中我们可以看到,不管我们是什么分辨率的机型下,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 调试工具中可以看到
html 默认的 font-size 大小就 = 1rem , 从上面代码我们可以看到 box 的宽高都为 10rem 即 160px ,我们来验证一下,运行看结果
果然是 160px「肯定在别的分辨率上也是 160px」,这有个毛用呀,不就是把 100px 转化成 160px 了吗?还不是没有适配呀「大家是不是有这个疑问」,别急马上揭晓答案
我们可以想一下,rem 和 font-size 有关,那么如果我们能动态的修改 font-size 的大小,那么以 rem 为单位的宽高等不就自动适配了吗。我们来一下修改 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 的安装
- 1、安装 ruby 地址:http://rubyinstaller.org/downloads/ 建议安装 2.4.3 版本
- 2、安装 sass 和 compass
gem install sass
gem install compass
以上安装速度如果慢的话,可以切换成淘宝的 gem「安装基于ruby的软件」源
- 3、查看是否安装成功
如果看到这个,就证明 sass 安装成功了
- 4、具体的安装过程请看:https://www.sass.hk/install/
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 并且显示出结果了
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';
}
依据前面我们知道,我们是以设计稿为 iphone 6p 基准来设置的「在此手机上宽高就是 100 px」,从上图可以看到确实在不同的分辨率手机下 box 的宽高等比缩放,这就达到了适配的目的,基本上 rem 适配手机 webapp 方法就说完了
四、参考资料
腾讯全端AlloyTeam团队--移动web适配利器--rem:http://www.alloyteam.com/2016/03/mobile-web-adaptation-tool-rem/
点赞富一生,转发富五代,更多文章请关注我的微信公号来查阅
公众号:TigerChain