CycleTracker:基本 HTML 和 CSS

为了构建 PWA(渐进式网页应用),我们需要创建一个功能完备的网页应用。在本节中,我们将为一个静态网页标记 HTML,并使用 CSS 增强外观。

我们的项目是创建 CycleTracker,一个月经周期追踪器。此入门 PWA 教程的第一步是编写 HTML 和 CSS。页面顶部是一个表单,用户可以在其中输入每个周期的开始和结束日期。底部是一个之前月经周期的列表。

我们创建一个 HTML 文件,在头部添加元数据,并在静态网页中包含一个表单和一个占位符,用于显示用户输入的数据。然后,我们将添加一个外部 CSS 样式表以改善网站的外观。

要完成本教程,最好对 HTML、CSS 和 JavaScript 有基本了解。如果你不熟悉这些,MDN 是 "入门" 的所在地,这是一个关于网页开发的入门系列教程。

在接下来的几节中,我们将设置一个本地开发环境,并在添加 JavaScript 功能将本节中创建的静态内容转换为功能性网页应用之前,查看我们的进度。一旦我们拥有一个功能性应用程序,我们就可以将其逐步增强为一个可安装且可离线工作的 PWA。

静态网页内容

我们的静态网站 HTML,包括占位符 <link><script> 元素,用于尚未创建的外部 CSS 和 JavaScript 文件,如下所示:

html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Cycle Tracker</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <h1>Period tracker</h1>
    <form>
      <fieldset>
        <legend>Enter your period start and end date</legend>
        <p>
          <label for="start-date">Start date</label>
          <input type="date" id="start-date" required />
        </p>
        <p>
          <label for="end-date">End date</label>
          <input type="date" id="end-date" required />
        </p>
      </fieldset>
      <p>
        <button type="submit">Add Period</button>
      </p>
    </form>
    <section id="past-periods"></section>
    <script src="app.js" defer></script>
  </body>
</html>

复制此 HTML 并将其保存到名为 index.html 的文件中。

HTML 内容

即使你熟悉 index.html 中的 HTML,我们也建议你在添加一些临时硬编码数据、将 CSS 添加到 style.css 外部样式表以及创建 app.js(应用程序的 JavaScript,使此网页正常工作)之前,通读本节内容。

HTML 的第一行是文档类型声明,它确保内容行为正确。

html
<!doctype html>

<html> 标签使用 lang 属性将所有内容包装起来,该属性定义页面的主要语言。

html
<!doctype html>
<html lang="en-US">
  <!-- the <head> and <body> will go here -->
</html>

文档头部

<head> 包含有关网页应用程序的机器可读信息,这些信息对读者不可见,除了 <title>,它将显示为浏览器标签的标题。

<head> 包括所有元数据。<head> 中的前两部分信息应该始终是字符集定义,它定义字符编码,以及视窗元标签,它确保页面以视窗的宽度呈现,并且在非常小的屏幕上加载时不会缩小。

html
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
</head>

我们使用 <title> 元素将页面的标题设置为 "Cycle Tracker"。虽然 <head> 的内容不会在页面中显示,但 <title> 的内容会显示!<title> 元素的内部文本在页面加载时会显示在浏览器标签中,在搜索引擎结果中也会显示,并且是用户将网页添加到书签时使用的默认标题。标题还为依赖标题来了解当前所在的标签的屏幕阅读器用户提供了可访问的名称。

虽然标题可以是 "月经周期跟踪应用程序",但我们选择了更简短的名称,更不显眼。

html
<title>Cycle Tracker</title>

虽然官方上是可选的,但为了更好的用户体验,这两个 <meta> 标签和 <title><head> 中的三个组成部分,应该被视为任何 HTML 文档的必需组成部分。

目前,我们在 <head> 中包含的最后一个组件是一个 <link> 元素,它将 style.css(我们尚未编写的样式表)链接到我们的 HTML。

html
<link rel="stylesheet" href="style.css" />

