Skip to main content

可访问性

SvelteKit 致力于默认为你的应用提供一个可访问的平台。Svelte 的 编译时可访问性检查 也适用于你构建的任何 SvelteKit 应用。

¥SvelteKit strives to provide an accessible platform for your app by default. Svelte’s compile-time accessibility checks will also apply to any SvelteKit application you build.

以下是 SvelteKit 内置辅助功能的工作原理,以及你需要做些什么才能使这些功能尽可能正常工作。请记住,虽然 SvelteKit 提供了可访问的基础,但你仍有责任确保你的应用代码可访问。如果你是无障碍新手,请参阅本指南的 “怎么会这样?” 部分以获取更多资源。

¥Here’s how SvelteKit’s built-in accessibility features work and what you need to do to help these features to work as well as possible. Keep in mind that while SvelteKit provides an accessible foundation, you are still responsible for making sure your application code is accessible. If you’re new to accessibility, see the “further reading” section of this guide for additional resources.

我们认识到可访问性可能很难正确实现。如果你想建议改进 SvelteKit 处理可访问性的方式,请使用 打开 GitHub 问题

¥We recognize that accessibility can be hard to get right. If you want to suggest improvements to how SvelteKit handles accessibility, please open a GitHub issue.

路由公告(Route announcements)

¥Route announcements

在传统的服务器渲染应用中,每次导航(例如单击 <a> 标签)都会触发整个页面重新加载。当发生这种情况时,屏幕阅读器和其他辅助技术将读出新页面的标题,以便用户了解页面已更改。

¥In traditional server-rendered applications, every navigation (e.g. clicking on an <a> tag) triggers a full page reload. When this happens, screen readers and other assistive technology will read out the new page’s title so that users understand that the page has changed.

由于 SvelteKit 中的页面间导航无需重新加载页面(称为 客户端路由),因此 SvelteKit 会在页面上注入一个 实时区域,每次导航后都会读出新的页面名称。这通过检查 <title> 元素来确定要宣布的页面名称。

¥Since navigation between pages in SvelteKit happens without reloading the page (known as client-side routing), SvelteKit injects a live region onto the page that will read out the new page name after each navigation. This determines the page name to announce by inspecting the <title> element.

由于这种行为,你应用中的每个页面都应该有一个唯一的描述性标题。在 SvelteKit 中,你可以通过在每个页面上放置一个 <svelte:head> 元素来执行此操作:

¥Because of this behavior, every page in your app should have a unique, descriptive title. In SvelteKit, you can do this by placing a <svelte:head> element on each page:

src/routes/+page
<svelte:head>
	<title>Todo List</title>
</svelte:head>

这将允许屏幕阅读器和其他辅助技术在导航后识别新页面。提供描述性标题对于 SEO 也很重要。

¥This will allow screen readers and other assistive technology to identify the new page after a navigation occurs. Providing a descriptive title is also important for SEO.

焦点管理(Focus management)

¥Focus management

在传统的服务器渲染应用中,每次导航都会将焦点重置到页面顶部。这可确保使用键盘或屏幕阅读器浏览网页的人从一开始就与页面交互。

¥In traditional server-rendered applications, every navigation will reset focus to the top of the page. This ensures that people browsing the web with a keyboard or screen reader will start interacting with the page from the beginning.

为了在客户端路由期间模拟此行为,SvelteKit 在每次导航和 增强表单提交 之后聚焦 <body> 元素。有一个例外 - 如果存在具有 autofocus 属性的元素,SvelteKit 将改为关注该元素。使用该属性时,请确保 考虑对辅助技术的影响

¥To simulate this behavior during client-side routing, SvelteKit focuses the <body> element after each navigation and enhanced form submission. There is one exception - if an element with the autofocus attribute is present, SvelteKit will focus that element instead. Make sure to consider the implications for assistive technology when using that attribute.

如果你想自定义 SvelteKit 的焦点管理,可以使用 afterNavigate 钩子:

¥If you want to customize SvelteKit’s focus management, you can use the afterNavigate hook:

import { function afterNavigate(callback: (navigation: import("@sveltejs/kit").AfterNavigate) => void): void

A lifecycle function that runs the supplied callback when the current component mounts, and also whenever we navigate to a new URL.

afterNavigate must be called during a component initialization. It remains active as long as the component is mounted.

afterNavigate
} from '$app/navigation';
function afterNavigate(callback: (navigation: import("@sveltejs/kit").AfterNavigate) => void): void

A lifecycle function that runs the supplied callback when the current component mounts, and also whenever we navigate to a new URL.

afterNavigate must be called during a component initialization. It remains active as long as the component is mounted.

afterNavigate
(() => {
/** @type {HTMLElement | null} */ const const to_focus: Element | null
@type{HTMLElement | null}
to_focus
= var document: Documentdocument.ParentNode.querySelector<Element>(selectors: string): Element | null (+4 overloads)

Returns the first element that is a descendant of node that matches selectors.

MDN Reference

querySelector
('.focus-me');
const to_focus: Element | null
@type{HTMLElement | null}
to_focus
?.focus();
});

