CycleTracker:基础 HTML 和 CSS

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

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

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

要完成本教程,对 HTMLCSSJavaScript 有基本的了解会有帮助。如果您不熟悉这些,MDN 是入门系列(一个 Web 开发入门系列)的所在地。

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

静态网页内容

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

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 的第一行是 doctype 前言,它确保内容正确运行。

html
<!doctype html>

<html> 标签包含所有内容,并使用 lang 属性定义页面的主要语言。

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

文档头部

<head> 包含有关 Web 应用程序的机器可读信息,除了 <title>(显示为浏览器标签页的标题)之外,读者不可见。

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

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

我们使用 <title> 元素将页面的标题设置为“周期跟踪器”。虽然 <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> 中,我们包含一个带有 <legend><fieldset>,用于标记该组表单字段的目的。

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

日期选择器是 <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>

我们鼓励您了解更多关于创建可访问 Web 表单的信息

临时硬编码结果文本

然后,我们包含一个空的 <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: #eeffee;
}
ul,
fieldset,
legend {
  border: 1px solid;
  background-color: white;
}
ul {
  padding: 0;
  font-family: monospace;
}
li,
legend {
  list-style-type: none;
  padding: 0.2em 0.5em;
  background-color: #ccffcc;
}
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 设置浅绿色(#eeffee)背景色。然后,在无序列表、字段集和图例上,我们使用白色背景色,并使用 border 属性添加细实线边框。我们覆盖了图例的 background-color,使图例和列表项变为更深的绿色(#ccffcc)。

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

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

为了使无序列表和列表项看起来不像列表,我们通过将 ulpadding: 0 设置为 0 来移除填充,并通过将列表项本身的 list-style-type: none 设置为 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: #eeffee;
}
ul,
fieldset,
legend {
  border: 1px solid;
  background-color: white;
}
ul {
  padding: 0;
  font-family: monospace;
}
li,
legend {
  list-style-type: none;
  padding: 0.2em 0.5em;
  background-color: #ccffcc;
}
li:nth-of-type(even) {
  background-color: inherit;
}

如果上述 CSS 中仍有您不熟悉的地方,您可以查阅 CSS 属性选择器,或者学习 CSS 样式基础模块。

无论您是原样使用上述 CSS,根据您的喜好编辑上述样式,还是从头开始编写您自己的 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 应用,然后使用清单文件Service Worker将其增强为渐进式 Web 应用之前,我们将创建一个本地开发环境以查看我们的进度。

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