当前位置: 首页 > news >正文

SvelteKit 最新中文文档教程(22)—— 最佳实践之无障碍与 SEO

前言

Svelte,一个语法简洁、入门容易,面向未来的前端框架。

从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1

image.png

Svelte 以其独特的编译时优化机制著称,具有轻量级高性能易上手等特性,非常适合构建轻量级 Web 项目

为了帮助大家学习 Svelte,我同时搭建了 Svelte 最新的中文文档站点。

如果需要进阶学习,也可以入手我的小册《Svelte 开发指南》,语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!

欢迎围观我的“网页版朋友圈”、加入“冴羽·成长陪伴社群”,踏上“前端大佬成长之路”。

无障碍

SvelteKit 默认努力为您的应用程序提供一个无障碍的平台。Svelte 的编译时无障碍检查也将适用于您构建的任何 SvelteKit 应用程序。

以下是 SvelteKit 内置无障碍功能的工作原理,以及您需要做什么来帮助这些功能尽可能好地工作。请记住,虽然 SvelteKit 提供了无障碍的基础,但您仍然要负责确保您的应用程序代码是无障碍的。如果您是无障碍新手,请参阅本指南的"进一步阅读"部分获取更多资源。

我们认识到实现无障碍可能很困难。如果您想就 SvelteKit 处理无障碍的方式提出改进建议,请提交 GitHub issue。

路由公告

在传统的服务端渲染应用程序中,每次导航(例如点击 <a> 标签)都会触发完整的页面重载。当这种情况发生时,屏幕阅读器和其他辅助技术会读出新页面的标题,让用户理解页面已经改变。

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

因此,您应用程序中的每个页面都应该有一个独特的、描述性的标题。在 SvelteKit 中,您可以通过在每个页面上放置 <svelte:head> 元素来实现:

<!--- file: src/routes/+page.svelte --->
<svelte:head><title>待办事项列表</title>
</svelte:head>

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

焦点管理

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

为了在客户端路由期间模拟这种行为,SvelteKit 在每次导航和增强型表单提交后会将焦点设置在 <body> 元素上。有一个例外 - 如果存在带有 autofocus 属性的元素,SvelteKit 将转而聚焦该元素。使用该属性时,请确保考虑对辅助技术的影响。

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

/// <reference types="@sveltejs/kit" />
// ---cut---
import { afterNavigate } from '$app/navigation';afterNavigate(() => {/** @type {HTMLElement | null} */const to_focus = document.querySelector('.focus-me');to_focus?.focus();
});

您也可以使用 goto 函数以编程方式导航到不同的页面。默认情况下,这将具有与点击链接相同的客户端路由行为。但是,goto 也接受一个 keepFocus 选项,该选项将保留当前聚焦的元素,而不是重置焦点。如果启用此选项,请确保当前聚焦的元素在导航后仍然存在于页面上。如果该元素不再存在,用户的焦点将丢失,这会让辅助技术用户感到困惑。

“lang” 属性

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

/// file: src/app.html
<html lang="de"></html>

如果您的内容提供多种语言,您应该根据当前页面的语言设置 lang 属性。您可以使用 SvelteKit 的 handle hook来实现:

/// file: src/app.html
<html lang="%lang%"></html>
/// file: src/hooks.server.js
/*** @param {import('@sveltejs/kit').RequestEvent} event*/
function get_lang(event) {return 'en';
}
// ---cut---
/** @type {import('@sveltejs/kit').Handle} */
export function handle({ event, resolve }) {return resolve(event, {transformPageChunk: ({ html }) => html.replace('%lang%', get_lang(event))});
}

进一步阅读

在大多数情况下,构建无障碍 SvelteKit 应用程序与构建无障碍 Web 应用程序是一样的。您应该能够将以下通用无障碍资源中的信息应用到您构建的任何 Web 体验中:

  • MDN Web 文档:无障碍
  • A11y 项目
  • 如何满足 WCAG(快速参考)

SEO

SEO 最重要的方面是创建高质量的内容,使其能在网络上被广泛链接。但是,构建能够良好排名的网站,还需要考虑一些技术因素。

开箱即用的功能

SSR(服务端渲染)

虽然近年来搜索引擎在索引客户端 JavaScript 渲染的内容方面有所改善,但服务端渲染的内容仍然能够更频繁和可靠地被索引。SvelteKit 默认采用 SSR,虽然您可以在handle中禁用它,但除非有充分的理由,否则应该保持启用。

[!NOTE] SvelteKit 的渲染是高度可配置的,您可以根据需要实现动态渲染。但这通常不推荐,因为 SSR 除了 SEO 之外还有其他好处。

性能

核心网页指标等信号会影响搜索引擎排名。由于 Svelte 和 SvelteKit 引入的开销最小,因此更容易构建高性能网站。您可以使用 Google 的 PageSpeed Insights 或 Lighthouse 测试您的网站性能。详情请阅读性能页面。

URL 标准化

SvelteKit 会将带有尾部斜杠的路径重定向到不带斜杠的路径(或根据您的配置反向操作),因为重复的 URL 对 SEO 不利。

手动设置

<title><meta>

每个页面都应该在 <svelte:head> 中包含精心编写的独特的 <title><meta name="description"> 元素。关于如何编写描述性标题和描述,以及其他使内容便于搜索引擎理解的建议,可以在Google的 Lighthouse SEO 审核 文档中找到。