你还可以使用 goto 函数以编程方式导航到其他页面。默认情况下,这将具有与单击链接相同的客户端路由行为。但是,goto 还接受 keepFocus 选项,该选项将保留当前焦点元素而不是重置焦点。如果启用此选项,请确保导航后当前焦点元素仍然存在于页面上。如果元素不再存在,用户的焦点将丢失,从而给辅助技术用户带来混乱的体验。

¥You can also programmatically navigate to a different page using the goto function. By default, this will have the same client-side routing behavior as clicking on a link. However, goto also accepts a keepFocus option that will preserve the currently-focused element instead of resetting focus. If you enable this option, make sure the currently-focused element still exists on the page after navigation. If the element no longer exists, the user’s focus will be lost, making for a confusing experience for assistive technology users.

“lang” 属性(The “lang” attribute)

¥The “lang” attribute

默认情况下,SvelteKit 的页面模板将文档的默认语言设置为英语。如果你的内容不是英文,则应更新 src/app.html 中的 <html> 元素以具有正确的 lang 属性。这将确保任何辅助技术读取文档时都使用正确的发音。例如,如果你的内容是德语,则应将 app.html 更新为以下内容:

¥By default, SvelteKit’s page template sets the default language of the document to English. If your content is not in English, you should update the <html> element in src/app.html to have the correct lang attribute. This will ensure that any assistive technology reading the document uses the correct pronunciation. For example, if your content is in German, you should update app.html to the following:

src/app
<html lang="de">

如果你的内容有多种语言版本,则应根据当前页面的语言设置 lang 属性。你可以使用 SvelteKit 的 处理钩子 执行此操作:

¥If your content is available in multiple languages, you should set the lang attribute based on the language of the current page. You can do this with SvelteKit’s handle hook:

src/app
<html lang="%lang%">
src/hooks.server
/** @type {import('@sveltejs/kit').Handle} */
export function 
function handle({ event, resolve }: {
    event: any;
    resolve: any;
}): any
@type{import('@sveltejs/kit').Handle}
handle
({ event: anyevent, resolve: anyresolve }) {
return resolve: anyresolve(event: anyevent, {
transformPageChunk: ({ html }: {
    html: any;
}) => any
transformPageChunk
: ({ html: anyhtml }) => html: anyhtml.replace('%lang%', function get_lang(event: any): string
@paramevent
get_lang
(event: anyevent))
}); }
import type { 
type Handle = (input: {
    event: RequestEvent;
    resolve(event: RequestEvent, opts?: ResolveOptions): MaybePromise<Response>;
}) => MaybePromise<...>

The handle hook runs every time the SvelteKit server receives a request and determines the response. It receives an event object representing the request and a function called resolve, which renders the route and generates a Response. This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing routes programmatically, for example).

Handle
} from '@sveltejs/kit';
export const const handle: Handlehandle:
type Handle = (input: {
    event: RequestEvent;
    resolve(event: RequestEvent, opts?: ResolveOptions): MaybePromise<Response>;
}) => MaybePromise<...>

The handle hook runs every time the SvelteKit server receives a request and determines the response. It receives an event object representing the request and a function called resolve, which renders the route and generates a Response. This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing routes programmatically, for example).

Handle
= ({ event: RequestEvent<Partial<Record<string, string>>, string | null>event, resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>resolve }) => {
return resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>resolve(event: RequestEvent<Partial<Record<string, string>>, string | null>event, {
ResolveOptions.transformPageChunk?(input: {
    html: string;
    done: boolean;
}): MaybePromise<string | undefined>

Applies custom transforms to HTML. If done is true, it’s the final chunk. Chunks are not guaranteed to be well-formed HTML (they could include an element’s opening tag but not its closing tag, for example) but they will always be split at sensible boundaries such as %sveltekit.head% or layout/page components.

@paraminput the html chunk and the info if this is the last chunk
transformPageChunk
: ({ html: stringhtml }) => html: stringhtml.String.replace(searchValue: string | RegExp, replaceValue: string): string (+3 overloads)

Replaces text in a string, using a regular expression or search string.

@paramsearchValue A string or regular expression to search for.
@paramreplaceValue A string containing the text to replace. When the {@linkcode searchValue} is a RegExp, all matches are replaced if the g flag is set (or only those matches at the beginning, if the y flag is also present). Otherwise, only the first match of {@linkcode searchValue} is replaced.
replace
('%lang%', function get_lang(event: any): string
@paramevent
get_lang
(event: RequestEvent<Partial<Record<string, string>>, string | null>event))
}); };

进一步阅读(Further reading)

¥Further reading

在大多数情况下,构建可访问的 SvelteKit 应用与构建可访问的 Web 应用相同。你应该能够将来自以下通用可访问性资源的信息应用于你构建的任何 Web 体验:

¥For the most part, building an accessible SvelteKit app is the same as building an accessible web app. You should be able to apply information from the following general accessibility resources to any web experience you build:

上一页 下一页