Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom font not loaded with webpack/sass

We have a large project where we're trying to implement ITCSS pattern (which works just fine) and add to it a custom icon font created by our graphists.

Here is the folder structure (not exhaustive):

.
├── build
│   └── webpack.config.js
└── src
    ├── components                           # Using React
    │   ├── test.jsx
    │   └── test.scss
    └── styles
        ├── _objects                         # Components style reusable
        │   ├── _all.scss
        │   └── table.scss
        ├── _settings                        # Global variables
        │   ├── _all.scss
        │   ├── _custom-icons.scss           # Define icon font (see below)
        │   ├── _custom-icons-variables.scss # Define icon codes
        │   ├── _colors.scss                 # Define colors
        │   ├── _predefined-colors.scss      # Define brand colors
        │   └── _theme.scss                  # Define specific theme
        ├── _tools                           # Mixins / helpers
        │   ├── _all.scss
        │   ├── _animation.scss
        │   ├── _breakpoints.scss
        │   └── _transition.scss
        ├── _wins                            # Overrides
        │   ├── _all.scss
        │   ├── _display.scss
        │   ├── _position.scss
        │   └── _text.scss
        ├── assets
        │   └── fonts
        │       ├── custom-icons.eot
        │       ├── custom-icons.svg
        │       ├── custom-icons.ttf
        │       └── custom-icons.woff
        ├── _base.scss                       # HTML Selectors
        ├── _generic.scss                    # Reset (normalize)
        └── main.scss                        # Loads everything

OK, that's a pretty heavy file structure, but it does the job regarding what we want to achieve!

We started our app upon the react-redux-starter-kit by davezuko. We tweaked webpack config file to match our needs but didn't change the style part, so you can refer to the webpack.config.js from GitHub.

Now, here are our files:

_custom-icons-variables.scss

$fontPath: "./assets/fonts" !default;

$aw-happy: "\e9df";
$aw-smile: "\e9e1";
$aw-tongue: "\e9e3";
$aw-sad: "\e9e5";
$aw-wink: "\e9e7";
$aw-grin: "\e9e9";
$aw-cool: "\e9eb";
$aw-angry: "\e9ed";
…

_custom-icons.scss

The custom icon font is relying on Semantic-UI font icon styling.

@import "custom-icons-variables";

$fontName: 'custom-icons';

$fallbackSRC: url("#{$fontPath}/#{$fontName}.eot");
$src:
  url("#{$fontPath}/#{$fontName}.eot?#iefix") format('embedded-opentype'),
  url("#{$fontPath}/#{$fontName}.woff") format('woff'),
  url("#{$fontPath}/#{$fontName}.ttf") format('truetype'),
  url("#{$fontPath}/#{$fontName}.svg?##{$fontName}") format('svg')
;

@font-face {
  font-family: $fontName;
  src:  $fallbackSRC;
  src:  $src;
  font-weight: normal;
  font-style: normal;
}

i.icon.aw {
  font-family: $fontName !important;
}

.aw-happy {
  &:before {
    content: $aw-happy;
  }
}
.aw-smile {
  &:before {
    content: $aw-smile;
  }
}
.aw-tongue {
  &:before {
    content: $aw-tongue;
  }
}
.aw-sad {
  &:before {
    content: $aw-sad;
  }
}
.aw-wink {
  &:before {
    content: $aw-wink;
  }
}
.aw-grin {
  &:before {
    content: $aw-grin;
  }
}
.aw-cool {
  &:before {
    content: $aw-cool;
  }
}
.aw-angry {
  &:before {
    content: $aw-angry;
  }
}
…

main.scss

Everything in here is global so we avoid webpack adding a hash and allow us to use direct class names in our components (see below for an example).

:global {
  @import "_settings/all";
  @import "_settings/custom-icons";
  @import "_tools/all";
  @import "generic";
  @import "base";
  @import "_objects/all";
  @import "_wins/all";
}

test.jsx

Here you can see we use both global and scoped styles.

import React, { Component } from 'react'

import s from './test.scss'

export default class Test extends Component {
  render () {
    return (
      <div className={s['test']}>
        <i className='icon aw aw-happy'></i>
        <h1>Test</h1>
      </div>
    )
  }
}

test.scss

Yes, for each component that uses our brand colors, we need to reimport the Sass file… I don't know if it's a bad thing, but it works :)

@import "src/styles/_settings/all";

.test {
  background: $brown;
  color: $white_smoke;
}

Now that background is set, here is the problem:

The aw-happy icon is rendered as a square (like when your font is not loaded…) and I can't manage to make it work, I tried everything I could after browsing tons of resources :/

We are using Semantic-UI which is built and then bundled with webpack, so I tried to add the @font-face rule to the semantic.min.css and also moved fonts files to semantic folder:

semantic.min.css

@font-face {
   font-family: 'custom-icons';
   src:  url(themes/default/assets/fonts/custom-icons.eot);
   src:  url(themes/default/assets/fonts/custom-icons.eot?#iefix) format('embedded-opentype'),
   url(themes/default/assets/fonts/custom-icons.woff) format('woff'),
   url(themes/default/assets/fonts/custom-icons.ttf) format('truetype'),
   url(themes/default/assets/fonts/custom-icons.svg?#custom-icons) format('svg');
   font-weight: normal;
   font-style: normal;
 }
 // Semantic stuff…

And… It works!

I wonder if I'd better build and serve this custom font the same way we do with semantic, but it's annoying to move all the process apart from global styles stuff.

Any idea on how to solve this by keeping all the Sass/Webpack stuff?

like image 585
Nicolas Goudry Avatar asked Oct 31 '22 01:10

Nicolas Goudry


1 Answers

Here is the solution I've found by browsing closed bug of react-redux-starter-kit project:

I moved the @font-face definition to main.scss, above :global:

main.scss

$font-path: 'styles/assets/fonts';
$font-name: 'custom-icons';

$fallback-src: url("#{$font-path}/#{$font-name}.eot");
$src:
  url("#{$font-path}/#{$font-name}.eot?#iefix") format('embedded-opentype'),
  url("#{$font-path}/#{$font-name}.woff") format('woff'),
  url("#{$font-path}/#{$font-name}.ttf") format('truetype'),
  url("#{$font-path}/#{$font-name}.svg?##{$font-name}") format('svg')
;

@font-face {
  font-family: $font-name;
  src:  $fallback-src;
  src:  $src;
  font-weight: normal;
  font-style: normal;
}

It also worked when I defined $font-path to ../styles/assets/fonts but not to ./assets/fonts.

It's a known bug that is referenced at GitHub but davezuko didn't dig into it at this time.

like image 175
Nicolas Goudry Avatar answered Nov 08 '22 07:11

Nicolas Goudry