[!NOTE] 一个常见的模式是从页面的 load 函数返回与 SEO 相关的 data,然后在根布局的 <svelte:head> 中使用它(作为page.data)。

站点地图

站点地图可帮助搜索引擎对网站内的页面进行优先级排序,特别是当您有大量内容时。您可以使用端点动态创建站点地图:

/// file: src/routes/sitemap.xml/+server.js
export async function GET() {return new Response(`<?xml version="1.0" encoding="UTF-8" ?><urlsetxmlns="https://www.sitemaps.org/schemas/sitemap/0.9"xmlns:xhtml="https://www.w3.org/1999/xhtml"xmlns:mobile="https://www.google.com/schemas/sitemap-mobile/1.0"xmlns:news="https://www.google.com/schemas/sitemap-news/0.9"xmlns:image="https://www.google.com/schemas/sitemap-image/1.1"xmlns:video="https://www.google.com/schemas/sitemap-video/1.1"><!-- <url>元素放在这里 --></urlset>`.trim(),{headers: {'Content-Type': 'application/xml'}});
}
AMP

现代网络开发的一个不幸现实是有时需要创建网站的加速移动页面(AMP)版本。在 SvelteKit 中,这可以通过设置 inlineStyleThreshold 选项来实现…

/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {kit: {// 由于不允许使用<link rel="stylesheet">,// 内联所有样式inlineStyleThreshold: Infinity}
};export default config;

…在根 +layout.js/+layout.server.js 中禁用 csr

/// file: src/routes/+layout.server.js
export const csr = false;

…在app.html中添加amp

<html amp>...
</html>

…并使用从 @sveltejs/amp 导入的 transformtransformPageChunk 转换 HTML:

/// file: src/hooks.server.js
import * as amp from '@sveltejs/amp';/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {let buffer = '';return await resolve(event, {transformPageChunk: ({ html, done }) => {buffer += html;if (done) return amp.transform(buffer);}});
}

为了防止在将页面转换为 amp 时发送任何未使用的 CSS,我们可以使用dropcss

// @filename: ambient.d.ts
declare module 'dropcss';// @filename: index.js
// ---cut---
/// file: src/hooks.server.js
// @errors: 2307
import * as amp from '@sveltejs/amp';
import dropcss from 'dropcss';/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {let buffer = '';return await resolve(event, {transformPageChunk: ({ html, done }) => {buffer += html;if (done) {let css = '';const markup = amp.transform(buffer).replace('⚡', 'amp') // dropcss无法处理此字符.replace(/<style amp-custom([^>]*?)>([^]+?)<\/style>/, (match, attributes, contents) => {css = contents;return `<style amp-custom${attributes}></style>`;});css = dropcss({ css, html: markup }).css;return markup.replace('</style>', `${css}</style>`);}}});
}

[!NOTE] 使用 handle hook 通过 amphtml-validator 验证转换后的 HTML 是个好主意,但由于速度很慢,仅建议在预渲染页面时使用。

Svelte 中文文档

点击查看中文文档:

  1. SvelteKit 无障碍
  2. SvelteKit SEO

系统学习 Svelte,欢迎入手小册《Svelte 开发指南》。语法篇、实战篇、原理篇三大篇章带你系统掌握 Svelte!

此外我还写过 JavaScript 系列、TypeScript 系列、React 系列、Next.js 系列、冴羽答读者问等 14 个系列文章, 全系列文章目录:https://github.com/mqyqingfeng/Blog

欢迎围观我的“网页版朋友圈”、加入“冴羽·成长陪伴社群”,踏上“前端大佬成长之路”。

相关文章:

  • 进程与线程:02 多进程图像
  • 在统信UOS 1060上实现自动关机
  • 高防IP能抵御哪些类型的网络攻击?
  • Buildroot、BusyBox与Yocto:嵌入式系统构建工具对比与实战指南
  • 辛格迪客户案例 | 苏州富士莱医药GMP培训管理(TMS)项目
  • 深度学习3.3 线性回归的简洁实现
  • XXL-JOB 深入理解教程
  • 【MySQL】表的约束(主键、唯一键、外键等约束类型详解)、表的设计
  • javaSE.二叉查找树和平衡二叉树
  • EMQX安装使用和客户端认证
  • PCIE Spec ---Base Address Registers
  • 13 数据存储单位与 C 语言整数类型:从位到艾字节、常见整数类型及其范围、字面量后缀、精确宽度类型详解
  • 【嵌入式系统设计师(软考中级)】第二章:嵌入式系统硬件基础知识(上)
  • 玩转Docker | 使用Docker部署nullboard任务管理工具
  • 基于Python的图片/签名转CAD小工具开发方案
  • 数字IC后端PR阶段Innovus,ICC,ICC2修复short万能脚本分享
  • Sunscreen的TFHE 与Parasol编译器新愿景
  • 前端配置代理解决发送cookie问题
  • 算法 | 鲸鱼优化算法(WOA)与强化学习的结合研究
  • Google独立站和阿里国际站不是一回事
  • 商务部:支持外籍医生开设诊所,优化罕见病药品进口抽检模式
  • 长三角议事厅·周报|服务业扩大开放:长三角六城联动新探索
  • 《蛮好的人生》上海特色鲜明,聚焦荧屏甚少出现的保险业
  • 由“环滁皆山”到“环滁皆景”,滁州如何勾勒“文旅复兴”
  • 东航推出“上博号”班机,上博设立“东航特展厅”
  • 外交部谈第十六个“联合国中文日”:期待更多人以中文为桥读中国,读懂世界