1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

svg形式のオリジナルiconfontのmixin作成

Posted at

この記事、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>
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?