H5-移动端响应式布局vw,vh替代方案(可灵活搭配)

转载请注明出处:
http://blog.csdn.net/lishihong108/article/details/52290021

#前言
  大家都知道当下,手机屏幕大小多种多样,而且即使同样大小的size,每个手机的设备像素比还不一样。当我们选用html5来开发移动应用的时候,有没有一种合适的方案来完美的适配到所有的屏幕呢?
对移动端接触不多的,可以先了解下移动端的单位、viewport的概念。这里也不再赘述,通过以下连接了解。
1.http://www.cnblogs.com/2050/p/3877280.html  2.http://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201509/376281.shtml
#经典方式

先简要的介绍下现在多数开发者使用的方式,由于这些方式大家或多或少都使用过,而且网上也有非常详细的教程,我就不再重复造轮子,只是简单的列举下。
1.css3 @media

http://www.w3cways.com/1180.html
这种方式适配起来良好,但是还是无法兼容所有的屏幕,而且各个样式都用@media写几套,很麻烦,也不利于后期扩展维护。

2.px+百分百+flex

像目前接触过的一些前端框架ionic、bootstrap、amaze、mui等,对于已经确定无需随屏幕变化的元素,一般用px固定大小,对于宽度的处理用百分比或flex来灵活处理。

这种方式处理起来,大体还好,但是对于小屏iphone5s和大屏iphone6 plus,某些布局只能折中处理。最大的缺陷是, 一些布局无法通过百分比或者flex设置的时候,布局的样式和字体的大小都无法随屏幕的变化而响应式变化。

3.对于viewport的处理

  • 固定高度,宽度自适应

  • 固定宽度,动态生成viewport
var fixScreen = function() {
    var metaEl = doc.querySelector('meta[name="viewport"]'),
        metaCtt = metaEl ? metaEl.content : '',
        matchScale = metaCtt.match(/initial\-scale=([\d\.]+)/),
        matchWidth = metaCtt.match(/width=([^,\s]+)/);
    if ( metaEl && !matchScale && ( matchWidth && matchWidth[1] != 'device-width') ) {
        var width = parseInt(matchWidth[1]),
            iw = win.innerWidth || width,
            ow = win.outerWidth || iw,
            sw = win.screen.width || iw,
            saw = win.screen.availWidth || iw,
            ih = win.innerHeight || width,
            oh = win.outerHeight || ih,
            ish = win.screen.height || ih,
            sah = win.screen.availHeight || ih,
            w = Math.min(iw,ow,sw,saw,ih,oh,ish,sah),
            scale = w / width;
        if ( ratio < 1) {
            metaEl.content += ',initial-scale=' + ratio + ',maximum-scale=' + ratio + ', minimum-scale=' + scale;
        }
    }
}

详细处理方式请看以下链接,
https://github.com/riskers/blog/issues/18
http://html-js.com/article/MobileWeb

4.根节点固定fontSize,布局单位用rem
动态生成根节点的fontSize:


页面上字体和布局单位都采用rem,该方式基本可以适应大部分的布局,使用过程中发现一个缺陷,由于,fontSize是根据屏幕的宽度自动生成的,那么在横屏的时候,由于设置的元素的高度rem是基于宽度计算的fontSize来的,fontSize会变大,就会造成元素的高度被拉的很高。我们希望是这样的:**布局元素的宽度始终基于屏幕宽度百分比变化,布局元素的高度始终基于屏幕高度百分比变化。**有没有方法实现呢?答案是有,看下面的一种方式。

5.css3百分比单位vw,vh
1vw等于可视区宽度(屏幕的可视区域即布局区域)的百分之一,1vh等于可视区高度的百分之一

表示当前元素在任何屏幕下都是div占当前屏幕宽度的20%,当前高度的40%。刚好满足我们的需求,但是你会发现很少有有开发者采用这个单位。很不幸,这个单位有部分浏览器和手机并不支持。我们有没有替代的解决方案呢?就是下面今天打算重点讲的一个方案。

#angularjs指令计算百分方式
由于vw,vh不被完全支持的原因,有了这个替代的解决方案,目前项目中正在使用,效果很不错。
先上代码:

angular.module('starter.directives', [])
.directive('adaptive',function(){
    function link($scope, element, attrs) { 
        var dom=element[0]; 
        var wPercent = attrs.w;
        var hPercent = attrs.h;
        var pPercent = attrs.p ? attrs.p.split(",") : null;
        var mPercent = attrs.m ? attrs.m.split(",") : null;
        var screenW = Math.min(document.documentElement.clientWidth,window.innerWidth);
        var screenH = Math.min(document.documentElement.clientHeight,window.innerHeight);  
        setWAndH();
        function setWAndH(){   
            if(wPercent){ //宽度 
                dom.style.width=whatUnitValue(wPercent)+"px";
            }
            if(hPercent){  //高度
                dom.style.height=whatUnitValue(hPercent)+"px";
            }
            if(pPercent){//padding
                dom.style.paddingTop=whatUnitValue(pPercent[0])+"px";
                dom.style.paddingRight=whatUnitValue(pPercent[1])+"px";
                dom.style.paddingBottom=whatUnitValue(pPercent[2])+"px";
                dom.style.paddingLeft=whatUnitValue(pPercent[3])+"px";
            }
            if(mPercent){//margin
                dom.style.marginTop=whatUnitValue(mPercent[0])+"px";
                dom.style.marginRight=whatUnitValue(mPercent[1])+"px";
                dom.style.marginBottom=whatUnitValue(mPercent[2])+"px";
                dom.style.marginLeft=whatUnitValue(mPercent[3])+"px";
            }
        } 
        function whatUnitValue(value){
        	if(value.indexOf("px")!=-1){//原始单位
        		return parseFloat(value);
        	}
        	if(value.indexOf("vw")!=-1){//占比屏幕宽度
        		return parseFloat(value)/100*screenW;
        	}
        	if(value.indexOf("vh")!=-1){//占比屏幕高度
        		return parseFloat(value)/100*screenH;
        	}
        	return parseFloat(value)/100*screenW;//默认占比屏幕宽度
        } 
        window.function(){
        	screenW = Math.min(document.documentElement.clientWidth,window.innerWidth);
        	screenH = Math.min(document.documentElement.clientHeight,window.innerHeight);  
            setWAndH();
        };
    } 
    return {
        restrict: 'A',
        link: link 
    };
})

使用:

第一个div,宽度始终占屏幕宽度的20%,高度占屏幕高度的10%;第三个div的margin上、右、下、左分别占屏幕高度10%,宽度10%,10个像素,屏幕宽度10%。可以看到,完全可以和px灵活搭配。vw就表示是占屏幕的宽度,vh表示是占屏幕的高度。

代码很简单,就不做过多解释。用html5的data属性添加我们自己的数据,通过指令封装。在指令里面拿到对应的属性的值,乘屏幕的宽高度,算出实际值,再设置到元素上面。实际上就是一个变相的vw、vh的实现。然后有一个监听屏幕大小变化的函数,比如切屏时候,元素的位置和大小也会随着变化。这种方式非常灵活,不影响你使用其他的方案,你可以单独对某一个、某几个有特殊需求的元素进行处理都可以。
  有什么好的建议或其他方案欢迎留言讨论。说一点自己项目中使用的建议:确定要用固定px大小的,尽量用定值px,比如标题栏高度等;宽度布局时候尽量使用百分比或flex或者用指令实现的这种方式;高度需要自适应时候用指令这种方式非常方便;在处理字体大小的时候,如果产品没有特殊要求,可不对字做响应式处理,有特殊要求可以采用上面的rem的方式。

你可能感兴趣的:(ionic)