我们都知道,在HTML中引入CSS的方式有<link>
标签和<style>
标签两种,下面结合webpack
来实现以下功能:
- 将
CSS
通过link
标签引入; - 将
CSS
放在style
标签里; - 动态加载和卸载
CSS
; - 页面加载CSS前的transform。
安转需要用到的loader:
yarn add css-loader style-loader file-loader -D
<link>
标签引入
CSS通过通过link标签引用css文件,这需要借助file-loader
来将css
处理为文件。具体配置如下:
const path = require('path');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader/url'
},
{
loader: 'file-loader'
}
]
}
]
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
入口文件index.js
const isClick = false;
// 点击页面上的按钮后,页面会引入相应的样式
document.querySelector('#btn').addEventListener('click', () => {
if (!isClick) {
import('./style/index.css');
}
});
2
3
4
5
6
7
点击加载前:
点击加载后:
从上图可以看出,对应的css被插入了相应的link
标签中。
<style>
标签里
CSS放在通常来说,css
放在style
标签里可以减少网络请求次数,缩短响应时间。需要注意的是,在老式IE
浏览器中,对style
标签的数量是有要求的。具体配置如下:
const path = require('path');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
options: {
singleton: true // 处理为单个style标签
}
},
{
loader: 'css-loader'
}
]
}
]
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
点击加载前:
点击加载后:
动态卸载和加载CSS
style-loader
为css
对象提供了use()和unuse()
两个方法,借助这两个方法,可以方便快捷地加载和卸载css
样式。具体配置如下:
const path = require('path');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader/useable',
},
{
loader: 'css-loader'
}
]
}
]
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
入口文件:
import style from './style/index.css';
let flag = false;
setInterval(() => {
// use和unuse是style上的方法
if (flag) {
style.unuse();
}
else {
style.use();
}
flag = !flag;
}, 1000);
2
3
4
5
6
7
8
9
10
11
12
样式不会添加在import/require()
上,而是在调用use/ref
时添加,在调用unuse/unref
时删除。
页面加载css前的transform
对于css
的transform
,简单来说:在加载css
样式前,可以更改css
。这样,方便开发者根据业务需要,对css
进行相关处理。
需要对style-loader
增加options.transform
属性,值为指定的js
文件,具体的webpack.config.js
配置如下:
const path = require('path');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
publicPath: __dirname + '/dist/', // js引用路径或者CDN地址
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
options: {
transform: './src/transform.js'
}
},
{
loader: 'css-loader'
}
]
}
]
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
transform.js:
module.exports = function (css) { // 传入的参数是css字符串本身
console.log(css);
const transformed = css.replace('yellow', 'green')
// 如果屏幕宽度小于800,则替换背景颜色
return window.innerWidth < 800 ? transformed : css;
}
2
3
4
5
6
在index.js中引入css文件即可:
import style from './style/index.css';
打开控制台,如下图所示,当屏幕宽度小于800
时候,css
中的yellow
已经被替换为了green
。
需要注意的是:transform是在css
引入前根据需要修改,所以之后是不会改变的。所以上方代码不是响应式,当把屏幕宽度拉长到大于800
时候,依旧是绿色。重新刷新页面,才会是黄色。
css打包处理
yarn add style-loader css-loader -D
// index.js
import avatar from './avatar.jpg';
import './index.css';
const img = new Image();
img.src = avatar;
img.classList.add('avatar');
document.body.appendChild(img);
2
3
4
5
6
7
8
9
// index.css
@import './avatar.css';
2
// avatar.css
.avatar {
width: 100px;
height: 100px;
border-radius: 5px;
}
2
3
4
5
6
在上述代码中,在index.js中引入了index.css,在index.css中通过@import语法引入了avatar.css。页面展示效果如下:
从上面例子中,可以知道:
- css-loader:用于加载
.css
文件,并且转换成commonjs对象。会分析多个css文件之间的关系(@import语法等),把多个css文件合并成一段css代码。 - style-loader:将合并后的css通过style标签的形式插入到html文件head标签中。
less打包处理
yarn add less less-loader style-loader css-loader -D
# 样式添加前缀
yarn add postcss-loader autoprefixer -D
2
3
// index.js
import avatar from './avatar.jpg';
import './index.less';
const img = new Image();
img.src = avatar;
img.classList.add('avatar');
document.body.appendChild(img);
2
3
4
5
6
7
8
9
// index.less
.avatar {
width: 100px;
height: 100px;
border-radius: 5px;
transform: translate(100px, 200px);
}
2
3
4
5
6
7
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
};
2
3
4
5
6
{
test: /\.less$/,
// less-loader会将less语法转化为css语法
// css-loader会分析多个css文件之间的关系(@import语法等),把多个css文件合并成一段css代码
// style-loader将合并后的css插入到html文件的style标签中
use: [
'style-loader',
'css-loader',
'less-loader',
'postcss-loader'
]
}
2
3
4
5
6
7
8
9
10
11
12
需要注意:autoprefixer是css的后置处理器,是在css文件打包完成后再对css文件代码添加浏览器前缀。
autoprefixer对@import方式引用css文件无效的解决方案
具体解决方案是配置importLoaders,具体参考。
// index.less
@import './avatar.less';
2
// avatar.less
.avatar {
width: 100px;
height: 100px;
border-radius: 5px;
transform: translate(100px, 200px);
}
2
3
4
5
6
7
我们在index.js中引入了index.less,又在index.less中通过@import
语法引入了avatar.less。
需要注意:在index.js中引入了index.less,index.less文件的loader处理顺序为:less-loader->postcss-loader->css-loader->style-loader。
而对于avatar.less,其loader处理顺序为:css-loader->style-loader。默认并不会被less-loader和postcss-loader处理。这是因为importLoaders默认值为0。我们在index.js中引入了index.less,又在index.less中引入了avatar.less(@import './avatar.less';
)。如果不配置importLoaders: 2
,那么avatar.less将不会被postcss-loader和less-loader处理。如果css-loader后面只有postcss-loader,则设置importLoaders: 1
。
{
test: /\.less$/,
// less-loader会将less语法转化为css语法
// css-loader会分析多个css文件之间的关系(@import语法等),把多个css文件合并成一段css代码
// style-loader将合并后的css插入到html文件的style标签中
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'postcss-loader',
'less-loader'
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
此外还需要注意:postcss-loader必须在css-loader之后,less-loader之前,否则前缀也添加不成功。
CSS Module(CSS模块化)
CSS模块化主要用来解决不同文件样式的冲突问题,避免样式之间的相互影响。
// createAvatar.js
import avatar from './avatar.jpg';
function createAvatar() {
const img = new Image();
img.src = avatar;
// 给image标签添加一个avatar的类
img.classList.add('avatar');
document.body.appendChild(img);
}
export default createAvatar;
2
3
4
5
6
7
8
9
10
11
12
// index.js
import avatar from './avatar.jpg';
import './index.less';
import createAvatar from './createAvatar';
createAvatar(); // 每运行一次,就会在页面中添加一张图片
const img = new Image();
img.src = avatar;
img.classList.add('avatar');
document.body.appendChild(img);
2
3
4
5
6
7
8
9
10
11
例如上述代码:我们在index.js中创建了一个Image对象并给其添加了一个avatar的类。与此同时,在createAvatar.js中也创建了一个Image对象并给其添加了一个avatar的类。在index.less中给avatar的类添加了一些样式,这个样式是全局的,会同时影响到index.js和createAvatar.js中两个图片的样式。结果如下:
但是上图中的结果有时候并不是我们所期望的,如何才能让avatar的类的样式称为一个局部样式呢?具体配置如下:
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: true // 开启css模块化打包,使得引入的样式文件仅仅作用于当前的js文件,不会对其他文件中同名类造成影响
}
}
2
3
4
5
6
7
import avatar from './avatar.jpg';
import style from './index.less'; // index.less引入方式改变
import createAvatar from './createAvatar';
createAvatar(); // 每运行一次,就会在页面中添加一张图片
const img = new Image();
img.src = avatar;
img.classList.add(style.avatar); // 添加类的方式发生改变
document.body.appendChild(img);
2
3
4
5
6
7
8
9
10
重新打包,结果如下:
从上图结果可以看出:createAvatar.js中的图片样式并没有受到影响,符合预期。如果想让其也拥有对应的样式,也需要在createAvatar.js进行如下配置:
import avatar from './avatar.jpg';
import style from './index.less'; // 引入index.less
function createAvatar() {
const img = new Image();
img.src = avatar;
// 给image标签添加一个avatar的类
img.classList.add(style.avatar); // 基于style添加avatar类
document.body.appendChild(img);
}
export default createAvatar;
2
3
4
5
6
7
8
9
10
11
12
sass打包处理
配置类似于less,具体参考。
样式公共变量的提取
yarn add style-resources-loader -D
mini-css-extract-plugin
提取样式文件
style-loader
和MiniCssExtractPlugin.loader
两者作用是冲突的,style-loader
用于将样式代码插入到<head>
标签中,MiniCssExtractPlugin.loader
用于将样式文件提取到单独的css文件中。
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
{
test: /\.less$/,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css' // 设置css文件指纹
})
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
移动端css适配 px自动转换成rem
说到响应式布局,我们一般想到的可能是CSS媒体查询,虽然媒体查询可以实现响应式布局,但是该方案的缺陷是:需要针对不同的屏幕写多套适配样式代码。
yarn add px2rem-loader -D
// lib-flexible作用是根据页面的分辨率动态计算根元素的font-size
yarn add lib-flexible
2
3
W3C对rem的定义是:font-size of the root element。 rem是相对单位,px是绝对单位。 原理:页面渲染时计算根元素的font-size值,可以使用手淘的lib-flexible库。
{
test: /\.less$/,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
'postcss-loader',
{
loader: 'px2rem-loader',
options: {
// 适用于750的设计稿
remUnit: 75, // 1rem等于75px
remPrecision: 8 // px转为rem时小数点的位数
}
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
lib-flexible
引入我们可以在<head>
标签中直接将lib-flexible
的代码通过<script>
标签的形式引入。引入之后,页面根元素的font-size值会根据当前页面的分辨率进行改变。