HTML & CSS
Article

Customizing Bootstrap Icons using Gulp

By Massimo Cassandro

If you are developing a web project using Bootstrap, you may have the need to add a set of custom icons in the place of the default Glyphicons that come with the framework.

I’ve already covered the topic of building an icon using Illustrator and Icomoon, but what is the better way to integrate icons in a Bootstrap project?

Icomoon CSS vs Glyphicons CSS

When we download a set of icons from Icomoon (for this demo I’ve created a project called my-icons), we get the font files, some demo files (that provide a useful reference to our glyphs), and a style.css file. This one contains all the CSS rules you need to use the font in your project.

Icomoon font folder

Lets take a look at the CSS file. It contains a @font-face declaration, a rule to catch all icon classes (based on the first part of their names) and a list of all icon classes:

@font-face {
  font-family: 'my-icons';
  src:url('fonts/my-icons.eot?-dp1fqh');
  /* other properties */
}

[class^="myicon-"], [class*=" myicon-"] {
  /* some properties */
}

.myicon-alert:before {
  content: "\e600";
}

.myicon-arrow-down:before {
  content: "\61";
}

/* ... more icons */

Now, let’s see the glyphicons.less file from Bootstrap:

// Import the fonts
@font-face {
  font-family: 'Glyphicons Halflings';
  src: url('@{icon-font-path}@{icon-font-name}.eot');
  /* other properties */
}

// Catchall baseclass
.glyphicon {
  /* some properties */
}

// Individual icons
.glyphicon-asterisk { 
  &:before {
    content: "\2a";
  }
}

.glyphicon-plus {
  &:before {
    content: "\2b";
  }
}

/* ... more icons */

They are very similar, but with some fundamental differences:

  • First, Glyphicons is a Less file (there is a Sass file too) and the icon font path and name are assigned to two variables (@{icon-font-path} and @{icon-font-name}).
  • Glyphicons uses a class as a “catchall” selector (.glyphicon), while Icomoon uses an attribute selector.
  • Glyphicons uses the parent selector (&) for individual classes.

The last point can be really useful in some situations, because it can simplify the way you build your CSS files.

The ampersand refers to the parent of each rule, and when glyphicons.less is compiled, it produces exactly the same result as the Icomoon CSS:

.glyphicon-asterisk:before { 
  content: "\2a";
}

So, what’s the difference?

Simply put, you can use each icon class as a mixin, therefore you can embed them in other rules without worrying about any changes to the original class.

Lets see a sample.

Using font mixins

In the screenshot below, you can see an alert block that uses an icon from the my-icons font created with Icomoon.

Alert sample

The icon is applied using a span element; this is the “classic” way to use an icon font, and it is the same way suggested for Bootstrap Glyphicons.

Therefore, to build our example we need to add a span.myicon-alert element inside a container (in this case a div):

<div class="alert">
  <span class="myicon-alert"></span>
  .alert
</div>

You can’t apply the myicon-alert directly to the div, because it would inherit the icon font. This is the reason we need the additional span element. But using mixins there’s another way to solve our problem.

First, let’s rearrange our icon font in the same way as Glyphicons and build the alert rules using mixins:

/* this replaces the [class^="myicon-"], [class*=" myicon-"] selectors */
.myicon { 
  /* catchall properties */
}

.myicon-alert { 
  &:before { 
    content: "\e600"; 
  }
}

.alert {
  /* some properties */
  .myicon-alert();
  &:before {
    .myicon();
  }
}

.myicon-alert and .myicon (parentheses can be omitted) refer to the respective classes, and import all their properties inside the .alert rule.

This is the generated CSS:

.myicon {
  /* catchall properties */
}

.myicon-alert:before {
  content: "\e600";
}

.alert {
  /* some properties */
}

.alert:before {
  content: "\e600";
}

.alert:before {
  /* myicon catchall properties */
}

Now we can minimize the markup and obtain the same result as the previous sample without a span element:

<div class="alert">
  .alert
</div>

But the generated CSS is redundant: the catchall properties are repeated twice, there are two .alert:before rules, and so on.

We can do it more efficiently using the :extend pseudo-class:

.alert {
  /* some properties */

  &:before {
    &:extend(.myicon);
    &:extend(.myicon-alert:before);
  }
}

Which produces:

.myicon,
.alert:before {
   /* myicon catchall properties */
}

.myicon-alert:before,
.alert3:before {
  content: "\e600";
}

.alert {
  /* some properties */
}

Not bad, right?

Towards Bootstrap

The above example is just one of many benefits you can get by using Less (or Sass) for icon fonts. So let’s recap the tasks we have to do to rearrange our Icomoon CSS file in the Bootstrap way:

  • Change the font path using the @{icon-font-path} variable (that must be set in our Bootstrap project variables.less file). I don’t care about the @{icon-font-name} variable (there is also another one: @{icon-font-svg-id}), but you can handle that too if you need.
  • Change the catchall selectors ([class^="myicon-"], [class*=" myicon-"]) in .myicon.
  • Change all individual icon classes using the & selector.
  • Rename the file in my-icons.less

You can do most of these changes manually, and the individual icon classes can be easily rearranged using a regular expression. Many tools can help you to perform this task, but I usually prefer Bare Bones BBEdit:

