今天來介紹 font-family

當我們對 CSS 定義「字形」的時候,會使用 font-family

p {
    font-family: "Times New Roman", Georgia, Serif;
}

font-family 由一串字型名稱組成,預設是瀏覽器會選取第一個字型來呈現,以上面例子來說,假設你的電腦有 Times New Roman 這個字型,就會用它來呈現文字;若是沒有的話,則檢查下一個,也就是 Georgia 是否有。如果 font-family 定義的字型都沒有,就會採用瀏覽器預設的字型。

想了解更多的話可以看 MDN 或是 W3C 的文件。

而今天要特別講的是預設字型的「回調」
以下這串字:

のコ Hello 你好嗎 안녕하세요 Cześć Olá Здравствуйте ♫

並不是單一字型就能處理的,即使是預設字型,也要好幾種才能把這串字呈現出來。

所以概念就是一串字,我們先試試看 font-family 的順序看能不能把字元呈現,不行的話就使用瀏覽器預設的字型,瀏覽器預設的一樣有順序,就照順序直到可以顯示出來為止。


本系列本來都是用 Servo 介紹,不過目前的寫法並沒有實踐 font-family,不管如何都直接採用預設的字型。相關的程式碼在這邊。但也因為還沒實踐,所以就不拿來舉例,若是大家有興趣可以一起來貢獻把它完成。

不過 Firefox 的 Gecko 理所當然有把它實踐囉!
這邊來看 Gecko 針對 Windows 平台的程式碼,因為不同平台的處理方式還是有差異,所以處理字型的部分有特別切開。

Gecko 使用 GetCommonFallbackFonts 這個函式來處理字型。

gfxWindowsPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                           Script aRunScript,
                                           nsTArray<const char*>& aFontList)
{
    EmojiPresentation emoji = GetEmojiPresentation(aCh);
    if (emoji != EmojiPresentation::TextOnly) {
        if (aNextCh == kVariationSelector16 ||
           (aNextCh != kVariationSelector15 &&
            emoji == EmojiPresentation::EmojiDefault)) {
            // if char is followed by VS16, try for a color emoji glyph
            aFontList.AppendElement(kFontSegoeUIEmoji);
            aFontList.AppendElement(kFontEmojiOneMozilla);
        }
    }

// Arial is used as the default fallback for system fallback
aFontList.AppendElement(kFontArial);

if (!IS_IN_BMP(aCh)) {
    uint32_t p = aCh &gt;&gt; 16;
    if (p == 1) { // SMP plane
        aFontList.AppendElement(kFontSegoeUISymbol);
        aFontList.AppendElement(kFontEbrima);
        aFontList.AppendElement(kFontNirmalaUI);
        aFontList.AppendElement(kFontCambriaMath);
    }
} else {
    uint32_t b = (aCh &gt;&gt; 8) &amp; 0xff;

    switch (b) {
    case 0x05:
        aFontList.AppendElement(kFontEstrangeloEdessa);
        aFontList.AppendElement(kFontCambria);
        break;
    case 0x06:
        aFontList.AppendElement(kFontMicrosoftUighur);
        break;
    case 0x07:
        aFontList.AppendElement(kFontEstrangeloEdessa);
        aFontList.AppendElement(kFontMVBoli);
        aFontList.AppendElement(kFontEbrima);
        break;
    case 0x09:
        aFontList.AppendElement(kFontNirmalaUI);
        aFontList.AppendElement(kFontUtsaah);
        aFontList.AppendElement(kFontAparajita);
        break;
    case 0x0a:
    case 0x0b:
    case 0x0c:
    case 0x0d:
        aFontList.AppendElement(kFontNirmalaUI);
        break;
    case 0x0e:
    // ...
    // ...
    // &#x4E2D;&#x9593;&#x7701;&#x7565;
    // ...
    // ...
   case 0xff:
        aFontList.AppendElement(kFontMicrosoftJhengHei);
        break;
    default:
        break;
    }
}

// Arial Unicode MS has lots of glyphs for obscure characters,
// use it as a last resort
aFontList.AppendElement(kFontArialUnicodeMS);

}

可以看到光瀏覽器預設字型就超過四十種,這也是因為各種奇形怪狀的符號實在太多,不同國家的文字使用的字型也不一樣,為了讓各種字元都能顯示,才不會出現顯示不出來變成框框的情形。


希望對大家有幫助,我們明天見!


關於作者

劉安齊

軟體工程師,熱愛寫程式,更喜歡推廣程式讓更多人學會