《使用 Modernizr 对浏览器进行 HTML5 和 CSS3 功能检测》

2016-10-29 10:23:19 +08:00
 toloric

原文地址: https://github.com/hugojing/web-lessons/blob/master/lesson4/README.md

目标

创建 lesson4 项目,引入 Modernizr CLI 。

使用 Modernizr CLI 生成自己需要的 Modernizr 包。

使用 Modernizr 进行功能特性检测,在浏览器不支持某一特性时应用相应样式和逻辑。

当在浏览器中访问 http://localhost:8080 时,输出页面。

知识点

  1. 学习使用 Yarn(新的 npm CLI client )
  2. 学习使用 html-webpack-plugin 自动生成 HTML 文件
  3. 学习 Modernizr CLI 的用法
  4. 学习使用 url-loader 与 file-loader 实现音频、图像、视频等模块的加载
  5. 学习 Modernizr 的用法

课程内容

为什么使用 Modernizr

在进行前端开发时,想用一些浏览器的新特性,却不确定用户的浏览器是否支持。

这时便需要进行手工检测来判断,进而给出不同的处理。

使用 Modernizr ,可以方便地进行特性检测。从这些手工检测中解放出来,腾出力气来做好优雅降级。

而且 Modernizr 可订制化,列出一个 JSON 格式的特性清单,便可以打出一个你所需要的最小的包。

Modernizr 实战

html-webpack-plugin

上节课有用到 Webpack 的插件: extract-text-webpack-plugin ,这次首先介绍一个新的小插件: html-webpack-plugin. 主要功能是自动生成 HTML 文件。

使用 Yarn (新的 npm CLI client )初始化项目:

$ yarn init  #替代原 npm init

沿用上一节课的项目结构,创建需要用到的文件目录。

添加 html-webpack-plugin 到项目:

$ yarn add --dev html-webpack-plugin #替代原 npm i --save-dev html-webpack-plugin

添加 Webpack config 如下:

const HtmlWebpackPlugin = require('html-webpack-plugin')
// ...
plugins: [
    // ...
    new HtmlWebpackPlugin({
        title: 'Modernizr 实战',
        template: path.resolve(SRC_PATH, 'index.html')
    }),
    // ...
]

这段配置是说以 src/index.html 为模板,创建一个 title 为 Modernizr 实战 的 html 文件,并输出到 output 输出目录。如果一同输出的有 JS 和 CSS 文件,它会自己写好 script srclink 到所输出的 html 文件中。

新增 src/index.html 文件,编写如下:

<!DOCTYPE html>
<html class="no-audio">
<head>
    <title>Modernizr 实战</title>
</head>
<body>
    <div id="music">
        <p>The End Of The World</p>
    </div>
</body>
</html>

这样一来,打包时就会自动生成符合需要的 dist/index.html 文件。

Modernizr CLI

添加 Modernizr CLI 到项目中:

$ yarn add modernizr  #替代原 npm i modernizr --save

新增 modernizr CLI 的 generate 命令到 package.json ,可根据指定的 config json 文件生成自订制的 modernizr.js 文件。

"scripts": {
    "modernizr": "modernizr -c node_modules/modernizr/lib/config-all.json"
}

执行 modernizr CLI 的 generate 命令,生成 modernizr.js 文件:

$ yarn run modernizr #替代原 npm run modernizr
# Modernizr build saved to xxxxx/lesson4/modernizr.js

为了代码中方便使用,可在 webpack.config.js 的 config.resolve.alias 中配置别名:

alias: {
    'modernizr': path.resolve(ROOT_PATH, 'modernizr.js')
}

url-loader && file-loader

在 src/main.js 文件中编写代码,引入需要加载的一些前端模块( CSS 、 MP3 ):

import 'normalize.css' // 不是合法的 ES2015 Modules 写法,由 babel 转为 `require('normalize.css')`,再由 Webpack 实现 CSS 加载
import './main.css' // 同上,会转为 `require('normalize.css')
import musicUrl from './The_End_Of_The_World.mp3' // 同上,会转为 `const musicUrl = require('./The_End_Of_The_World.mp3')`

代码中的 import(require) 都是 Webpack 接管的,所以 The_End_Of_The_World.mp3 这个音频文件得让 Webpack 来加载它。这就要用到两个新的 loader: url-loaderfile-loader .