HTML <link> 元素用于指定当前文档和外部资源之间的关系。rel 属性有超过 25 个定义的值,以及许多不在任何规范中的值。最常用的值 rel="stylesheet" 将外部资源作为样式表导入。

我们将在以后的章节中重新讨论 <link> 元素及其 rel 属性,届时我们将包含指向清单文件的链接。

文档主体

<body> 元素包含我们希望用户在互联网上访问该网站时显示的所有内容。

<body> 中,我们使用 <h1> 包含应用程序的名称作为一级标题,以及一个 <form>

html
<body>
  <h1>Period tracker</h1>
  <form></form>
</body>

表单将包含说明、表单控件、每个表单控件的标签以及提交按钮。在表单控件方面,我们需要用户输入每个提交的月经周期的开始日期和结束日期。

<form> 中,我们包含一个 <fieldset>,其中包含一个 <legend>,用于标记该组表单字段的目的。

html
<form>
  <fieldset>
    <legend>Enter your period start and end date</legend>
  </fieldset>
</form>

日期选择器是类型为 date<input> 元素。我们包含 required 属性,以防止用户意外提交不完整的表单,从而减少用户错误。

为了将 <label> 与表单控件相关联,每个 <input> 都有一个 id 属性,该属性与相关联的 <label>for 属性匹配。相关联的标签为每个 <input> 提供了一个可访问的名称。

html
<label for="start-date">Start date</label>
<input type="date" id="start-date" required />

将所有这些放在一起,在 <fieldset> 中,我们包含两个段落(<p> 元素),每个段落都包含一个用于输入当前月经周期的开始日期和结束日期的日期选择器,以及日期选择器的关联 <label>。我们还包含一个 <button> 元素,它提交表单;我们通过在开始和结束标签之间包含该文本将其标记为 "添加周期"。type="submit" 是可选的,因为 submit<button> 的默认类型。

html
<form>
  <fieldset>
    <legend>Enter your period start and end date</legend>
    <p>
      <label for="start-date">Start date</label>
      <input type="date" id="start-date" required />
    </p>
    <p>
      <label for="end-date">End date</label>
      <input type="date" id="end-date" required />
    </p>
  </fieldset>
  <p>
    <button type="submit">Add Period</button>
  </p>
</form>

我们鼓励你学习有关制作无障碍网页表单的更多信息。

临时硬编码结果文本

然后,我们包含一个空的 <section>。这个容器将使用 JavaScript 填充。

html
<section id="past-periods"></section>

当用户提交表单时,我们将使用 JavaScript 捕获数据并呈现过去周期的列表,以及该部分的标题。

暂时,我们在该 <section> 中临时硬编码了一些内容,包括一个 <h2> 标题和几个过去的周期,以便在编写页面的 CSS 时有一些内容可以进行样式化。

html
<section id="past-periods">
  <h2>Past periods</h2>
  <ul>
    <li>From 01/01/2024 to 01/06/2024</li>
    <li>From 01/29/2024 to 02/04/2024</li>
  </ul>
</section>

除了容器 <section id="past-periods"></section> 之外,此内容是临时的。一旦我们完成 CSS 并对应用程序的外观感到满意,我们将删除或注释掉此临时数据。

在关闭 </body> 之前,我们包含一个指向尚未编写的 app.js JavaScript 文件的链接。我们包含 defer 属性以延迟此脚本的加载,并确保在解析文档的 HTML 后执行 JavaScript。

html
<script src="app.js" defer></script>

app.js 文件将包含我们应用程序的所有工作原理,包括 <button> 的事件处理程序、将提交的数据保存到本地存储以及在正文内容中显示周期。

此步骤的 HTML 文件 现在已完成!您现在可以在浏览器中打开该文件,但您会注意到它非常简单。我们将在下一节中修复它。

CSS 内容

现在我们可以使用 CSS 来设置静态 HTML 的样式。我们的最终 CSS 是

css
body {
  margin: 1vh 1vw;
  background-color: #efe;
}
ul,
fieldset,
legend {
  border: 1px solid;
  background-color: #fff;
}
ul {
  padding: 0;
  font-family: monospace;
}
li,
legend {
  list-style-type: none;
  padding: 0.2em 0.5em;
  background-color: #cfc;
}
li:nth-of-type(even) {
  background-color: inherit;
}

如果您熟悉每一行,您可以复制上面的 CSS,或编写自己的 CSS,并将文件保存为 style.css,然后 完成静态 HTML 和 CSS。如果您不熟悉上述 CSS 中的任何内容,请继续阅读以获取解释。

Light green web page with a large header, a form with a legend, two date pickers and a button. The bottom shows fake data for two menstrual cycles and a header.

CSS 解释

我们使用 background-color 属性在 body 上设置浅绿色 (#efe) 背景颜色。然后在无序列表、字段集和图例上,我们使用白色 (#fff) 背景颜色,以及使用 border 属性添加的细实线边框。我们覆盖了图例的 background-color,使图例和列表项变成深绿色 (#cfc)。

我们使用 :nth-of-type(even) 伪类 选择器 将每个偶数列表项设置为 inherit 从其父级继承背景颜色;在这种情况下,从无序列表继承 #fff 背景颜色。

css
body {
  background-color: #efe;
}
ul,
fieldset,
legend {
  border: 1px solid;
  background-color: #fff;
}
li,
legend {
  background-color: #cfc;
}
li:nth-of-type(even) {
  background-color: inherit;
}

为了使无序列表和列表项看起来不像列表,我们通过在 ul 上设置 padding: 0 来删除填充,并通过在列表项本身设置 list-style-type: none 来删除列表标记。

css
ul {
  padding: 0;
}
li {
  list-style-type: none;
}

我们通过使用 vwvh 视窗单位 设置 bodymargin 来添加一些空白,使应用程序外部的空白与视窗的大小成比例。我们还在 lilegend 上添加了一些填充。最后,为了改善但不能修复过去周期数据的对齐方式,我们将 ul 结果部分的 font-family 设置为 monospace,使每个字形具有相同的固定宽度。

css
body {
  margin: 1vh 1vw;
}
ul {
  font-family: monospace;
}
li,
legend {
  padding: 0.2em 0.5em;
}

我们可以将上述内容结合起来,在每个选择器声明块中放置多个属性。我们甚至可以将 lilegend 的样式放在一起;不相关的样式,例如 legend 上的 list-style-type 声明,将被忽略。

css
body {
  margin: 1vh 1vw;
  background-color: #efe;
}
ul,
fieldset,
legend {
  border: 1px solid;
  background-color: #fff;
}
ul {
  padding: 0;
  font-family: monospace;
}
li,
legend {
  list-style-type: none;
  padding: 0.2em 0.5em;
  background-color: #cfc;
}
li:nth-of-type(even) {
  background-color: inherit;
}

如果您仍然不熟悉上述任何 CSS,您可以查找 CSS 属性选择器,或者完成 CSS 入门 学习路径。

无论您是使用上面 CSS 的逐字 verbatim、编辑上面样式以满足您的偏好,还是从头开始编写自己的 CSS,请将所有 CSS 包含在一个新文件中,并将其保存为 style.css,与您的 index.html 文件位于同一个目录中。

完成我们的 PWA 的静态 HTML 和 CSS

在继续之前,请 注释掉 或删除虚假过去周期数据和标题

html
<section id="past-periods">
  <!--
  <h2>Past periods</h2>
  <ul>
    <li>From 01/01/2024 to 01/06/2024</li>
    <li>From 01/29/2024 to 02/04/2024</li>
  </ul>
  -->
</section>

接下来

在添加 JavaScript 功能 以将此静态内容转换为 Web 应用程序,然后使用 清单文件服务工作者 将其增强为渐进式 Web 应用程序之前,我们将 创建一个本地开发环境 来查看我们的进度。

在此之前,您可以查看 静态 CycleTracker 外壳,并从 GitHub 下载 CycleTracker HTML 和 CSS 源代码