Files
2nd/10_Wiki/Topics/AI_and_ML/웹 접근성 및 성능 최적화.md
T
koriweb d8a80f6272 chore(wiki): dangling 링크 canonical 정규화 (768파일/1200건)
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해
끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은
과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업.
도구: Datacollect/scripts/link_reconcile_apply.mjs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:24:15 +09:00

7.3 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-웹-접근성-및-성능-최적화 웹 접근성 및 성능 최적화 10_Wiki/Topics verified self
Web Accessibility
A11y
Performance Optimization
WCAG
Core Web Vitals
none A 0.9 applied
accessibility
a11y
performance
wcag
core-web-vitals
frontend
2026-05-10 pending
language framework
TypeScript React/Web

웹 접근성 및 성능 최적화

매 한 줄

"매 a11y 의 의 minority feature 의 의 — 매 keyboard / screen reader / high contrast user 의 의 majority 의 의 better UX.". WCAG 2.2 (2023) + WCAG 3 (draft 2026) 의 의 standard, ARIA 1.3, Core Web Vitals (LCP/INP/CLS) 의 modern user-centric performance metric. 매 2026 의 의 INP (Interaction to Next Paint, 2024 replaced FID) 의 의 main interaction metric 의 의.

매 핵심

매 WCAG 2.2 의 4 principle (POUR)

  • Perceivable: alt text, captions, contrast 4.5:1 (AA) / 7:1 (AAA).
  • Operable: keyboard navigable, focus visible, no seizure-inducing flash.
  • Understandable: clear language, error messages, predictable.
  • Robust: valid HTML, ARIA properly used, works across AT.

매 Core Web Vitals (2026)

  • LCP (Largest Contentful Paint): < 2.5s — main content visible.
  • INP (Interaction to Next Paint): < 200ms — responsiveness (replaces FID).
  • CLS (Cumulative Layout Shift): < 0.1 — visual stability.

매 응용

  1. Public sector — WCAG AA 의 의 (ADA, EU EN 301 549).
  2. E-commerce — checkout 의 keyboard accessibility (2024 EAA mandate).
  3. SEO — Core Web Vitals 의 Google ranking factor.
  4. AI tooling — voice / dictation / screen reader user 의 의 의.

💻 패턴

Semantic HTML + ARIA

<!-- 매 BAD: div soup -->
<div class="button" onclick="submit()">Submit</div>

<!-- 매 GOOD: semantic + accessible -->
<button type="submit" aria-describedby="submit-help">
  Submit
</button>
<p id="submit-help" class="text-sm">매 reset 의 의 의.</p>

Focus management (modal trap)

import { useEffect, useRef } from 'react';
import FocusTrap from 'focus-trap-react';

export function Modal({ open, onClose, children }: Props) {
  const closeRef = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    if (open) closeRef.current?.focus();
    const onKey = (e: KeyboardEvent) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);

  if (!open) return null;
  return (
    <FocusTrap>
      <div role="dialog" aria-modal="true" aria-labelledby="modal-title">
        <h2 id="modal-title">Settings</h2>
        {children}
        <button ref={closeRef} onClick={onClose}>Close</button>
      </div>
    </FocusTrap>
  );
}

LCP optimization (image priority)

// Next 15 의 의
import Image from 'next/image';

<Image
  src="/hero.webp"
  alt="Product showcase"
  width={1200}
  height={630}
  priority         // 매 LCP image 의 의 preload
  fetchPriority="high"
  sizes="(max-width: 768px) 100vw, 1200px"
/>

INP optimization (yield to main thread)

// 매 long task 의 의 의 break up
async function processLargeList(items: Item[]) {
  const CHUNK = 100;
  for (let i = 0; i < items.length; i += CHUNK) {
    items.slice(i, i + CHUNK).forEach(process);
    // 매 yield to browser — keep INP < 200ms
    await scheduler.yield?.() ?? new Promise(r => setTimeout(r, 0));
  }
}

// React 19 useTransition
function Search() {
  const [isPending, startTransition] = useTransition();
  const [results, setResults] = useState([]);

  function onChange(q: string) {
    startTransition(() => {
      setResults(filter(largeList, q));  // 매 deprioritize
    });
  }
  return <input onChange={e => onChange(e.target.value)} />;
}

CLS prevention (reserve space)

/* 매 explicit aspect ratio — image / video 의 layout shift 의 */
.media {
  aspect-ratio: 16 / 9;
  width: 100%;
  background: #eee;
}

/* 매 font 의 layout shift — size-adjust + fallback metric */
@font-face {
  font-family: 'Inter';
  src: url('/inter.woff2') format('woff2');
  size-adjust: 107%;
  ascent-override: 90%;
  font-display: swap;
}

Color contrast check

// 매 WCAG 의 의 contrast ratio
function contrastRatio(fg: string, bg: string): number {
  const lum = (hex: string) => {
    const [r, g, b] = hex.match(/\w\w/g)!.map(h => parseInt(h, 16) / 255);
    const lin = (c: number) =>
      c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
    return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
  };
  const [l1, l2] = [lum(fg), lum(bg)].sort((a, b) => b - a);
  return (l1 + 0.05) / (l2 + 0.05);  // ≥ 4.5 for AA, ≥ 7 for AAA
}

Automated testing (axe-core + Playwright)

import { test, expect } from '@playwright/test';
import { injectAxe, checkA11y } from 'axe-playwright';

test('homepage 의 a11y', async ({ page }) => {
  await page.goto('/');
  await injectAxe(page);
  await checkA11y(page, undefined, {
    detailedReport: true,
    axeOptions: { runOnly: ['wcag2a', 'wcag2aa', 'wcag22aa'] },
  });
});
<a href="#main" class="skip-link">매 본문으로 건너뛰기</a>
<header role="banner">...</header>
<nav role="navigation" aria-label="Primary">...</nav>
<main id="main" tabindex="-1">...</main>
<footer role="contentinfo">...</footer>

<style>
.skip-link {
  position: absolute; left: -9999px;
}
.skip-link:focus {
  left: 0; top: 0; z-index: 100; padding: 1rem;
}
</style>

매 결정 기준

상황 Approach
Public sector / regulated WCAG 2.2 AA mandatory + 3rd party audit
E-commerce INP optimization (form/checkout) + keyboard nav
Marketing site LCP < 2s + image priority + Next Image
SPA / dashboard Focus management + ARIA live regions
Form-heavy Error association (aria-describedby) + autocomplete
Animation-heavy prefers-reduced-motion + INP budget

기본값: Semantic HTML + axe-core CI + Lighthouse 의 LCP/INP/CLS budget + manual screen reader test (NVDA/VoiceOver) per release.

🔗 Graph

🤖 LLM 활용

언제: ARIA pattern lookup, semantic HTML refactor, WCAG criteria explanation, axe rule remediation. 언제 X: 의 actual screen reader UX evaluation (의 user testing 의 의), legal compliance ruling.

안티패턴

  • <div onclick>: keyboard / screen reader 의 의.
  • Color-only signal: red error 의 — icon / text label 의 의.
  • Auto-focus on load: 매 disorienting — modal 의 의 의 의.
  • outline: none 의 focus state 의 X: keyboard user 의 의 의 의.
  • Lazy-load LCP image: 매 LCP 의 의 — loading="eager" + fetchpriority="high".
  • tabindex 의 의 (>0): tab order 의 의 의.

🧪 검증 / 중복

  • Verified (W3C WCAG 2.2 spec, web.dev Core Web Vitals, axe-core rules, MDN ARIA Authoring Practices).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — a11y + Core Web Vitals (INP) 의 의