添加到项目中:

$ yarn add --dev url-loader file-loader

然后添加 Webpack config:

module: {
    loaders: [
        // ...
        {
            test: /\.mp3$/,
            loader: 'url?limit=1024&name=[hash].[ext]'
        }
    ]
},

url?limit=1024&name=[hash].[ext] 意思是使用 url-loader 来加载,小于 1024k 的打成 Base64 ,大于的复制文件到 output 输出目录、并命名为 [hash].[ext] 的格式。

这样, JS 中 import(require) 一些 mp3 文件的时候, Webpack 就可以按照配置策略进行加载,其返回值为 Base64 值或者 文件的 url.

可以验证一下,console.log(musicUrl) 会得到类似 /205cc6e697917a94362ed6ed99febe71.mp3 的结果,即为加载成功。

Modernizr

继续编辑 src/main.js , 应该引入我们生成的自订制 modernizr 文件了。

查看 modernizr.js 文件,可以发现这个模块既不是 AMD 、 CMD 、 CommonJS 模块,也不是 ES2015 模块,更不是 UMD 模块,而是传统的 globals 库,将 modernizr 挂载在 window 上。(了解不同的模块类别,推荐阅读:关于 AMD,CMD,CommonJS 及 UMD 规范识别库的类型

由于 modernizr.js 文件是传统的 globals 库,所以执行所加载的 modernizr.js 即可,写法如下:

import 'modernizr' // modernizr 即为 ./modernizr.js

注意,这虽是合法的 ES2015 Modules 写法,但实现上依然是由 babel 转为 require('modernizr'),再由 Webpack 实现 JS 加载的。

这样, window.Modernizr 就可用了。

打包一下:

$ yarn run build #替代原 npm run build

然后启动服务:

$ yarn run serve #替代原 npm run serve

打开浏览器查看开发者工具,查看 Elements :

可见,直接加载执行 Modernizr ,它不仅挂载了 window.Modernizr, 还依照检测结果给 <html> 标签写入了对应的 CSS class 名,例如 cookies cors crypto cssall no-backdropfilter audio 等。这样,开发者就可以写两种 CSS 样式(比如 .audio body.no-audio body),以应对两种可能的情况(某一功能的有或无)。

于是,这样编写 src/main.css :

html, body {
    width: 100%;
    height: 100%;
}
body {
    display: flex;
    justify-content: center;
    align-items: center;
    font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
}
.no-audio body {
    color: #fff;
    background-color: #000;
}
.audio body {
    color: #000;
    background-color: whitesmoke;
}
.no-audio #music {
    width: 600px;
    text-align: left;
}
.audio #music {
    width: 300px;
    text-align: center;
}

JS 中也可以获取检测结果,例如:

Modernizr.audio // turn or false

于是,这样编写 src/main.js :

//...
const container = document.getElementById('music')

if (Modernizr.audio) {  // Modernizr 即是 window.Modernizr
    const music = new Audio(musicUrl)
    music.controls = 'controls'
    container.appendChild(music)
} else {
    const musicIntro = document.createElement('p')
    musicIntro.textContent = '史琪特·戴维丝 1963 年演唱的《 The End Of The World 》(世界末日)被评为当年最受欢迎的歌曲,被无数人翻唱过,但无人能及她原唱的魅力,这首歌也是她唯一的传世之作。'
    container.appendChild(musicIntro)
}

别忘了打包和启动服务。

最终效果

在支持 HTML5 Audio 的浏览器中:

在不支持 HTML5 Audio 的浏览器中:

感谢 Modernizr ,给了我们一个更优雅的检测浏览器新特性的方式。

2588 次点击
所在节点    程序员
2 条回复
neoblackcap
2016-10-29 23:28:32 +08:00
不是我吹毛求疵。都多少年了,用 Modernizr 来进行特性检测以便编写兼容性更好的网页这不是前端开发的常识吗?我记得当 Chrome 刚出来那几年间,还得兼容 IE6,7,8 的时候,就已经推崇用 Modernizr 编写现代化的网页。
toloric
2016-10-30 15:02:45 +08:00
@neoblackcap 对呀

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/316376

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX