首页
/ freeCodeCamp Basic CSS 课程实战:使用 Google Fonts 导入并应用自定义网页字体

freeCodeCamp Basic CSS 课程实战:使用 Google Fonts 导入并应用自定义网页字体

2026-09-06 18:07:43作者:滕妙奇

本篇文章以 freeCodeCamp 开源仓库中 "Basic CSS"(CSS 基础)板块的 Import a Google Font(导入 Google Font)课程为线索,讲解如何在 HTML 页面中通过 <link> 引入 Google Fonts 在线字体库,并借助 CSS 的 font-family 属性将其应用到元素上。读完本篇文章,你将掌握网页字体(Web Font)的完整引入链路、font-family 家族名与通用字体族(generic font family)的回退写法,以及 freeCodeCamp 课程体系中该练习的自动校验与代码组织方式。

一、为什么需要"导入"自定义网页字体

在你日常开发的页面里,CSS 可以直接写 font-family: Arial;font-family: monospace;,但这些都是依赖访问者操作系统本地安装的字体——你的机器上有,不代表别人的机器上有。

除了指定大多数操作系统上都存在的常见字体外,我们还可以为网站指定非标准的、自定义的 Web 字体。Web 字体不依赖用户本地安装,而是由网页在加载时从远程字体服务器按需下载。互联网上有许多 Web 字体来源,本课程示例聚焦于 Google Fonts 字体库:它是一套可以通过在 CSS 中引用字体 URL 来使用的免费 Web 字体库。

这正是本挑战存在的意义:教会你一条可复用的"导入自定义字体 → 在 CSS 中应用"的标准路径。注意,本练习所面向的学习者环境为在线代码编辑器,因此原文档也给出了一个重要前提——如果 Google 在你的国家被屏蔽,可以跳过本挑战,因为这属于网络可达性问题,与 CSS 语法本身无关。

二、导入 Google Font 的标准写法:<link> 引用字体 URL

导入 Google Font 的操作非常直观:从 Google Fonts 字体库复制字体的 URL,然后粘贴到你的 HTML 中。本挑战要求导入 Lobster 字体。

把下面这段代码片段复制到代码编辑器的最顶部(在开头的 <style> 元素之前)

<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">

逐段拆解一下这个 <link> 标签的含义:

属性 作用
href https://fonts.googleapis.com/css?family=Lobster 字体样式表的远程地址。浏览器请求该 URL 后,Google Fonts 服务器会根据请求头中的 User-Agent 返回一份只包含该字体(含对应字重与字符集)的 CSS,其中通过 @font-face 声明字体的下载地址
rel stylesheet 声明这是一个样式表资源,浏览器会将其作为 CSS 应用(与引入本地 .css 文件的方式一致)
type text/css 明确资源 MIME 类型为 CSS(在现代 HTML5 中该属性已可选)
放置位置 <head>/代码顶部、<style> 之前 确保字体规则先于你的样式规则注册,页面样式解析时 font-family: Lobster 才能找到对应的字体定义

URL 中的查询参数 family=Lobster 指定了你需要加载的字体名。若需要一次引入多个字体,可继续追加参数(如 family=Lobster&family=Open+Sans),多词字体名中的空格在 URL 中需用 +%20 表示——这是 URL 编码规则,与 CSS 语法相互独立。

补充说明:当前课程文件 bad87fee1348bd9aedf08807.md 使用的 css?family= 是 Google Fonts 的经典端点写法。Google 后来也提供了功能更强的 css2 端点(支持可变字体与 display 等参数),但经典写法至今仍被广泛兼容。无论哪种端点,其底层原理一致:远程 CSS 通过 @font-face 声明字体族,供你页面中的 font-family 引用。

三、在 CSS 中用 font-family 应用已导入的字体

字体导入成功后,你就可以在自己的 CSS 中以 Lobster 作为**家族名(FAMILY_NAME)**来引用它了。语法模板如下:

font-family: FAMILY_NAME, GENERIC_NAME;

其中的关键点:

  • **FAMILY_NAME(家族名)**是必填的,即字体在 @font-face 中注册的名称,例如 Lobster
  • **GENERIC_NAME(通用字体族)**是可选的,用于在该字体不可用时的回退(fallback)。这部分回退机制会在下一挑战 Specify How Fonts Should Degrade 中专门展开讲解,届时你会在 h2 上写出 font-family: Lobster, monospace; 这样的回退链;
  • 家族名区分大小写。也就是说 Lobsterlobster 在 CSS 引用中不是一回事,需要与引入时声明的名字保持一致;
  • 家族名中若包含空格,必须用引号包裹。例如使用 "Open Sans" 时必须加引号(写成 font-family: "Open Sans", sans-serif;),而使用单词型字体 Lobster 时则不需要。

通用字体族(如 monospaceserifsans-serif)则相反:它们是 CSS 关键字,不区分大小写,也不需要引号。这两类名称在书写规则上的差异,是初学者最容易混淆的细节。

