Search code examples
fontssassfont-facemultilingualscoping

Scoping SCSS @font-face variables for use with Font Face Observer


So I maintain a site where we use Font Face Observer: https://fontfaceobserver.com — we currently define fonts like this:

$serif: Georgia, Times, 'Times New Roman', serif;
$serifFontface: 'Chronicle Display', $serif;

%serif {
  font-family: $serif;
  .fonts-loaded&{
    font-family: $serifFontface;
  }
}

We are now in the process of modifying the codebase for use as a multilingual site, where there will always be both Roman and Japanese Kanji characters on a page.

We have a body class .isJa and I tried scoping like this, but the Kanji fontface appears in the stack even without the class being present on the body:

$serif: Georgia, Times, 'Times New Roman', serif;

.isJa{
  $serif: 'hiragino kaku gothic pro', Georgia, Times, 'Times New Roman', serif;
}

$serifFontface: 'Chronicle Display', $serif;

%serif {
  font-family: $serif;
  .fonts-loaded &{
    font-family: $serifFontface;
  }
}

How / is it possible to achieve the desired outcome? i.e. the hiragino font is only declared when .isJa is present, but is declared initially and also when Font Face Observer applies the .fonts-loaded class. I should probably add that we are limited to Sass v3.2.6


Solution

  • You got bitten by @extend. Extended rules are generated only once - in the exact moment when you declare the %placeholder. Changing variables later won't affect them. This is (one of reasons) why using @extend in general is discouraged.

    What you should do is to use a mixin that has a default parameter set to your initial variable value.

    Code:

    $serifFontface: 'Chronicle Display';
    
    @mixin fontFallback($fallback: (Georgia, Times, 'Times New Roman', serif)) {
      font-family: $fallback;
      &.fonts-loaded {
        font-family: $serifFontface, $fallback;
      }
    }
    
    body {
      @include fontFallback;
    }
    
    .isJa {
      $japaneseFallback: 'hiragino kaku gothic pro', Georgia, Times, 'Times New Roman', serif;
      @include fontFallback($japaneseFallback);
    }
    

    Output:

    body {
      font-family: Georgia, Times, "Times New Roman", serif;
    }
    body.fonts-loaded {
      font-family: "Chronicle Display", Georgia, Times, "Times New Roman", serif;
    }
    
    .isJa {
      font-family: "hiragino kaku gothic pro", Georgia, Times, "Times New Roman", serif;
    }
    .isJa.fonts-loaded {
      font-family: "Chronicle Display", "hiragino kaku gothic pro", Georgia, Times, "Times New Roman", serif;
    }
    

    Read more about mixins and extends here and here.