BBEdit Find & Replace

Its handy Search & Replace window, and the well documented support of Grep Patterns make BBEdit a very useful tool for this kind of work. BBEdit is a commercial code editor, but you can use its free “little brother” Text Wrangler to get the same results.

All changes take a few minutes, but you’ll probably need to repeat these tasks many times (especially when a project starts), and it would be useful if the tasks could be automated. Here is when a task runner like Gulp or Grunt, enters the game.

What is Gulp?

Gulp and Grunt are JavaScript task runners, in other words, a simple way to automate repetitive tasks. They use JavaScript and are perfect for a front-end developer since they don’t need to learn another language. Both of them only need Node.js to be installed on your computer, and this makes Grunt/Gulp scripts easy to share.

I’ve spent a bit of time to help me decide which one of them would be more suitable for this work. The difference is minimal, but I found Gulp to be a little easier, so I prefer it (maybe I’ll change my mind in the future).

Take a look at Craig’s article An Introduction to Gulp.js from last year, if you want an overview.

Installing Gulp

According to the official Gulp getting started guide, to install Gulp you have to perform a few simple steps.

Note: If you are already familiar with Gulp and have it installed, you can skip down to the next section.

First of all, you need to install the Node Package Manager for JavaScript (npm). npm comes with the Node.js installer, so you only need to download and run it.

Once npm is on your computer:

  • Open the Terminal app (or the Command Prompt on Windows)
  • Type npm install --global gulp

On a Mac, you will probably get a lot of errors, since you need to be authenticated as administrator to run this kind of command:

Gulp install with errors

This can be easily solved using the sudo (= super user do) command that allows you to run commands as a top level administrator:

sudo npm install --global gulp

You will be asked for your administrator password, and then the installation will start.

At this point, Gulp will be installed globally on your computer, but you need to install it in your project folder too (on StackOverflow you can find a brief and clear explanation on this).

To install Gulp locally you have to locate your project folder in the Terminal using the cd (= change directory) command. You can perform this task by simply dragging your project folder into the Terminal / Command Prompt window (after you have typed cd followed by a space):

Change directory

The full path of the folder will be automatically added to the terminal and you will only need to press the return key.

Once inside your project folder, type:

npm install --save-dev gulp

Your Gulp installation is now completed and you will find a node_modules folder inside your project that contains the local Gulp files. Note that if you will need Gulp for other projects, you will have to repeat the local installation for each of them.

Tip: Using Coda Terminal

Although the Terminal app is perfect for our purposes, I find that Panic Coda, the application I normally use for development, is particularly suitable for this kind of work.

Coda has a built-in Terminal app that can open a local shell inside your project window. The Terminal opens directly in your project folder and you can switch to it without leaving Coda.

Coda terminal

Install Gulp Modules

Besides installing Gulp, we need two modules (Gulp extensions) to perform our task.

They can be found at the npmjs online repository, and are Gulp Replace and Gulp Rename.

You have to install them locally in the same way you did for Gulp:

npm install --save-dev gulp-replace
npm install --save-dev gulp-rename

Note that the install command for each module can be found on its npmjs page:

Gulp replace in npmjs

Building the gulpfile.js

Now we can write our script. When Gulp is launched, it searches for a file named gulpfile.js, so you have to create it at the root of your project.

This is the content of it:

var gulp = require('gulp');
var replace = require('gulp-replace');
var rename = require("gulp-rename");

gulp.task('default', function() {
  gulp.src(['my-icons/style.css'])
    .pipe(replace(/\.myicon-(.*):before \{\n\t(.*)\n\}/g, '.myicon-$1 { \&:before { $2 } }'))
    .pipe(replace(/\[class\^="myicon-"\], \[class\*=" myicon-"\]/, '.myicon'))
    .pipe(replace(/url\('fonts\//g, "url('@{icon-font-path}/"))
    .pipe(rename("my-icons.less"))
    .pipe(gulp.dest('./'));
});

The first three lines load everything we need: Gulp and the two modules we have downloaded, then a task is instantiated: it first loads our source file (my-icons/style.css) and three replaces are performed. Note that we are using the vanilla JavaScript replace syntax and that the RegExp string is the same we’ve previously tested with BBEdit (or the tool you are using).

By default, Gulp generates a file with the same name of the source, therefore we need the Gulp Rename module to change it in my-icons.less. The last command tells Gulp the position of the generated file (in this case ./ indicates the same folder as gulpfile.js).

To perform all of the tasks, simply open the Terminal (or the Command Prompt) at your project root and type gulp.

Gulp task

This will create a my-icons.less file in your project folder root. The original file my-icons/style.css is left untouched, so that the my-icons/demo.html file (in your Icomoon folder) is still available to provide a useful reference to your font glyphs.

Project folder

If you need to update your font, you only have to download the files from Icomoon and run your Gulp task again.

Conclusion

Although not mandatory, I found that rearranging the CSS icon file can really improve and speed up the development of a web project (not only if you are using Bootstrap). Gulp can help you in many ways, we have seen here a basic usage, but you can add more actions and speed up your work further.

No Reader comments

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Front-end, once a week, for free.