Stylus系列——webpack-spritesmith配合stylus使用示例

大卫

一、前言

基于Webpack的CSS Sprites实现方案,若是直接在html中调用雪碧图图标已经很方便,但是实际开发过程可能遇到需要在伪元素中使用雪碧图,或者需要hover切换另一个图标,这种情况下就无法在css中直接调用图标类名。这时,就需要css预处理器,当然不限于stylus,less、sass都是可以的,本文介绍stylus方案。

二、项目配置

1. 目录结构预览

+ node_modules
+ src               // 开发目录
    + css
        - icon.styl // webpack-spritesmith生成
        - index.styl
    + images
        - icon.png  // webpack-spritesmith生成
        + icon
            ..png
            ..png
    + js
        + main.js
+ dist              // 代码产出目录
    – index.html
    + js
        - main.js
    + css
        - index.css
    + images
        - icon.png
– package.json
– package-lock.json
- postcss.config.js
– webpack.config.js

2. 初始化项目

npm init

3. package.json

{
  "name": "cwwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack --mode development"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^9.1.2",
    "clean-webpack-plugin": "^1.0.0",
    "css-loader": "^1.0.0",
    "cssnano": "^4.0.5",
    "file-loader": "^1.1.11",
    "postcss-loader": "^3.0.0",
    "stylus": "^0.54.5",
    "url-loader": "^1.1.1",
    "webpack": "^4.17.0",
    "webpack-cli": "^3.1.2",
    "webpack-spritesmith": "^0.5.4"
  },
  "dependencies": {
    "mini-css-extract-plugin": "^0.4.1",
    "stylus-loader": "^3.0.2"
  }
}

4. 安装相关modules

npm install

5. webpack.config.js

var path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');
const SpritesmithPlugin = require('webpack-spritesmith');

var templateFunctionStylPC = function(data) {
    var sharedRem = '.ico\n    display: inline-block\n    background-image: url("I")\n'
        .replace('I', data.sprites[0].image);

    var perSpriteRem = data.sprites.map(function(sprite) {
        return '.ico-N\n    width: Wpx\n    height: Hpx\n    background-position: Xpx Ypx'
            .replace('N', sprite.name.replace(/_/g, '-'))
            .replace('W', sprite.width)
            .replace('H', sprite.height)
            .replace('X', sprite.offset_x)
            .replace('Y', sprite.offset_y);
    }).join('\n');

    return sharedRem + '\n' + perSpriteRem;
};

var templateFunctionStylMobile = function(data) {
    var sharedRem = '.ico\n    display: inline-block\n    background-image: url(I)\n    background-size: Drem Hrem'
        .replace('I', data.sprites[0].image)
        .replace('D', data.sprites[0].total_width / 100)
        .replace('H', data.sprites[0].total_height / 100);

    var perSpriteRem = data.sprites.map(function(sprite) {
        return '.ico-N\n    width: Wrem\n    height: Hrem\n    background-position: Xrem Yrem'
            .replace('N', sprite.name.replace(/_/g, '-'))
            .replace('W', sprite.width / 100)
            .replace('H', sprite.height / 100)
            .replace('X', sprite.offset_x / 100)
            .replace('Y', sprite.offset_y / 100);
    }).join('\n');

    return sharedRem + '\n' + perSpriteRem;
};

