盘点移动端适配方案

盘点移动端适配方案

移动端.png

作为开发者,在手机移动端做适配的时候会出现很多问题:最不希望用户看到的就是横向滚动条。其次是文字(图片等)的大小不能一成不变,要根据用户设备的物理像素调节大小。

手机浏览器是把页面放在一个虚拟的"窗口"(viewport)中,通常这个虚拟的"窗口"(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中(<u>这样会破坏没有针对手机浏览器优化的网页的布局</u>),用户可以通过平移和缩放来看网页的不同部分。

这就该轮到meta标签出场了。meta标签的作用是让当前viewport的宽度等于设备的宽度,同时不允许用户手动缩放。也许允不允许用户缩放,不同的网站有不同的要求,但让viewport的宽度等于设备的宽度,这个应该是大家都想要的效果,如果你不这样的设定的话,就会使用那个比屏幕宽的默认viewport,也就是说会出现横向滚动条;

  • 设置Viewport

一个常用的针对移动网页优化过的页面的 viewport meta 标签大致如下:

<meta name="viewport" content="width=device-width, initial-scale=1.0">
  • width

控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。

  • initial-scale

初始缩放比例,也即是当页面第一次 load 的时候缩放比例。

  • user-scalable

用户是否可以手动缩放(默认设置为no,因为我们不希望用户放大缩小页面)

  • minimum-scale

允许用户缩放到的最小比例(默认设置为1.0)

  • maximum-scale

允许用户缩放到的最大比例(默认设置为1.0)

一、rem适配

rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem大家一定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很相似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。

正是因为它适配的标准是根元素的字体大小,而不同的手机型号对于根元素的规定不同[1],这便增加了很多不必要的判断。

二、vw适配

vw(viewpoint width),即视窗宽度,1vw等于视窗宽度的1%

计算方式(以750的设计稿为准):设计图中元素固定的大小(px) * 100 / 750 => vw

eg : 90px转化为vw : 90 * 100 / 750 => 12vw

如果是375的设计稿需要乘以2 : 设计图中元素固定的大小(px) * 2 * 100 / 750 => vw

不难看出,使用的时候仍需进行大量的计算。

三、vw+rem适配

因为vw的比例需要动态地计算,而rem做移动端布局的时候刚好需要动态地改变,因此我们只要稍加计算,将根元素的字体大小换成vw即可。

  • 640的设计稿

    320px == 100vw ; 1px == 100 / 320 == 0.3125vw ; 100px == 31.25vw;

    此时设置根元素字体大小html,body{font-size:31.25vw} , => 1rem == 100px; =>1px == 0.01rem;

    所以,根据设计稿的像素计算时,只需将px除以100即可

    计算方式:元素尺寸 / 2 / 100 = rem

    320的设计稿计算方式:元素尺寸 / 100 = rem

  • 750的设计稿

    375px == 100vw ; 1px == 100 / 375 == 0.26666vw ; 100px == 26.6666vw

    出现了小数点后除不尽的情况……为了将结果它转换成整数 120px == 32vw此时设置根元素字体大小html,body{font-size:32vw} , 计算方式也发生改变:元素尺寸 / 2 / 120 = rem

    375的设计稿计算方式:元素尺寸 / 120 = rem

以上面的几种设计稿为例,尤其是750的设计稿居多,大多数情况下根据元素的尺寸 / 120 ,这么难以计算的数字,还是交给插件来做吧。以VScode中的cssrem为例:

注意:配置完参数之后,重启软件

cssrem.png

四、flexible.js布局(推荐)

通过flexible.js实现了rem自适应,有了flexible.js,我们就不必再为移动端各种设备兼容烦恼。通过rem与px的换算,把设计稿从px转到rem。再也不用为各种设备横行而担忧。

rem是相对于根元素html,这样就意味着,我们只需要在根元素确定一个px字号,则可以来算出元素的宽高。1rem=16px(浏览器html的像素,可以设定这个基准值),假如浏览器的html设为64px,则下面的元素则1rem=64px来运算。

阿里团队开源的一个库。使用flexible.js轻松搞定各种不同的移动端设备兼容自适应问题。

  1. 删除viewport的meta标签,替换为下面的JS代码

    (function (win, lib) {
        var doc = win.document;
        var docEl = doc.documentElement;
        var metaEl = doc.querySelector('meta[name="viewport"]');
        var flexibleEl = doc.querySelector('meta[name="flexible"]');
        var dpr = 0;
        var scale = 0;
        var tid;
        var flexible = lib.flexible || (lib.flexible = {});
    
        if (metaEl) {
            //        console.warn('将根据已有的meta标签来设置缩放比例');
            var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
            if (match) {
                scale = parseFloat(match[1]);
                dpr = parseInt(1 / scale);
            }
        } else if (flexibleEl) {
            var content = flexibleEl.getAttribute('content');
            if (content) {
                var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
                var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
                if (initialDpr) {
                    dpr = parseFloat(initialDpr[1]);
                    scale = parseFloat((1 / dpr).toFixed(2));
                }
                if (maximumDpr) {
                    dpr = parseFloat(maximumDpr[1]);
                    scale = parseFloat((1 / dpr).toFixed(2));
                }
            }
        }
    
        if (!dpr && !scale) {
            var isAndroid = win.navigator.appVersion.match(/android/gi);
            var isIPhone = win.navigator.appVersion.match(/iphone/gi);
            var devicePixelRatio = win.devicePixelRatio;
            if (isIPhone) {
                // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
                if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
                    dpr = 3;
                } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
                    dpr = 2;
                } else {
                    dpr = 1;
                }
            } else {
                // 其他设备下,仍旧使用1倍的方案
                dpr = 1;
            }
            scale = 1 / dpr;
    
        }
    
        docEl.setAttribute('data-dpr', dpr);
        if (!metaEl) {
            metaEl = doc.createElement('meta');
            metaEl.setAttribute('name', 'viewport');
            metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
            if (docEl.firstElementChild) {
                docEl.firstElementChild.appendChild(metaEl);
            } else {
                var wrap = doc.createElement('div');
                wrap.appendChild(metaEl);
                doc.write(wrap.innerHTML);
            }
        }
    
        function refreshRem() {
            var width = docEl.getBoundingClientRect().width;
    
            if (width / dpr > 768) {
                width = 768 * dpr;
            }
            var rem = width / 7.5;
            docEl.style.fontSize = rem + 'px';
            flexible.rem = win.rem = rem;
        }
    
        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);
    
        if (doc.readyState === 'complete') {
            doc.body.style.fontSize = 12 * dpr + 'px';
        } else {
            doc.addEventListener('DOMContentLoaded', function (e) {
                doc.body.style.fontSize = 12 * dpr + 'px';
            }, false);
        }
    
        refreshRem();
    
        flexible.dpr = win.dpr = dpr;
        flexible.refreshRem = refreshRem;
        flexible.rem2px = function (d) {
            var val = parseFloat(d) * this.rem;
            if (typeof d === 'string' && d.match(/rem$/)) {
                val += 'px';
            }
            return val;
        }
        flexible.px2rem = function (d) {
            var val = parseFloat(d) / this.rem;
            if (typeof d === 'string' && d.match(/px$/)) {
                val += 'rem';
            }
            return val;
        }
    
    })(window, window['lib'] || (window['lib'] = {}));
    
    
  2. 以750设计稿为准,元素尺寸 / 100 = rem ; 以375设计稿为准,元素尺寸 * 2 / 100 = rem ,因为flexble中会再除以2,所以这里乘以2将其抵消。

参考博客1 前端开发博客


  1. 根字体大小:iPhone5s:12px iPhone6S:14px iPhone6P:16px

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

推荐阅读更多精彩内容

  • 方案一: 最新方案:(隆重推荐) 1、下载MateHandler.js,并引入页面2、head里加入 3、设置bo...
    晨光2016阅读 886评论 0 0
  • 移动端适配方案:1)viewport(scale=1/dpr)2)rem3)flex4)vm/vh一、什么是移动端...
    puxiaotaoc阅读 43,027评论 3 56
  • @description 该方法是用于移动端适配功能, 结合淘宝的适配方案flexible + rem 实现适配,...
    王小傲阅读 434评论 0 0
  • 手淘的rem适配js flex.js ;(function(win, lib) { var doc = win.d...
    尝了又尝阅读 373评论 0 0
  • 这是一篇“读书笔记”,原文是万维钢老师的专栏《精英日课》的一篇文章,与题目同名。 话不多说,直接开始! 万老师从四...
    小小Mark阅读 399评论 3 0