Stories

Detail Return Return

SvelteKit 最新中文文檔教程(22)—— 最佳實踐之無障礙與 SEO - Stories Detail

前言

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" ?>
        <urlset
            xmlns="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

歡迎圍觀我的“網頁版朋友圈”、加入“冴羽·成長陪伴社羣”,踏上“前端大佬成長之路”。

user avatar jcguanqi Avatar minnanitkong Avatar morimanong Avatar
Favorites 3 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.