移动适配页面实践与总结

2017-09-21  本文已影响256人  Kaku_fe

布局

lib-flexible

这是手淘团队开源的一个基于viewport与rem单位的H5适配开源库,原理非常的简单,通过手机dpr动态设置viewport的缩放以及html的font-size来兼容不同尺寸屏幕下页面的效果。

在100分的项目中,我们没有采取他默认的缩放加rem的方式,强制定义缩放比例为1,只使用了rem方案来适应不同的手机。查看lib-flexible代码,发现只要手动设置了meta标签,就会按照自己的缩放比例进行计算。

// flexible源代码第11行,判断缩放的方式
var metaEl = doc.querySelector('meta[name="viewport"]');
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) {
        // .......
}

在使用lib-flexible的时候,由于水土不服等多种原因,遇到了很多坑,如果有要采用同样方案的小伙伴,可以重点注意一下。

image

100分没有采取此方案,而是采取了简单粗暴的雪碧图方案,下文细说。

image

上图中,因为父页面使用了缩放,导致iframe内容也同时做出了响应了缩放,但是因为iframe子页面无法设置font-size,因此显示非常奇怪。


$rem-baseline: 75px !default;
@function rem-separator($list) {
    @if function-exists("list-separator") == true {
        @return list-separator($list);
    }

    $test-list: ();
    @each $item in $list {
        $test-list: append($test-list, $item, space);
    }

    @return if($test-list == $list, space, comma);
}

@mixin rem-baseline($zoom: 100%) {
    font-size: $zoom / 16px * $rem-baseline;
}

@function rem-convert($to, $values...) {
    $result: ();
    $separator: rem-separator($values);
    @each $value in $values {
        @if type-of($value) == "number" and unit($value) == "rem" and $to == "px" {
            $result: append($result, $value / 1rem * $rem-baseline, $separator);
        } @else if type-of($value) == "number" and unit($value) == "px" and $to == "rem" {
            $result: append($result, $value / ($rem-baseline / 1rem), $separator);
        } @else if type-of($value) == "list" {
            $result: append($result, rem-convert($to, $value...), $separator);
        } @else {
            $result: append($result, $value, $separator);
        }
    }
    @return if(length($result) == 1, nth($result, 1), $result);
}

@function px2rem($values...) {
    @return rem-convert(rem, $values...);
}

@mixin px2rem($properties, $values...) {
    @if type-of($properties) == "map" {
        @each $property in map-keys($properties) {
            @include px2rem($property, map-get($properties, $property));
        }
    } @else {
        @each $property in $properties {
            #{$property}: rem-convert(rem, $values...);
        }
    }
}

// 使用方式
.login_box {
    @include px2rem(margin, 0 auto);
    @include px2rem(padding, 20px 0 15px);
}

刚才说到,100分项目采取了强制设置initial-scale=1的方式来按照视觉稿还原,这么做也有一些无法解决的问题。

    transform:scaleX(0.5)或transform:scaleY(0.5)

这个hack也只是为了视觉而做出的无奈之举,解决这个问题的关键在于去交流

flex + box-sizing

起初采用此方案时,担心flex布局的兼容性,特意把flex的大部分属性进行了一次测试,发现一切安好。
测试系统:IOS 8IOS`` 9android 4.2android 4.4android 6.0
有其他需求的话,可以自行用手机测试(只测试了常用的属性,欢迎提交其他属性测试)
测试地址

图片

雪碧图

为什么在100分项目中执迷于采用雪碧图方案呢,在图片方案选择中明明还有不少其他方案,如淘宝的每个图标就是一张大图的方案,图标采取base64方案在通过background-size缩放,字体图标方案。

说了这么多其他方式,说说100分采取的传统雪碧图方案,相对于传统雪碧图的繁琐。在100分项目中,采取的通过compass的方式进行动态生成,并且为了兼容retina屏幕,使用了2套不同的图片进行生成,在通过媒体查询的方式确定当前手机需要访问什么样的图片资源。在利用scss强大的mixin,完成自己想要的功能。
相关代码和项目结构如下:

    
//生成compass雪碧图    
@function generate-sprite($path){
    @return sprite-map($path, $spacing: 10px, $layout: vertical);
}
// 获取某一张图的background-position
@mixin sprite-background($name,$normal,$retina:null) {
    background-repeat: no-repeat;
    background-image: sprite-url($normal);
    background-position: sprite-position($normal, $name);
    height: image-height(sprite-file($normal, $name));
    width: image-width(sprite-file($normal, $name));

    // retina屏幕样式
    @if ($retina != null){
        @media (min--moz-device-pixel-ratio: 1.3),
        (-o-min-device-pixel-ratio: 2.6/2),
        (-webkit-min-device-pixel-ratio: 1.3),
        (min-device-pixel-ratio: 1.3),
        (min-resolution: 1.3dppx) {
            background-image: sprite-url($retina);
            background-position: 0 round(nth(sprite-position($retina, $name), 2) / 2);
            height: round(image-height(sprite-file($retina, $name)) / 2);
            width: round(image-width(sprite-file($retina, $name)) /2);
            $double-width: ceil(image-width(sprite-path($retina)) / 2);
            $auto-height: auto;
            @include background-size($double-width $auto-height);
        }
    }
}

//调用方式, 写起来非常的简单
/* 设置不同倍数的雪碧图*/
$sprites: generate-sprite("mobile/mob/member/login/icon1x/*.png");
$sprites-retina: generate-sprite("mobile/mob/member/login/icon2x/*.png");

.icon-logo {
    @include sprite-background(logo, $sprites, $sprites-retina);
}

项目结构:

image

根据不同dpr取不同的图片

生成的图片样式如下:

图片

觉得不好看浪费空间的话可以设置排列方式。反正不用自己量,who care?

该方案灵活简单,雪碧图交给compass生成,增加修改删除测量都是全自动化的,非常的易于使用以及后期维护,同时也兼容了高清图的需求。有一个缺点就是不能100%还原视觉稿,在任何手机下看到的图标大小都是固定的。具体采取以上什么方式,还是要根据当前开发环境进行分析。

字体

安利一个简单的字体图标生成网站,可以自己上传矢量图生成图标,也可以使用网站提供的图标,贴心的是还会生成该图标使用的css。地址

总结

总的来说,移动适配还不存在万能的技术方案,无论是字体、间距、布局、图片都还需要根据自己项目的环境以及复杂度来进行选型。

参考资料

  1. 使用Flexible实现手淘H5页面的终端适配
  2. 使用Sass和Compass制作雪碧图
上一篇 下一篇

猜你喜欢

热点阅读