この記事、Gulp4でのビルドを前提として書いています。
#やりたかったこと
- 独自のIconFont用のSVGを、特定のディレクトリに追加すると勝手にビルド実行!
- watchタスクは書いてません…🙇♂️
- SVGが追加されるたびに、IconFont用scssのmixinが更新!
- mixin作成による、scss記述の作業軽量化!
#サンプルを使っても上手くいかず苦戦したところ
- content要素が文字化けして、上手く出力されなかった!
#参考記事
ビルド環境
node -v
- v8.16.2
npm -v
- 6.14.7
gulp -v
- CLI version: 2.3.0
- Local version: 4.0.2
npm module
- gulp-iconfont
- gulp-consolidate
- gulp-rename
gulpfile.js
const iconfont = require('gulp-iconfont');
const consolidate = require('gulp-consolidate');
const rename = require('gulp-rename');
// icon font
const filename = 'icon';
function fontBuild(cb) {
return gulp.src('src/icon/svg/*.svg')
.pipe(iconfont({
fontName: filename,
formats: ['ttf', 'eot', 'woff','woff2' , 'svg' ]
}))
.on('glyphs', function(glyphs, options) {
let consolidateOptions = {
glyphs: glyphs,
fontName: filename,
fontPath: 'fonts/',
className: 'ico'
}
gulp.src('src/icon/template/iconfont.scss')
.pipe(consolidate('lodash', consolidateOptions))
.pipe( rename( { basename: '_iconfont' , extname: '.scss'}))
.pipe(gulp.dest('src/sass/core/'));
gulp.src('src/icon/template/css.ejs')
.pipe(consolidate('lodash', consolidateOptions))
.pipe(rename( { basename: filename , extname: '.css'} ) )
.pipe(gulp.dest('src/icon/sample/'));
gulp.src('src/icon/template/html.ejs' )
.pipe(consolidate( 'lodash', consolidateOptions))
.pipe( rename( { basename: filename , extname: '.html'}))
.pipe( gulp.dest('src/icon/sample/') );
})
.pipe(gulp.dest('src/icon/sample/fonts/'))
.pipe(gulp.dest('dest/fonts/'));
cb();
}
~ 省略 ~
taskの実行処理はお好みで・・・
わたしは、_iconfont.scss がsrc/sass/coreフォルダに出力された後、scssのコンパイルを走らせています。
iconfont.scss
$iconFont-path: "<%= fontPath %>" !default;
@font-face {
font-family: "<%= fontName %>";
src: url('<%= fontPath %><%= fontName %>.eot?64h6xh');
src: url('<%= fontPath %><%= fontName %>.eot?64h6xh#iefix') format('embedded-opentype'),
url('<%= fontPath %><%= fontName %>.ttf?64h6xh') format('truetype'),
url('<%= fontPath %><%= fontName %>.woff?64h6xh') format('woff'),
url('<%= fontPath %><%= fontName %>.svg?64h6xh#<%= fontName %>') format('svg');
font-weight: normal;
font-style: normal;
}
//アイコンを配列で指定
$icons:( <% _.each(glyphs, function(glyph) { %>
<%= className %>-<%= glyph.name %> : "<%= glyph.unicode[0].charCodeAt(0).toString(16).toUpperCase() %>", <% }); %>
) !default;
//mixinを作る。アイコンの種類と、疑似要素の位置を引数で渡す。
@mixin icon($icon: false, $position: before){
@if $position == both {
$position: 'before, &:after'
}
&:#{$position}{
@if $icon{
content: #{'"\\' + map-get($icons, $icon) + '"'};
font-family: '<%= fontName %>';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
@content;
}
上記、iconfont.scssの出力結果が以下になります。
_iconfont.scss
$iconFont-path: "fonts/" !default;
@font-face {
font-family: "icon";
src: url('fonts/icon.eot?64h6xh');
src: url('fonts/icon.eot?64h6xh#iefix') format('embedded-opentype'),
url('fonts/icon.ttf?64h6xh') format('truetype'),
url('fonts/icon.woff?64h6xh') format('woff'),
url('fonts/icon.svg?64h6xh#icon') format('svg');
font-weight: normal;
font-style: normal;
}
//アイコンを配列で指定
$icons:(
ico-hogehoge1 : "EA01",
ico-hogehoge2 : "EA02",
) !default;
//mixinを作る。アイコンの種類と、疑似要素の位置を引数で渡す。
@mixin icon($icon: false, $position: before){
@if $position == both {
$position: 'before, &:after'
}
&:#{$position}{
@if $icon{
content: #{'"\\' + map-get($icons, $icon) + '"'};
font-family: 'icon';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
@content;
}
mixinでは、contentの呼び出し部分をこんな書き方にしてます。
content: #{'"\' + map-get($icons, $icon) + '"'};
design.scss
.hogehoge1 {
@include icon(ico-hogehoge1, before);
}
.hogehoge2 {
@include icon(ico-hogehoge2, after);
}
mixinを上記の方法で呼び出し、コンパイル後のcssが以下になりますが
content: "\EA01"; となって文字化け(お豆腐化)を起こしていません。
design.css
@font-face {
font-family: "icon";
src: url("fonts/icon.eot?64h6xh");
src: url("fonts/icon.eot?64h6xh#iefix") format("embedded-opentype"), url("fonts/icon.ttf?64h6xh") format("truetype"), url("fonts/icon.woff?64h6xh") format("woff"), url("fonts/icon.svg?64h6xh#icon") format("svg");
font-weight: normal;
font-style: normal;
}
.hogehoge1:before {
content: "\EA01";
font-family: 'icon';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.hogehoge2:after {
content: "\EA02";
font-family: 'icon';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
sampleのhtml/cssは有っても無くても良いと思いますが
作成したアイコンフォントの一覧があった方が便利です。
sampleソース用のejsは、ほぼ参考サイトのままのソースを使わせていただきました!
css.ejs
@font-face {
font-family: "<%= fontName %>";
src: url('<%= fontPath %><%= fontName %>.eot');
src: url('<%= fontPath %><%= fontName %>.eot?#iefix') format('eot'),
url('<%= fontPath %><%= fontName %>.woff') format('woff'),
url('<%= fontPath %><%= fontName %>.ttf') format('truetype'),
url('<%= fontPath %><%= fontName %>.svg#<%= fontName %>') format('svg');
font-weight: normal;
font-style: normal;
}
[class^="<%= className %>-"]:before, [class*=" <%= className %>-"]:before {
display: inline-block;
font-family: "<%= fontName %>";
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.<%= className %>-lg {
font-size: 1.3333333333333333em;
line-height: 0.75em;
vertical-align: -15%;
}
.<%= className %>-2x { font-size: 2em; }
.<%= className %>-3x { font-size: 3em; }
.<%= className %>-4x { font-size: 4em; }
.<%= className %>-5x { font-size: 5em; }
.<%= className %>-fw {
width: 1.2857142857142858em;
text-align: center;
}
<% _.each(glyphs, function(glyph) { %>.<%= className %>-<%= glyph.name %>:before { content: "\<%= glyph.unicode[0].charCodeAt(0).toString(16).toUpperCase() %>" }
<% }); %>
/**/
[class^="af-<%= className %>-"]:after, [class*=" af-<%= className %>-"]:after {
display: inline-block;
font-family: "<%= fontName %>";
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.<%= className %>-lg {
font-size: 1.3333333333333333em;
line-height: 0.75em;
vertical-align: -15%;
}
.af-<%= className %>-2x { font-size: 2em; }
.af-<%= className %>-3x { font-size: 3em; }
.af-<%= className %>-4x { font-size: 4em; }
.af-<%= className %>-5x { font-size: 5em; }
.af-<%= className %>-fw {
width: 1.2857142857142858em;
text-align: center;
}
<% _.each(glyphs, function(glyph) { %>.af-<%= className %>-<%= glyph.name %>:after { content: "\<%= glyph.unicode[0].charCodeAt(0).toString(16).toUpperCase() %>" }
<% }); %>
html.ejs
<html>
<head>
<title><%= fontName %></title>
<link href="<%= fontName %>.css" rel="stylesheet">
<style>
body { font-family: Gill Sans; text-align: center; background: #f7f7f7 }
body > h1 { color: #666; margin: 1em 0 }
.glyph { padding: 0 }
.glyph > li { display: inline-block; margin: .3em .2em; width: 5em; height: 6.5em; background: #fff; border-radius: .5em; position: relative }
.glyph > li span:first-child { display: block; margin-top: .1em; font-size: 4em; }
.glyph-name { font-size: .8em; color: #999; display: block }
.glyph-codepoint { color: #999; font-family: monospace }
</style>
</head>
<body>
<h1><%= fontName %></h1>
<ul class="glyph"><% _.each(glyphs, function(glyph) { %>
<li>
<span class="<%= className %> <%= className %>-<%= glyph.name %>"></span>
<span class="glyph-name"><%= className %>-<%= glyph.name %></span>
<span class="glyph-codepoint"><%= glyph.unicode[0].charCodeAt(0).toString(16).toUpperCase() %></span>
</li><% }); %>
</ul>
</body>
</html>