一种让 IE6/7/8 支持 media query 响应式设计的方法

在不一样的浏览器宽度下使用不一样的 CSS 声明,常见的方案是使用 media query,但这个方案不支持 IE9 如下浏览器。css

国外比较流行的 UI 框架 bootstrap v3 版本中使用 media query 技术实现了栅格布局 ,但要兼容 IE8 的话,( IE6/7 没有中国占比那么高,因此不用兼容)须要引入 Respond.js 的方案。html

 

该方案的原理分如下 4 步:前端

一、在样式 link 以后,载入 respond.js ,该脚本会获取在他以前出现的 link 节点到一个数组css3

二、发送 ajax 请求从新获取 link 数组中 css 文件文本内容git

三、经过分析文本内容中 @media 类声明,从新计算并应用相关样式github

四、在 window.resize 时,触发第 3 步逻辑ajax

 

这里的问题点有两个:gulp

一、第 2 步是否会形成重复的请求消耗?bootstrap

二、若是 css 静态资源存放域名与当前页面不一样,势必会遇到 js 同源策略的限制,如何突破跨域问题?跨域

 

问题 1 比较好回答,基本包括 IE 在内的全部浏览器都会对 GET 请求进行缓存,因为在第 1 步的时候浏览器已经请求过全部的 CSS 文件,所以在第 2 步 ajax 的时候会直接使用本地缓存,不会形成性能损耗。但因为需引用一个 respond.proxy.gif 来 hack IE 路径问题,可能会形成一个额外的请求损耗。

 

问题 2 确实存在,Respond.js 经过 iframe proxy file 的方案突破了同源策略,详细的讲解可参考这篇文章《Respond.js让IE6-8支持CSS3 Media Query》或自行百度相关JS跨域知识。但在 Respond.js 场景中会形成两个问题:

一、因为 iframe 的建立是异步的,respond.proxy.js 没法阻塞渲染,势必会形成页面样式的闪动(先应用了默认样式,第 3 步样式分析完毕后,又从新应用一次样式)

二、因为 iframe proxy file 在 css 资源请求完成时的事件没法主动回调(子iframe没法访问非同源父窗口),而是经过父窗口的一个定时器不断读取子窗口 window.name 值来实现被动通信,所以样式的渲染就存在进一步的延迟。

 

若是使用场景没法接收问题 2 所带来的负面影响(有情怀的前端工程师都会把静态资源部署到一个独立域名,以提高网页性能,并且也没法接受页面出现明显的重绘这种体验损失),则须要考虑其余方案(另外 Respond.js 项目做者已经有几年没有维护了,部分BUG还没修复 )。本文就此问题发散出一个基于 SASS + JS 的解决方案,以供参考。思路以下:

 

一、一般屏幕的分辨率宽度是符合必定规范的,而PC端网站栅格布局的常见宽度是能够穷举的:1024px、1280px、1440px、1600px、 1920px

二、在样式中,针对不一样的浏览器宽度,咱们能够复写多条样式规则,例如 body{} 、.w1280px body{} 、.w1440px body{},达到个性化的目的

三、当 window.resize 时,动态的在 html 节点上改变预设好的宽度 className ,例如宽度 width = 1620px 时,知足 width > 1600px && width < 1920px ,所以 html.classList.add('w1600px')

 

以上方法十分直观,IE6/7/8 使用以上方案,其余支持 media query 的浏览器则使用 @media only screen and (min-width: 1620px)  的 css 样式方案。对于样式维护性的问题(写一大坨 @media 和 .w1440px body 之类的相一样式确定不利于维护),咱们经过 SASS mixin 来解决,具体代码参考如下样式:

 

@mixin mediaWidth($min-width: 1024px, $max-width: null) {
    $widthSet: (1024px, 1280px, 1440px, 1600px, 1920px);
    $selector: ();

    @if $max-width {
        @media only screen and (min-width: $min-width) and (max-width: $max-width){ 
            @content; 
        }
    } @else {
        @media only screen and (min-width: $min-width) {
            @content; 
        }
    }

    @each $item in $widthSet {
        @if $max-width {
            @if $item >= $min-width and $item < $max-width {
                $selector: append($selector, unquote('.w#{$item} &'), 'comma');
            }
        } @else {
            @if $item >= $min-width{
                $selector: append($selector, unquote('.w#{$item} &'), 'comma');
            }
        }
    }

    #{$selector}{
        @content;
    }

}

body{
    width: 1024px;
    background-color: red;

    @include mediaWidth(1024px) {
        width: 1024px;
        background-color: orange;
    }

    @include mediaWidth(1280px, 1440px) {
        width: 1280px;
        background-color: green;
    }

    @include mediaWidth(1600px) {
        width: 1600px;
        background-color: blue;
    }

}

 

以上 SASS 编译以后的 CSS 为:

 

body {
    width: 1024px;
    background-color: red;
}
@media only screen and (min-width: 1024px) {
    body {
        width: 1024px;
        background-color: orange;
   }
}
.w1024px body, .w1280px body, .w1440px body, .w1600px body, .w1920px body {
    width: 1024px;
    background-color: orange;
}
@media only screen and (min-width: 1280px) and (max-width: 1440px) {
    body {
        width: 1280px;
        background-color: green;
   }
}
.w1280px body {
    width: 1280px;
    background-color: green;
}
@media only screen and (min-width: 1600px) {
    body {
        width: 1600px;
        background-color: blue;
   }
}
.w1600px body, .w1920px body {
    width: 1600px;
    background-color: blue;
}

 

问题一:若是项目中没用到 SASS 怎么办?

从实际项目经验来看,SASS 的引入能够大幅提升样式文件的维护性,并且不会对前端项目流程带来任何影响,由于你能够直接用编辑器的编译工具在保存文件时同步编译出 CSS 文件,例如 sublime text 的 sass build 和 build on save 插件,更不用说 sass 命令行、compass、grunt、gulp 之类的工具了。

 

问题二:若是不会 SASS 怎么办?

学就是了,看看这个就知道有多简单了《SASS用法指南》。

 

以上代码示例,参看此 demo:http://yekai.net/demo/ie-media-query.html

相关文章
相关标签/搜索