module.exports = {
    entry: __dirname + "/src/js/main.js",   //唯一入口文件
    output: {
        path: __dirname + "/dist/js",       //打包后的文件存放的地方
        filename: "main.js"                 //打包后输出文件的文件名
    },
    watch: false,                           //开启自动编译
    module: {
        rules: [
            {
                test: /\.styl$/,
                use: [{
                    loader: MiniCssExtractPlugin.loader
                }, {
                    loader: "css-loader"
                }, {
                    loader: "postcss-loader"
                }, {
                    loader: "stylus-loader"
                }]
            },
            {
                test: /\.(png|svg|jp?g|gif)$/,
                loader: 'url-loader',
                options: {
                    limit: 8192,            //大于 1KB = 1024B = 8192字节 的图片正常打包,小于8192字节的图片以base64的方式引用
                    name: '../images/[name].[ext]'
                }
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(
            ['dist/css', 'dist/images'],    //打包前需要清除的文件夹
            {
                root: __dirname,            //根目录
                verbose: true,              //开启在控制台输出信息
                dry: true                   //关闭删除文件
            }
        ),
        new SpritesmithPlugin({
            src: {
                cwd: path.resolve(__dirname, 'src/images/icon'),
                glob: '*.png'
            },
            target: {
                image: path.resolve(__dirname, 'src/images/icon.png'),
                css: [
                    [path.resolve(__dirname, 'src/css/icon.styl'), {
                        format: 'function_based_template'
                    }]
                ]
            },
            customTemplates: {
                'function_based_template': templateFunctionStylPC
            },
            apiOptions: {
                cssImageRef: '../images/icon.png'
            },
            spritesmithOptions: {
                algorithm: 'binary-tree',
                padding: 2
            }
        }),
        new MiniCssExtractPlugin({
            filename: "../css/index.css",
        }),
    ],
};

5. 在src/images/icon中放置需要合成雪碧图的图标

6. index.styl

@import "icon.styl"

7. 执行打包命令

npm start
  • icon.styl示例(由webpack-spritesmith生成)
.ico
    display: inline-block
    background-image: url("../images/icon.png")

.ico-btn-android-active
    width: 147px
    height: 59px
    background-position: -370px -250px

.ico-btn-android
    width: 147px
    height: 59px
    background-position: -370px -320px

8. index.styl(书写stylus代码)

@import "icon.styl"

.btn
    @extend .ico
    @extend .ico-btn-android
    &:hover
        @extend .ico
        @extend .ico-btn-android-active

9. 再次执行打包命令

npm start //若嫌每次手动打包麻烦的话,可以在webpack.config.js中开启自动编译watch: true

10. index.css(webpack打包后的文件)

.ico,
.btn,
.btn:hover {
  display: inline-block;
  background-image: url(../images/icon.png);
}

.ico-btn-android-active,
.btn:hover {
  width: 147px;
  height: 59px;
  background-position: -370px -250px;
}

三、相关链接

四、错误记录

stylus相关

  1. expected "indent", got "outdent"

    • tab和空格混用缩进,导致stylus编译出错
  2. expected "indent", got "literal ../"

    • 图片路径需要双引号
  3. expected "indent" got "eos"

    • 混用了tab和空格,只能用其中一种

webpack相关

  1. 清除旧文件

  2. npm operation not permitted

    • 试试重启电脑(可能是什么进程锁住了文件),不行?再看看下面其他回答
    • 知乎

五、后记

或许以上还不是最优方案,但仍在自动化的边缘反复试探,在试探的过程中发现stylus的函数有点好用,配合图片使用,可以不用再去测量图片的宽高,还有其他特性慢慢摸索吧(ง'-̀'́)ง

Image placeholder
peterq
未设置
  80人点赞

没有讨论,发表一下自己的看法吧

推荐文章
结合Spring Security进行web应用会话安全管理

在本文中,将为大家说明如何结合SpringSecurity和SpringSession管理web应用的会话。 一、SpringSecurity创建使用session的方法 SpringSecurit

闲鱼Flutter互动引擎系列——整体设计篇

什么是Candy引擎Candy引擎是闲鱼技术团队设计开发的一款:APP嵌入式的、轻量级的、易于开发、性能稳定的互动引擎;绘制系统高度融合Flutter体系,游戏场景和FlutterUI支持无缝混排;动

【Kubernetes系列】第5篇 Ingress controller – traefik组件介绍

1.概述为了能够让Ingress资源能够工作,在Kubernetes集群中必须至少有一个运行中的ingresscontroller组件。也就是说如果在kubernetes集群中没有一个ingressc

基于Webpack的css sprites实现方案

一、前言关于csssprites(雪碧图/精灵图)的几种实现方案可以参考浅谈CSSSprites雪碧图应用。本文主要讨论基于webpack的csssprites实现方案。由于使用webpack时会涉及

使用html-webpack-plugin对HTML文件进行预处理

一、前言先整理一波之前和webpack相关的文章: 使用Webpack对CSS文件进行后处理 基于Webpack的CSSSprites实现方案 Stylus系列——webpack-spritesmit

Spring-SpringAOP原理,手写Spring事务框架

一、Spring核心知识Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由RodJohnson在其著作ExpertOne-On-OneJ2EEDevelopm

代码传奇 | 身价10亿的程序员 雷军当年也为他打工——WPS之父 求伯君

他的前半生,值得我们每一个人深思。在普通人眼里,他寂寂无名,只有年岁稍长的文化人,才听说过他传奇般的存在。在IT人眼里,他是块活化石,中国第一的大旗除了他,没人敢抗!他是求伯君,从一个浙江穷山村走出来

使用Jupyter NoteBook进行IB查询和交易,以及使用算法交易示例

在搞好IB盈透接口后,试了下客户端交易,但是最终目的还是使用程序化交易。发现vnpy已经提供的Script_engine来支持JupyterNoteBook交易的,而且非常方便调用。 这里就用写了基于

Redis使用不当导致应用卡死

来源:http://rrd.me/ezfTj首先说下问题现象:内网sandbox环境API持续1周出现应用卡死,所有api无响应现象刚开始当测试抱怨环境响应慢的时候,我们重启一下应用,应用恢复正常,于

css使用url引用图片报错

css使用url引用图片报错css使用url引用图片报错,是因为图片路径填写错误,路径需要相对于css文件,而不是引用css文件的html文件。例如:css文件夹下的index.css样式表中back

css使用float怎么居中?

css使用float怎么居中?css并没有float:center,但是实现水平居中浮动是可以实现的。以下面的Li列表为例,我们要实现中间LI的居中浮动: 列表一 列表二 列表三 我们需要先了解下

webpack中css的url报错?

webpack中css的url报错?css-loader://打包样式中背景图 { test:/\.(png|jpg)$/, loader:"url-loader?limit=8192&name=im

react中的webpack是什么?

Webpack是一个开源的前端打包工具。Webpack提供了前端开发缺乏的模块化开发方式,将各种静态资源视为模块,并从它生成优化过的代码。Webpack可以从终端、或是更改webpack.config

如何不写css使div居中显示

如何不写css使div居中显示不使用css使div居中显示,可以使用标签,对其所包括的文本进行水平居中。html代码如下: 这是div 效果:(相关课程推荐:css视频教程)标签说明HT

你不知道的 CSS : Next-generation web styling

最近看了ChromeDevSummit2019大会视频,了解到了很多之前不知道的CSS新特性,挺有意思的。下面我就介绍几个激动人心的特性。特性总览:StickyStickeyStackSticySli

Spring WebFlux 的设计及工作原理剖析

前言 Spring5发布有两年了,随Spring5一起发布了一个和SpringWebMvc同级的SpringWebFlux。这是一个支持反应式编程模型的新框架体系。反应式模型区别于传统的MVC最大的不

Spring Boot 中的响应式编程和 WebFlux 入门

Spring5.0中发布了重量级组件Webflux,拉起了响应式编程的规模使用序幕。WebFlux使用的场景是异步非阻塞的,使用Webflux作为系统解决方案,在大多数场景下可以提高系统吞吐量。Spr

GoWeb教程_08.2. WebSocket

WebSocket是HTML5的重要特性,它实现了基于浏览器的远程socket,它使浏览器和服务器可以进行全双工通信,许多浏览器(Firefox、GoogleChrome和Safari)都已对此做了支

SpringBoot个人应用开发框架(SpringBoot版本2.1)+IDEA

前言: 此笔记为本人首个SpringBoot项目框架学习实践记录,期间参考了许多大神的笔记和心得。 参考文档如下: 项目git地址: 一、创建SpringBoot工程 1.1创建父POM工程结

搭建 Spring+SpringMVC+MyBatis 框架

SSM框架整合 pom中添加依赖 添加编辑Spring配置文件 添加编辑SpringMVC配置文件 添加编辑Mybatis配置文件 配置web.xml 1、pom中添加依赖 junit ju

再见 Spring Boot 1.X ,Spring Boot 2.X 走向舞台中心

2019年8月6日,Spring官方在其博客宣布,SpringBoot1.x停止维护,SpringBoot1.x生命周期正式结束。其实早在2018年7月30号,Spring官方就已经在博客进行过预告,

面试问烂的 Spring AOP 原理、SpringMVC 过程

  正文  SpringAOP,SpringMVC,这两个应该是国内面试必问题,网上有很多答案,其实背背就可以。但今天笔者带大家一起深入浅出源码,看看他的原理。以期让印象更加深刻,面试的时候游刃有余。

BAT大牛推荐开发人员必备Spring源码剖析文档,深度剖析Spring

为什么学习读源码我们每天都和代码打交道。经过数年的基础教育和职业培训,大部分程序员都会「写」代码,或者至少会抄代码和改代码。但是,会读代码的并不在多数,会读代码又真正读懂一些大项目的源码的,少之又少。

重磅|庖丁解牛之——Flutter for Web

Flutterfor Web在2018年冬的Flutter1.0伦敦发布会上,Flutter产品经理TimSneath通过一个滑动拼图的例子介绍了如何让Flutter运行在Web之上。这一当时代号Hu

SpringBoot 中的 Servlet Web 容器

1.前言 SpringBoot支持一下嵌入式Servlet容器: SpringBoot2.0.3.RELEASE需要Java8或9以及SpringFramework5.0.7.RELEASE或更高版本