将网页字体转换并渲染为base64 - 保持原始外观

问题描述 投票:0回答:6

我想推迟网站上的字体加载,灵感来自于 Smashing Magazine 的延迟字体加载逻辑

主要部分是将字体转换为 base64 并准备 CSS 文件。到目前为止我的步骤:

  1. Google Web Fonts 上选择字体并下载。
  2. 使用 Font Squirrel Webfont Generator 将下载的 TTF 文件转换为嵌入 Base64 WOFF 字体的 CSS 文件(专家选项 -> CSS -> Base64 编码)。
  3. 异步加载CSS文件(这里不重要)。

Open Sans Bold 的 CSS 片段:

@font-face {
  font-family: 'Open Sans';
  src: url(data:application/x-font-woff;charset=utf-8;base64,<base64_encoded>) format('woff');
  font-weight: 700;
  font-style: normal;
}

问题是,转换后的字体看起来有很大不同。看看 Open Sans Bold: GWF vs base64 rendering comparison

特别注意口音太离谱并且字母绝对可怕

a

。其他字体系列和变体看起来也非常明显不同(大小和形状扭曲等)。


所以问题是:

如何正确地将 TTF 文件从 Google Web Fonts(或其他来源)编码为 Base64 格式,并以结果与原始文件相同的方式使用它?

css fonts base64 webfonts
6个回答
154
投票
在 Font Squirrel Expert 选项中,确保将“TrueType Hinting”选项设置为“Keep Existing”。其他任何一个选项都会导致 TrueType 指令(提示)被修改,进而影响字体的渲染。

或者,如果您对直接从 GWF 渲染字体感到满意,您可以直接获取该文件并自行进行 Base64 编码。在 OS X 或 Linux 中,在 Terminal/shell 中使用内置的 base64 命令:

$ base64 -i myfont.ttf -o fontbase64.txt


对于 Windows,您需要下载一个程序以进行 Base64 编码(有多种免费/开源工具可用)。复制该文件的内容,然后在 CSS 中使用如下:

@font-face { font-family: 'myfont'; src: url(data:font/truetype;charset=utf-8;base64,<<copied base64 string>>) format('truetype'); font-weight: normal; font-style: normal; }
(请注意,您可能需要对各种@font-face信息进行一些调整以匹配您的特定字体数据;这只是一个示例模板)


106
投票
使用此代码片段直接在浏览器中对您的字体进行 Base64 编码(独立于操作系统,无需安装任何东西)

function base64convert (files) { console.clear() const reader = new FileReader() reader.onload = (e) => { console.log(e.target.result) } reader.readAsDataURL(files[0]) }
<input type="file" onchange="base64convert(this.files)">

然后复制输出并将其粘贴到您的 CSS 中:

@font-face { font-family: 'myfont'; src: url("<<copied base64 string>>"); }
    

4
投票
获取 Google Fonts 的 Base64 代码的一种更简单的方法是使用以下工具:

https://amio.github.io/embedded-google-fonts/

输入你的字体的 URL,你会立即得到 Base64 代码:)


2
投票
除了之前的答案之外 - 一些警告:

专用字体转换器可能会删除功能或更改数据

像 fontquirrel 或 transfonter 这样的生成器/转换器实际上会

解析并重建你的字体文件。

此过程还可能会因优化设置(例如影响字体渲染的

hinting数据)而引入更改。

2023:许多转换器(例如 fontsquirrel 和 transfonter)不支持可变字体

使用这些工具获取 Base64 数据 URL 时,您在生成数据 URL 时

可能会丢失可变字体功能(设计轴相关数据被剥离)。

这并不意味着,您根本不应该使用这些转换器 - 它们大多工作良好,如果

    您彻底检查了所有转换预设
  • 您需要静态字体支持并且需要对字形范围进行子集化
通用的 Base64 转换器不会操作任何字体数据