本节的动手任务

结合课程配套的 CatPhotoApp 小项目,本节的实际要求是:

  1. Lobster 字体导入到你的网页中;
  2. 使用**元素选择器(element selector)**为你的 h2 元素设置 font-family: Lobster

注意要求中的措辞"use an element selector"——它暗示你应当写 h2 { ... } 这样的标签选择器,而不是引入新的 classid。这正是下面自动测试会严格校验的点。

四、课程如何自动校验你的答案

freeCodeCamp 的每道编程题都配有浏览器内的自动化测试(--hints-- 区块),本挑战的测试从四个维度验证你的实现。读懂这些断言,能帮你理解"引入并应用 Web 字体"在浏览器中的可观测结果:

// 1) 你应当已经导入 Lobster 字体
assert.exists(document.querySelector('link[href*="googleapis" i]'));

// 2) 你的 h2 元素应当使用 Lobster 字体
const h2 = document.querySelector('h2');
const fontFamily = window.getComputedStyle(h2)['font-family'];
assert.match(fontFamily, /lobster/i);

// 3) 你应当只使用 h2 元素选择器来改变字体
assert.match(__helpers.removeHtmlComments(code), /\s*[^\.]h2\s*\{\s*font-family\s*:\s*('|"|)Lobster\1\s*(,\s*('|"|)[a-z -]+\3\s*)?(;\s*\}|\})/gi);

// 4) 你的 p 元素应当仍然使用 monospace 字体
const paragraphElement = document.querySelector('p');
const fontFamily = window.getComputedStyle(paragraphElement)['font-family'];
assert.match(fontFamily, /monospace/i);

逐条解读其中的技术要点:

  • 第一个断言验证"导入动作本身":DOM 中必须存在 href 包含 googleapis<link> 标签。i 标志表示不区分大小写。也就是说,只要你的 <link> 引入了 googleapis 样式表,导入即被认为成功。
  • 第二个断言验证"字体真正生效":它通过 window.getComputedStyle(h2) 读取浏览器计算后的样式,而不是直接检查你的 CSS 文本。这意味着即使你在规则里写了 font-family: Lobster,如果字体名拼写有误、或导入未生效导致回退,getComputedStyle 返回的 font-family 也不会匹配 /lobster/i。这正是"自定义 Web 字体必须成功加载才能生效"这一特性的体现——浏览器只会把你实际可用的字体族写进计算样式。
  • 第三个断言通过正则约束了选择器写法:[^\.]h2 禁止出现 .h2(类选择器),要求直接以 h2 开头写声明块;同时校验 font-family 声明的值以可选的引号包裹 Lobster 开头,并允许后面带一个可选的通用字体回退。
  • 第四个断言是一个"隔离性"测试:确保你只改了 h2,没有波及到本应保持 monospacep 元素,防止你图省事用通配符或对 body 施加全局字体。

五、初始代码与标准答案

初始代码(--seed-contents--

<style>
  .red-text {
    color: red;
  }

  p {
    font-size: 16px;
    font-family: monospace;
  }
</style>

<h2 class="red-text">CatPhotoApp</h2>
<main>
  <p class="red-text">Click here to view more <a href="#">cat photos</a>.</p>

  <a href="#"><img src="https://cdn.freecodecamp.org/curriculum/cat-photo-app/relaxing-cat.jpg" alt="A cute orange cat lying on its back."></a>

  <div>
    <p>Things cats love:</p>
    <ul>
      <li>catnip</li>
      <li>laser pointers</li>
      <li>lasagna</li>
    </ul>
    <p>Top 3 things cats hate:</p>
    <ol>
      <li>flea treatment</li>
      <li>thunder</li>
      <li>other cats</li>
    </ol>
  </div>

  <form action="https://freecatphotoapp.com/submit-cat-photo">
    <label><input type="radio" name="indoor-outdoor" checked> Indoor</label>
    <label><input type="radio" name="indoor-outdoor"> Outdoor</label><br>
    <label><input type="checkbox" name="personality" checked> Loving</label>
    <label><input type="checkbox" name="personality"> Lazy</label>
    <label><input type="checkbox" name="personality"> Energetic</label><br>
    <input type="text" placeholder="cat photo URL" required>
    <button type="submit">Submit</button>
  </form>
</main>

观察种子代码可以看到:页面里已有 .red-text 类把标题文字设为红色、p 使用 monospace,但 h2 尚无任何字体设置,因此默认显示浏览器系统字体。我们的任务就是在保持 .red-textp 规则不变的前提下,把 h2 的字体切换成刚刚导入的 Lobster

标准答案(--solutions--

<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
<style>
  .red-text {
    color: red;
  }

  p {
    font-size: 16px;
    font-family: monospace;
  }

  h2 {
    font-family: Lobster;
  }
</style>

<h2 class="red-text">CatPhotoApp</h2>
<main>
  <p class="red-text">Click here to view more <a href="#">cat photos</a>.</p>

  <a href="#"><img src="https://cdn.freecodecamp.org/curriculum/cat-photo-app/relaxing-cat.jpg" alt="A cute orange cat lying on its back."></a>

  <div>
    <p>Things cats love:</p>
    <ul>
      <li>catnip</li>
      <li>laser pointers</li>
      <li>lasagna</li>
    </ul>
    <p>Top 3 things cats hate:</p>
    <ol>
      <li>flea treatment</li>
      <li>thunder</li>
      <li>other cats</li>
    </ol>
  </div>

  <form action="https://freecatphotoapp.com/submit-cat-photo">
    <label><input type="radio" name="indoor-outdoor" checked> Indoor</label>
    <label><input type="radio" name="indoor-outdoor"> Outdoor</label><br>
    <label><input type="checkbox" name="personality" checked> Loving</label>
    <label><input type="checkbox" name="personality"> Lazy</label>
    <label><input type="checkbox" name="personality"> Energetic</label><br>
    <input type="text" placeholder="cat photo URL" required>
    <button type="submit">Submit</button>
  </form>
</main>

对照参考答案可以确认两个关键改动点:

  1. 在文件第一行(<style> 之前)追加了 Google Fonts 的 <link>
  2. 在样式表中新增了 h2 { font-family: Lobster; } 规则块。

整个改动只涉及这两处,其他结构保持原样。

六、从源码看挑战在课程体系中的位置

这道练习并非孤立存在,它在 "Basic CSS" 板块的字体系列中处于承上启下的位置。从板块定义文件 basic-css.jsonchallengeOrder 可以看到完整排序:

  • Set the Font Family of an Element(文件 bad87fee1348bd9aede08807.md):介绍 font-family 基础语法,让所有 p 元素使用 monospace
  • Import a Google Font(本挑战,文件 bad87fee1348bd9aedf08807.md:在本地字体之外,引入远程 Google Fonts 的自定义字体并应用到 h2
  • Specify How Fonts Should Degrade(文件 bad87fee1348bd9aedf08808.md):让 h2 写成 font-family: Lobster, monospace;,然后注释掉 <link>,观察字体如何优雅降级——这就是本挑战提及的 GENERIC_NAME 回退机制的实际演示。

三道练习由浅入深,构成一条完整的"字体族 → 远程字体 → 回退降级"知识链。如果你完成了本挑战后,把 <link> 注释掉仍能看到 Lobster 生效,那通常是因为你本机恰好安装了该字体——浏览器会优先使用本地字体(这也是下一挑战中特别说明的现象)。

七、挑战文件本身的组织与校验机制

本挑战的内容存储为 Markdown 文件 bad87fee1348bd9aedf08807.md,其结构反映了 freeCodeCamp 课程仓库的统一约定:

  • YAML Front Matter:文件头部的 idtitlechallengeTypedashedNamevideoUrl 等元数据。其中 challengeType: 0 表示这是一道基础的 HTML/CSS 练习;dashedName: import-a-google-font 用于 URL 定位;idbad87fee1348bd9aedf08807)则是全局唯一的课程标识,也是 basic-css.jsonchallengeOrder 引用它的依据;
  • 命名区块--description--(讲解)、--instructions--(任务)、--hints--(测试断言)、--seed-- / --seed-contents--(初始代码)、--solutions--(参考答案)。

这些结构化区块的合法性由仓库内的 Joi 校验规则约束,见 challenge-schema.js,其中 challengeType 被校验为 0~33 范围内的必填数字、solutions 等字段也有严格的数组结构要求。也就是说,仓库中每一道课程题从元数据到参考代码都经过统一的 schema 校验,本挑战自然也不例外。

八、小结:一条可复用的 Web 字体接入清单

以本挑战为模板,你在任何前端项目中接入 Google Fonts 都只需三步:

  1. 从字体库复制目标字体的 URL(例如 https://fonts.googleapis.com/css?family=Lobster),并可用 family= 参数按需声明多个字体;
  2. <link rel="stylesheet"> 放到 HTML 文档顶部、你自己的 <style>/样式表之前;
  3. 在 CSS 规则中通过 font-family 引用字体家族名,必要时追加通用字体族作为回退:font-family: FAMILY_NAME, GENERIC_NAME;

同时牢记两条书写纪律:家族名区分大小写含空格的家族名必须加引号(如 "Open Sans")。最后,若你的运行环境无法访问 Google 字体服务,可尝试使用自托管的 @font-face 方案作为替代思路——本仓库正是这样组织其自用静态字体的,可参考 client/static/fonts 目录中 Lato、Hack 等字体的 woff/woff2 文件布局,理解"字体资源本地化"的另一种工程实践。

登录后查看全文
热门项目推荐
相关项目推荐