コンテンツにスキップ

Progressive Enhancement

このコンテンツはまだ日本語訳がありません。

渐进增强

渐进增强是网页设计中的一种策略,它首先强调网页内容,允许每个人都能访问网页的基本内容和功能,而具有附加浏览器功能或更快互联网访问速度的用户则可以获得增强版本。

- [维基百科][维基百科]

这个短语由 Steven Champeon 和 Nick Finck 于 2003 年创造,出现在不同浏览器对 CSS 和 JavaScript 的支持各有不同的时候,许多用户实际上是在禁用 JavaScript 的情况下浏览网页的。

今天,我们很幸运能够开发出更加一致的网络,并且大多数用户都启用了 JavaScript。

然而,我们仍然相信 Remix 的渐进式增强的核心原则。它能通过简单的开发工作流程打造出快速且有弹性的应用程序。

性能:虽然您很容易认为只有 5% 的用户的连接速度很慢,但实际情况是,100% 的用户在 5% 的时间内连接速度都很慢。

弹性:每个人都禁用 JavaScript,直到它被加载为止。

简单:使用 Remix 以逐步增强的方式构建您的应用程序实际上比构建传统 SPA 更简单。

表现

从服务器发送 HTML 允许您的应用比典型的单页应用 (SPA) 并行执行更多操作,从而加快初始加载体验和后续导航速度。

典型的 SPA 会发送一个空白文档,并且仅在 JavaScript 加载后才开始工作。

HTML |---|
JavaScript |---------|
Data |---------------|
page rendered 👆

Remix 应用程序可以在请求到达服务器时开始工作并流式传输响应,以便浏览器可以开始并行下载 JavaScript、其他资产和数据。

👇 first byte
HTML |---|-----------|
JavaScript |---------|
Data |---------------|
page rendered 👆

弹性和可访问性

虽然您的用户可能不会在禁用 JavaScript 的情况下浏览网页,但每个人都会禁用 JavaScript,直到它完成加载。一旦您开始服务器渲染您的 UI,您就需要考虑当他们在 JavaScript 加载之前尝试与您的应用交互时会发生什么。

Remix 通过在 HTML 之上构建抽象来实现渐进式增强。这意味着您可以以无需 JavaScript 的方式构建应用,然后在 JavaScript 上分层以增强体验。

最简单的情况是 <Link to="/account">。它们会呈现一个无需 JavaScript 即可工作的 <a href="/account"> 标签。当 JavaScript 加载时,Remix 将拦截点击并通过客户端路由处理导航。这让您可以更好地控制用户体验,而不仅仅是在浏览器选项卡中旋转图标——但无论哪种方式都可以。

现在考虑一个简单的添加到购物车按钮。

export function AddToCart({ id }) {
return (
<Form method="post" action="/add-to-cart">
<input type="hidden" name="id" value={id} />
<button type="submit">Add To Cart</button>
</Form>
);
}

无论 JavaScript 是否已加载都没关系,此按钮都会将产品添加到购物车中。

当 JavaScript 加载时,Remix 将拦截表单提交并在客户端处理。这允许您添加自己的待处理 UI 或其他客户端行为。

简单

当你开始依赖 HTML 和 URL 等 Web 的基本功能时,你会发现你对客户端状态和状态管理的接触会越来越少。

考虑之前的按钮,在对代码没有根本改变的情况下,我们可以添加一些客户端行为:

import { useFetcher } from "@remix-run/react";
export function AddToCart({ id }) {
const fetcher = useFetcher();
return (
<fetcher.Form method="post" action="/add-to-cart">
<input name="id" value={id} />
<button type="submit">
{fetcher.state === "submitting"
? "Adding..."
: "Add To Cart"}
</button>
</fetcher.Form>
);
}

此功能在 JavaScript 加载时继续以与以前相同的方式工作,但是一旦 JavaScript 加载:

  • useFetcher 不再像 <Form> 那样导致导航,因此用户可以停留在同一页面上继续购物
  • 应用代码确定待处理的 UI,而不是在浏览器中旋转图标

这并不是要用两种不同的方式构建它——一次使用 JavaScript,一次不使用——而是要通过迭代来构建它。从最简单的功能版本开始并发布它;然后迭代以增强用户体验。

用户不仅将获得逐步增强的体验,而且应用程序开发人员还可以在不改变功能基本设计的情况下逐步增强UI。

另一个渐进增强带来简化的例子是 URL。当您从 URL 开始时,您无需担心客户端状态管理。您只需将 URL 用作 UI 的真实来源即可。

export function SearchBox() {
return (
<Form method="get" action="/search">
<input type="search" name="query" />
<SearchIcon />
</Form>
);
}

此组件不需要任何状态管理。它只是呈现提交到 /search 的表单。当 JavaScript 加载时,Remix 将拦截表单提交并在客户端处理它。这允许您添加自己的待处理 UI 或其他客户端行为。这是下一个迭代:

import { useNavigation } from "@remix-run/react";
export function SearchBox() {
const navigation = useNavigation();
const isSearching =
navigation.location.pathname === "/search";
return (
<Form method="get" action="/search">
<input type="search" name="query" />
{isSearching ? <Spinner /> : <SearchIcon />}
</Form>
);
}

架构上没有根本的改变,只是对用户和代码的逐步增强。

另请参阅:状态管理