Ilyich所示:您可以使用任何base64编码器。 (例如 browserlings 转换器。

这是基于这些步骤的另一个 JS 帮助器示例:

    获取外部CSS URL
  • 通过正则表达式查找字体 URL
  • 将所有 URL 作为 blob() 获取
  • 将 blob 转换为 base64 数据 URL
  • 用 Base64 数据 URL 替换外部 URL

inputUrl.addEventListener("input", async(e) => { let url = e.currentTarget.value; let css = await getdataUrlsFromCss(url) // output and download button fontCss.value = css; btnDownload.href = URL.createObjectURL(new Blob([css])); }); // init inputUrl.dispatchEvent(new Event("input")); async function getdataUrlsFromCss(url) { // fetch external css let css = await (await fetch(url)).text(); // find external urls in css via regex let urls = css.match(/https:\/\/[^)]+/g); for (let i = 0; i < urls.length; i++) { let url = urls[i]; // fetch font file let blob = await (await await fetch(url)).blob(); // create base64 string let base64 = await blobToBase64(blob); //replace urls with data url css = css.replaceAll(url, base64); } return css; } /** * fetched blob to base64 */ function blobToBase64(blob) { return new Promise((resolve) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.readAsDataURL(blob); }); }
body {
  font-family: sans-serif
}

legend {
  font-weight: bold;
}

fieldset {
  margin-bottom: 1em;
}

fieldset input,
fieldset textarea {
  border: none
}

input {
  width: 100%;
  display: block;
  margin-bottom: 1em;
}

textarea {
  width: 100%;
  min-height: 20em;
}

.btn-default {
  text-decoration: none;
  border: 1px solid #000;
  background: #ccc;
  color: #000;
  font-weight: bold;
  padding: 0.3em;
}
<h1>Fonts to base64</h1>
<fieldset>
  <legend>Enter CSS Url</legend>
  <input type="text" id="inputUrl" value="https://fonts.googleapis.com/css2?family=Open+Sans:ital@0;1&display=swap">
</fieldset>

<fieldset>
  <legend>New Css</legend>
  <textarea id="fontCss"></textarea>
  <p><a class="btn-default" id="btnDownload" href="#" download="fontface.css">Download css</a></p>
</fieldset>

用于测试:

Codepen 示例


0
投票
适用于 .woff 字体的简单 Nodejs 脚本。只需将扩展名更改为您的字体文件扩展名,它也可以与其他扩展名一起使用

const { readdirSync, mkdir, existsSync, readFileSync, writeFileSync } = require("fs") const { resolve } = require("path") const woffDirPath=resolve(".", "public", "assets", "fonts", "Typold", "woff") const files = readdirSync(woffDirPath) const base64Path = resolve(".", "public", "assets", "fonts", "Typold", "base64") if (!existsSync(base64Path)) mkdir(base64Path, (err) => { console.log("Error on dir creattion", err); }); for (let file of files) { if (file.includes(".woff")) { const fileData = readFileSync(resolve(woffDirPath, file), { encoding: "base64" }) writeFileSync(resolve(base64Path, file.replace(".woff", ".txt")), fileData) } } console.log("done");
    

0
投票
此 bash 脚本可以轻松地将 .ttf、.woff 和 .woff2 字体转换为 base64,确保它们在 CSS 中保持与在野外一样华丽。

为什么它很棒:

    支持多种格式:.ttf、.woff 和 .woff2(可扩展)
  • 忠实于原始:让您的字体看起来完全符合预期。
  • 灵活的输出:生成CSS文件或将@font-face代码直接复制到剪贴板。
  • 简单易行:用户友好的提示使其变得轻而易举。

快速入门:

代码:

#!/bin/bash # Initialize a variable to hold all @font-face codes, used when choosing the clipboard all_font_face_codes="" FONT_DIR="." OUTPUT_DIR="./css" SUPPORTED_EXTENSIONS=("ttf" "woff" "woff2") usage() { echo "Usage: $0 -i path/to/fonts -o path/to/output/css" exit 1 } # Parse command-line arguments while getopts "i:o:h" opt; do case ${opt} in i) FONT_DIR="${OPTARG}" ;; o) OUTPUT_DIR="${OPTARG}" ;; h|*) usage ;; esac done # Prompt user for action: create CSS files or copy to clipboard options=("Create CSS files" "Copy the @font-face code to the clipboard") select opt in "${options[@]}"; do case $opt in "Create CSS files") user_choice=1 break ;; "Copy the @font-face code to the clipboard") user_choice=2 break ;; *) echo "Invalid choice. Please enter 1 or 2." ;; esac done mkdir -p $OUTPUT_DIR # Function to generate @font-face code generate_font_face_code() { local font=$1 local font_name=$(basename "$font" | cut -d. -f1) local base64_string=$(base64 < "$font") local font_format case $font in *.ttf) font_format='truetype' ;; *.woff) font_format='woff' ;; *.woff2) font_format='woff2' ;; esac echo "@font-face { font-family: '$font_name'; /* Remember to add font-weight, font-style, etc. if needed */ src: url(data:application/$font_format;charset=utf-8;base64,$base64_string) format('$font_format'); }" } # Function to copy to clipboard copy_to_clipboard() { local data=$1 case "$OSTYPE" in "linux-gnu"*) echo "$data" | xclip -selection clipboard ;; "darwin"*) echo "$data" | pbcopy ;; *) echo "Clipboard support is not available on your OS." exit 1 ;; esac } # Loop through each font file in the directory for ext in "${SUPPORTED_EXTENSIONS[@]}"; do for font in "$FONT_DIR"/*."$ext"; do [ -f "$font" ] || continue font_face_code=$(generate_font_face_code "$font") case $user_choice in 1) # User chose to create CSS files echo "$font_face_code" >> "$OUTPUT_DIR/$(basename "$font" ."$ext").css" echo "Generated CSS for $(basename "$font" ."$ext")" ;; 2) # User chose to copy to clipboard all_font_face_codes+="$font_face_code"$'\n' echo "Generated CSS source for $(basename "$font" ."$ext")" ;; esac done done # Output message based on user choice if [ $user_choice -eq 1 ]; then echo "All fonts processed." echo "CSS files generated in $OUTPUT_DIR" elif [ $user_choice -eq 2 ]; then copy_to_clipboard "$all_font_face_codes" echo "All @font-face codes copied to clipboard." fi
使用示例

$ ./font_encoder.sh # [-h -i -o]
尝试一下,看看你的字体是否平滑地变换,编码愉快! 🚀

© www.soinside.com 2019 - 2024. All rights reserved.