web移动端适配方案之rem适配

相关标签
remviewportmediaQueryvw,vh...

前言

最近空余时间,还是在找些react小项目练手。练手的项目不是别的,正好是目前在做的iOS项目,在边做iOS边写react的对比中,自然而然地牵扯到了webApp的适配问题。

一、移动端适配前期准备

meta标签设置ideal viewport

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">

meta viewport 标签首先是由苹果公司在其safari浏览器中引入的,目的就是解决移动设备的viewport问题。因为好用后面的各种浏览器都纷纷对此进行了兼容。这里就不解释viewport的方方面面了,这篇文章解释的很详细。移动前端开发之viewport的深入理解

二、理解rem是什么

“font size of the root element”,W3C官网是这样定义的。直白点说就是根节点元素,(一般为<html>标签)的fontSize
打个比方:

如果根节点的元素fontSize设为100px,意味着1rem=100px。那么我们如果有一个边距在UI标注中为200px,就可以写为2rem

嗯...很好理解。这也是我查看N多前端童鞋写的相关rem文章时他们主要提到的。问题是,这和传说中适配有什么关系?
别着急,耐心看下去~

三、先来谈一下iOS端的比例适配

直接看代码,以下是我在iOS端处理的适配方案:
OC代码:

/**
 *  375为UI标注采用的屏幕宽度标准
 *  实际屏幕宽 / 375,获取真实尺寸与UI尺寸比例
 */
#define BEI6 (MIN(Screen_Width, Screen_Height) / 375)
/**
 *  size为UI标准的期望值
 *  根据真实尺寸与UI尺寸的比例,计算出期望值的真实尺寸
 */
#define AutoSize(size) ((size) * BEI6)
/**
 *  根据UI标注的frame获取真实frame
 */
#define AutoFrame(frame) CGRectMake(frame.origin.x*BEI6,frame.origin.y*BEI6, frame.size.width*BEI6, frame.size.height*BEI6)

swift代码:

public func kBEI6() -> CGFloat {
    return min(kScreenWidth, kScreenHeight) / 375.0
}
public func kAutoSize(size: CGFloat) -> CGFloat {
    return kBEI6() * size
}
public func kAutoFrame(frame: CGRect) -> CGRect {
    return CGRect(x: (kBEI6() * frame.origin.x), y: (kBEI6() * frame.origin.y), width: (kBEI6() * frame.size.width), height: (kBEI6() * frame.size.height))
}

代码很简洁,很容易就能明白。
就是通过手机真实屏幕的宽度除以UI标注上的宽度尺寸,获得一个比例。再以这个比例为媒介获取每一个期望值在真实手机上的真实尺寸。

实际上rem适配的精髓和这种iOS适配方式如出一辙!

题外话:非移动端的童鞋可以忽略!!!
移动端原生控件的宽高其实并不是指单纯的像素,因为有retina屏的原因,所以原生中的1 有可能为2px或3px。这就导致了原生控件中假如给定宽为100,实际上在相同物理屏幕宽度下,其有可能是200像素,也有可能是300像素。移动端懂得自然懂。6s和6plus就是个极为典型的例子,其屏幕宽度都是414point。但其一个为2倍屏,即宽度为828像素;一个为3倍屏,宽度为1242像素。

三、rem是如何进行比例适配的

子标题这样说,细究起来是不对的。因为rem只是一个单位,1rem=根节点的fontSize值而已。其本身是不具备适配功能的。
但是其与根节点的fontSize有这种特殊关系,那我们大可以对根节点的fontSize做做手脚~通过动态设置根节点fontSize,即动态设置单位rem值,实现比例适配。
刚才说了rem适配其实与我那种iOS比例适配有异曲同工之妙iOS适配的比例因子是真实屏幕宽度与UI标注宽度的商。那在我们web端,如果获取到浏览器的真实宽度(webApp中就是webView宽度),通过其与UI标注的宽度进行除法运算,商就是我们需要的适配比例因子。再通过这个比例因子,动态比例地设置根标签的fontSize,从而达到1 rem值对应像素单位px的比例升降。
知道了步骤,我们编写代码如下:
请仔细阅读注释,句句精髓

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
    <title>rem适配</title>
    <!--因为是设置样式的js代码,所以写在head标签中了-->
    <script type="text/javascript">
        //自执行匿名函数
        (function (uiWidth, expectFontSize) {
            //获取浏览器真实宽度
            let deviceWidth = document.documentElement.clientWidth
            function setRemUnit() {
                //计算适配比例
                let scale = deviceWidth / uiWidth
                //乘以100的目的是,这样我们将UI标注的px值除以100,就是我们需要的rem值
                document.documentElement.style.fontSize = scale * expectFontSize + 'px'
            }
            //执行初始rem函数
            setRemUnit()
            //设置监听,当window重新resize的时候,重新初始rem
            window.addEventListener('resize', setRemUnit)
        })(375, 100)
    </script>
</head>

以上代码中的375,是假设的UI标注的标准宽度。依具体的UI标注进行替换。
核心思想就是设备屏幕宽度不同,比例因子不同。从而使得根标签的fontSize不同,也就是单位rem对应的px值不同。 1rem = 比例因子 * 默认期望值
我们根据上面的代码捋一下产生的结果:

  • 假如iPhone6设备(屏幕宽度为375px)上,设置一个控件宽度设为0.7rem,此时换算为px单位为(375 / 375.0 * 70) = 70px;
  • 而在iPhone8设备(屏幕宽度为414px)上,0.7rem换算为px单位为(414 / 375.0 * 70) = 77.28px。这样就很完美地实现了比例适配功能。

四、媒体查询对特殊情况进行适配

做iOS开发的时候,使用上面我提到的比例适配方案,有时候并不能完美地去进行适配。比如处理刘海屏、适配iOS11等情况。这个时候命令式的iOS语法会单独地对这些情况去做处理。那么前端语言要怎么去解决这个问题呢?

  • 第一种最直白的方法就是利用js获取真实dom,然后针对特殊情况去设置样式属性,显然这种面向过程的方式太low太繁琐。
  • 利用媒体查询mediaQuery的方式进行处理,语法如下
@media 媒体类型 and (媒体特性: 600px) {
     选择器 {
       属性:属性值;
     }
 }

具体的媒体类型和特性可以在W3C官网上查看,我个人觉得没必要看,会一些常用的。其他到用到时再去查阅即可。
举个例子说明一下:

//处理屏幕宽小于等于320px时,类名为inner的标签样式
@media screen and (max-width: 320px) {
    .inner {
        height: 100%;
        width: 25%;
        float: left;
    }
}
//处理屏幕宽大于等于321px时,类名为inner的标签样式
@media screen and (min-width: 321px) {
    .inner {
        height: 50px;  
        width: 100%;
     }
}

五、vh、vw方案适配

这种好像算是目前最流行的移动端适配方案,暂时还没接触。待定...

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

推荐阅读更多精彩内容