WebValid
WebValid Team

Blind Code: 7 ข้อผิดพลาดร้ายแรงด้าน Accessibility ที่ AI มักจะทำพลาด

AI Accessibility A11y React Next.js QA

ข้อมูลบริบท: ตัวอย่างในบทความนี้ใช้กับโปรเจกต์ React, Next.js (App Router) และ Vite อย่างไรก็ตาม หลักการด้าน Accessibility สามารถนำไปใช้กับเฟรมเวิร์กใดก็ได้ (Vue, Svelte, Angular)

คุณเพิ่ง “vibe-code” หน้า Landing Page ใหม่ที่สวยงามภายในไม่กี่วินาทีโดยใช้ AI Assistant ตัวโปรดของคุณ Cursor หรือ Copilot สร้าง UI ทั้งหมดจากพรอมต์เดียว มันดูดีบนจอภาพของคุณ แอนิเมชันลื่นไหล และหน้าเว็บถูก deploy ได้อย่างไร้ปัญหา แต่ภายใต้เบื้องหลังนั้น คุณอาจเพิ่งบล็อกผู้ใช้ที่พึ่งพาโปรแกรมอ่านหน้าจอ (screen readers) หรือการนำทางด้วยคีย์บอร์ดไม่ให้เข้าถึงไซต์ของคุณ

เมื่อโมเดล AI สร้างโค้ด พวกมันจะให้ความสำคัญกับความสวยงามและการทำงานที่รวดเร็ว พวกมันยังขาดความเข้าใจในรายละเอียดของโครงสร้างเชิงความหมาย (semantic structure) ซึ่งหมายความว่าพวกมันมักจะทำลายชุดการทดสอบ Accessibility หากคุณไม่ตรวจสอบผลลัพธ์ของพวกมัน คุณกำลังส่งมอบผลิตภัณฑ์ที่โปรแกรมอ่านหน้าจอมองไม่เห็น และไม่สามารถนำทางด้วยคีย์บอร์ดได้

นี่คือ 7 ข้อผิดพลาดร้ายแรงด้าน Accessibility ที่โค้ดซึ่งสร้างโดย AI มักจะมี และวิธีตรวจพบก่อนการ deploy ครั้งต่อไปของคุณ

1. “Div Soup” และปุ่มผี

🔴 วิกฤต · โปรแกรมอ่านหน้าจอเข้าไม่ถึง · WCAG 4.1.2 (Name, Role, Value)

หากคุณขอให้ AI Assistant “สร้างเมนูแบบดรอปดาวน์ที่กำหนดเอง” วิธีแก้ปัญหาที่มันชอบที่สุดคือการสร้างกองขององค์ประกอบ <div> ขนาดใหญ่และใส่เหตุการณ์ onClick ลงไป เราเรียกสิ่งนี้ว่า “Div Soup”

วิธีของ AI (ก่อนหน้า):

// ❌ โค้ดที่สร้างโดย AI: ทำงานได้ในเชิงสายตา แต่เข้าถึงไม่ได้เลย
<div onClick={() => setIsOpen(true)}>เปิดเมนู</div>

ทำไมถึงเสีย: <div> โดยเนื้อแท้แล้วไม่มีคุณสมบัติการโต้ตอบ เมื่อโปรแกรมอ่านหน้าจอพบมัน มันจะอ่านแค่ “เปิดเมนู” โดยไม่ประกาศว่าเป็นส่วนที่สามารถกดได้ ยิ่งไปกว่านั้น ผู้ใช้ที่นำทางผ่านปุ่ม Tab จะข้ามองค์ประกอบนี้ไปโดยสิ้นเชิง ทำให้ไซต์ของคุณใช้งานไม่ได้สำหรับใครก็ตามที่ไม่สามารถใช้เมาส์ได้

วิธีแก้ไข (ภายหลัง):

// ✅ โค้ดที่ถูกต้อง: ปุ่มแบบ Native มาพร้อมกับความสามารถในการเข้าถึงในตัว
<button onClick={() => setIsOpen(true)}>เปิดเมนู</button>

องค์ประกอบ Native อย่างเช่น <button> และ <a> มาพร้อมกับการจัดการสถานะโฟกัสในตัว ปุ่มในคีย์บอร์ด (Enter และ Space) และบทบาทด้าน Accessibility หากคุณต้องใช้ <div> ที่กำหนดเอง คุณต้องเพิ่ม role="button" และ tabIndex={0} ด้วยตนเอง แต่มันดีกว่าเสมอถ้าจะบังคับให้ AI ใช้ Semantic HTML

หากคุณกำลังมีปัญหาในการติดตามหา div ที่ไม่ถูกต้องในคอมโพเนนต์ของคุณ ลองดูคู่มือของเราเกี่ยวกับ Markdown-Driven QA เพื่อดูว่าคุณจะตรวจสอบสิ่งนี้โดยอัตโนมัติได้อย่างไร

2. ช่องข้อมูลที่ไม่มีเลเบล (Unlabeled input)

🟡 สูง · การละทิ้งฟอร์ม · WCAG 1.3.1 (Info and Relationships)

ฟอร์มคือหัวใจสำคัญของผลิตภัณฑ์ SaaS ทุกประเภท เมื่อสร้างฟอร์มสมัครสมาชิก AI มักจะสร้างเลย์เอาต์ที่สวยงามโดยใช้ข้อความ placeholder เป็นเพียงสิ่งเดียวที่บ่งบอกถึงข้อมูลที่ต้องกรอก

วิธีของ AI (ก่อนหน้า):

// ❌ โค้ดที่สร้างโดย AI: ไม่มีความสัมพันธ์เชิงโครงสร้าง
<div>
  <span>ที่อยู่อีเมล</span>
  <input
    type="email"
    placeholder="ระบุอีเมลของคุณ"
  />
</div>

ทำไมถึงเสีย: การจัดกลุ่มด้วยสายตานั้นไม่เพียงพอ โปรแกรมอ่านหน้าจอต้องการความสัมพันธ์ที่เชื่อมโยงระหว่างเลเบล (label) และช่องกรอกข้อมูล (input) โดยตรง หากไม่มีความสัมพันธ์นี้ เมื่อผู้ใช้ย้ายไปยังช่องกรอกข้อมูล โปรแกรมอ่านหน้าจอจะประกาศเพียงว่า “แก้ไขข้อความ, ว่างเปล่า” พวกเขาจะไม่รู้เลยว่าต้องกรอกข้อมูลอะไร

วิธีแก้ไข (ภายหลัง):

// ✅ โค้ดที่ถูกต้อง: การเชื่อมโยงเลเบลอย่างถูกต้อง
<div>
  <label htmlFor="email-input">ที่อยู่อีเมล</label>
  <input
    id="email-input"
    type="email"
    placeholder="john@example.com"
  />
</div>

สั่ง AI ของคุณเสมอว่า “ใช้แท็ก <label> ที่เชื่อมโยงอย่างถูกต้องด้วยคุณสมบัติ htmlFor สำหรับ input ทั้งหมด”

3. กับดักคีย์บอร์ดใน Modal

🔴 วิกฤต · ผู้ใช้ถูกกักขัง · WCAG 2.1.2 (No Keyboard Trap)

Modal และหน้าต่างโต้ตอบ (dialogs) เป็นสิ่งที่ทำได้ถูกต้องได้ยากมาก เมื่อ AI สร้าง Modal ขึ้นมาจากศูนย์ มันแทบจะไม่เคยใช้การจัดการโฟกัสที่ถูกต้องเลย

เมื่อ Modal เปิดขึ้น โฟกัสของคีย์บอร์ด ต้อง ถูกจำกัดอยู่ภายใน Modal เพื่อไม่ให้ผู้ใช้กดแท็บไปโดนเนื้อหาพื้นหลังที่ถูกบดบังอยู่โดยไม่ได้ตั้งใจ อย่างไรก็ตาม AI มักจะลืมเตรียมวิธีทางออกไว้ให้ หากไม่มีปุ่มปิดที่เชื่อมโยงกับปุ่ม Esc ผู้ใช้คีย์บอร์ดจะถูก “กักขัง” ไว้บนหน้าเว็บของคุณอย่างเป็นทางการและต้องรีเฟรชเบราว์เซอร์เพื่อออกไป

วิธีแก้ไข: หยุดให้ AI เขียนลอจิก Modal ที่ซับซ้อนขึ้นมาเอง สั่งให้มันใช้ตัวเลือก dialog ของ HTML ซึ่งเบราว์เซอร์สมัยใหม่รองรับอยู่แล้ว มันจะจัดการเรื่องการดักโฟกัสและปุ่ม Esc ให้โดยอัตโนมัติ

// ✅ โค้ดที่ถูกต้อง: Native dialog ใช้ useImperativeHandle เพื่อการทำงานที่เสถียร
import { useRef, useImperativeHandle, forwardRef } from "react";

export const NewsletterModal = forwardRef((props, ref) => {
  const dialogRef = useRef<HTMLDialogElement>(null);

  // เปิดใช้งาน imperative methods ให้กับ parent อย่างปลอดภัย
  useImperativeHandle(ref, () => ({
    open: () => dialogRef.current?.showModal(),
    close: () => dialogRef.current?.close(),
  }));

  return (
    <dialog ref={dialogRef}>
      <h2>สมัครรับจดหมายข่าว</h2>
      {/* เนื้อหา */}
      <button onClick={() => dialogRef.current?.close()}>ปิด</button>
    </dialog>
  );
});

// การใช้งานใน Parent component:
// const modalRef = useRef(null);
// <button onClick={() => modalRef.current?.open()}>เปิด</button>
// <NewsletterModal ref={modalRef} />

4. ตัวบ่งชี้โฟกัสที่มองไม่เห็น

🟡 สูง · ความสับสนในการนำทาง · WCAG 2.4.13 (Focus Appearance)

AI Assistant ชอบสร้างดีไซน์ที่ดูมินิมอลแบบสุดๆ สิ่งที่พบบ่อยใน CSS ที่ AI สร้างขึ้นคือการตัดขอบโฟกัส (focus rings) เริ่มต้นของเบราว์เซอร์ออกไปเพราะพวกมัน “ดูไม่สวย”

// ❌ โค้ดที่สร้างโดย AI: ลบขอบโฟกัสออก
<button style={{ outline: "none" }}>ส่งข้อมูล</button>

ทำไมถึงเสีย: หากคุณลบขอบโฟกัสออก ผู้นำทางด้วยคีย์บอร์ดจะไม่มีตัวบ่งชี้ทางสายตาว่าพวกเขาอยู่ที่ไหนบนหน้าเว็บ มาตรฐาน WCAG 2.2 กำหนดให้มีตัวบ่งชี้โฟกัสที่มีความคมชัดสูง (อัตราส่วนความคมชัดอย่างน้อย 3:1) ที่มองเห็นได้อย่างชัดเจน หาก AI ของคุณลบขอบโฟกัสเริ่มต้นออก ให้บอกให้เปลี่ยนเป็นแบบที่มีสไตล์โดยใช้ pseudo-class :focus-visible แทน

หากสไตล์ที่คุณสร้างขึ้นก่อให้เกิดคอขวดด้านประสิทธิภาพ นอกเหนือจากปัญหาด้าน Accessibility โปรดอ่านบทวิเคราะห์ 5 ข้อผิดพลาด AI ใน CSS ของเรา

5. Alt-Text ที่ว่างเปล่าหรือจินตนาการขึ้นมาเอง

🟠 ปานกลาง · บริบทที่ผิดพลาด · WCAG 1.1.1 (Non-text Content)

AI ขาดบริบททางธุรกิจของแอปพลิเคชันของคุณ เมื่อมันสร้างแท็ก <img> มันมักจะปล่อยให้ข้อความ alt ว่างเปล่า หรือจินตนาการขึ้นมาเองตามชื่อตัวแปร

// ❌ โค้ดที่สร้างโดย AI: บริบทที่ไม่มีประโยชน์หรือขาดหายไป
<img src="/assets/hero-bg.jpg" alt="image" />
<img src="/icons/checkmark.svg" alt="รูปภาพไอคอนเป้าหมาย" />

ทำไมถึงเสีย: หากรูปภาพมีไว้เพื่อการตกแต่งเท่านั้น (เช่น รูปแบบพื้นหลัง หรือไอคอนทั่วไปข้างข้อความ) รูปภาพนั้น ต้อง มีแอตทริบิวต์ Alt ที่ว่างเปล่า (alt="") สิ่งนี้จะบอกโปรแกรมอ่านหน้าจอให้มองข้ามมันได้ หากมันเป็นรูปภาพที่ให้ข้อมูล (เช่น แผนภูมิ) มันต้องการคำอธิบายที่แม่นยำ AI ไม่สามารถระบุความแตกต่างนี้ให้คุณได้ คุณต้องตรวจสอบแท็ก alt ด้วยตนเองเพื่อให้แน่ใจว่ามันให้คุณค่าจริงๆ

6. การวางโครงสร้าง DOM ที่ผิดกฎ (ตัวทำลายโครงสร้าง Accessibility)

🔴 วิกฤต · การประมวลผลผิดพลาด · ข้อผิดพลาดไวยากรณ์ HTML5

เมื่อคุณสั่งให้ AI “สร้างปุ่มที่นำไปยังหน้าชำระเงิน” มันมักจะสร้าง HTML ที่ซ้อนกันอย่างผิดกฎ—เช่นการวางแท็ก <button> ไว้ภายในแท็ก <a>

วิธีของ AI (ก่อนหน้า):

// ❌ โค้ดที่สร้างโดย AI: การซ้อนทับที่ผิดกฎทำให้ Parser ของ HTML ทำงานผิดพลาด
<a href="/checkout">
  <button onClick={trackEvent}>ซื้อเลย</button>
</a>

ทำไมถึงเสีย: เบราว์เซอร์สมัยใหม่พยายามแก้ไขไวยากรณ์ที่ผิดกฎโดยอัตโนมัติ ซึ่งจะทำให้ Accessibility Tree เสียหายอย่างสิ้นเชิง เมื่อโปรแกรมอ่านหน้าจออ่านถึงส่วนนี้ มันจะสับสนกับองค์ประกอบที่มีการโต้ตอบที่ซ้อนกัน มันจะอาจประกาศข้อมูลซ้ำสองขยับข้ามไปเลย หรือทำให้โฟกัสคีย์บอร์ดติดลูป

วิธีแก้ไข (ภายหลัง):

// ✅ โค้ดที่ถูกต้อง: ลิงก์เชิงความหมาย (Semantic link) ที่ถูกปรับแต่งสไตล์ให้เหมือนปุ่ม
import Link from "next/link";

<Link
  href="/checkout"
  className="btn-primary"
  onClick={() => {
    trackEvent("checkout_clicked");
  }}
>
  ซื้อเลย
</Link>;

เพื่อตรวจพบข้อผิดพลาดเหล่านี้ตั้งแต่เนิ่นๆ ให้ใช้ HTML Syntax Scanner เพื่อวิเคราะห์โครงสร้าง DOM ที่แสดงผลออกมาสำหรับกฎการซ้อนทับที่ไม่ถูกต้อง

7. ระเบิดนิวเคลียร์ “Aria-Hidden”

🔴 วิกฤต · เนื้อหาที่มองไม่เห็น · WCAG 1.3.1 (Info and Relationships)

Axe-core Scanner มักจะตรวจพบข้อผิดพลาดที่เกิดจากความมั่นใจเกินไปของ AI: การแก้ไขที่มากเกินไป หากคุณขอให้ AI “แก้ไขปัญหาโปรแกรมอ่านหน้าจอบนองค์ประกอบพื้นหลัง” มันมักจะใส่ aria-hidden="true" ลงบนคอนเทนเนอร์หลัก

วิธีของ AI (ก่อนหน้า):

// ❌ โค้ดที่สร้างโดย AI: ทำให้แอปพลิเคชันทั้งหมดหายไปจากการรับรู้ของ Accessibility
<main aria-hidden="true">
  <div className="decorative-background" />
  <form>
    <label htmlFor="email">อีเมล</label>
    <input
      id="email"
      type="email"
    />
    <button>ส่งข้อมูล</button>
  </form>
</main>

ทำไมถึงเสีย: เมื่อใช้ aria-hidden="true" กับองค์ประกอบแม่ ทุก องค์ประกอบลูกที่อยู่ภายในจะถูกลบออกจาก Accessibility Tree ฟอร์มทั้งหมดจะหายไปจากสายตาของผู้พิการทางสายตาโดยสิ้นเชิง แม้ว่า input จะถูกใส่เลเบลมาเป็นอย่างดีก็ตาม หน้าตา UI นั้นดูไม่เปลี่ยนไปเลย ทำให้บั๊กนี้ตรวจจับได้ยากมากหากไม่มีการตรวจด้วย Axe-Core

วิธีแก้ไข (ภายหลัง):

// ✅ โค้ดที่ถูกต้อง: ซ่อนเฉพาะองค์ประกอบที่เป็นการตกแต่งเท่านั้น
<main>
  <div
    aria-hidden="true"
    className="decorative-background"
  />
  <form>
    <label htmlFor="email">อีเมล</label>
    <input
      id="email"
      type="email"
    />
    <button>ส่งข้อมูล</button>
  </form>
</main>

ข้อเท็จจริง: วิกฤตหนี้สินด้าน Accessibility

เพื่อที่จะเข้าใจว่าทำไมการพึ่งพาแต่ AI เพียงอย่างเดียวจึงเป็นเรื่องอันตราย เราต้องมองไปยังสถานะปัจจุบันของเว็บ รายงาน WebAIM Million 2024 ได้วิเคราะห์หน้าแรกของเว็บไซต์ชั้นนำ 1 ล้านหน้า และพบว่า 95.9% ของเว็บไซต์เหล่านั้นมีข้อผิดพลาดตามมาตรฐาน WCAG 2

ข้อผิดพลาดที่พบบ่อยที่สุดนั้นตรงกับโค้ดที่ AI มักจะสร้างขึ้น:

  1. ข้อความที่มีความคมชัดต่ำ (81%)
  2. ขาด Alt-text สำหรับรูปภาพ (54%)
  3. ขาดเลเบลสำหรับช่องกรอกฟอร์ม (48%)

เมื่อคุณ “vibe-code” โดยไม่มีการตรวจสอบ คุณไม่ได้แค่ทำผิดพลาดเท่านั้น แต่คุณกำลังมีส่วนช่วยสร้างช่องว่างด้าน Accessibility ที่ใหญ่ที่สุดในอุตสาหกรรมด้วยตนเอง

ความสามารถในการตรวจสอบของ WebValid

โมเดล AI นั้นน่าทึ่งในการเขียนโค้ด แต่พวกมันประมวลผลไม่เก่งในการมองเห็นผลลัพธ์สุดท้ายของ DOM คุณไม่สามารถแค่ก๊อปปี้โค้ดไปวางใน ChatGPT แล้วถามว่า “สิ่งนี้เข้าถึงได้ไหม (accessible)?” เพราะคอมโพเนนต์ React เพียงตัวเดียวไม่ได้แสดงให้เห็นว่ามันมีพฤติกรรมอย่างไรเมื่ออยู่ในเบราว์เซอร์

WebValid เติมช่องว่างนี้ด้วยการสแกน HTML ที่แสดงผลออกมาทั้งหมด และทำหน้าที่เป็นตัวแปลทางเทคนิคสำหรับ AI Co-pilot ของคุณ

หัวข้อที่ตรวจสอบความสามารถของ WebValidข้อจำกัด
โครงสร้าง Semantics / ARIA✅ ตรวจสอบผลลัพธ์ HTML ที่แสดงผลออกมาทั้งหมดไม่สามารถระบุได้ว่า Alt-text มีบริบททางธุรกิจที่ถูกต้องหรือไม่
ขอบโฟกัส (Focus Rings)✅ ตรวจสอบการมีอยู่ของสถานะโฟกัสใน CSSไม่สามารถระบุได้ว่าอัตราส่วนความคมชัดนั้นดูสวยงามหรือไม่
เลเบลของฟอร์ม✅ ตรวจสอบการเชื่อมโยงอย่างถูกต้อง (htmlFor)ไม่สามารถระบุได้ว่าข้อความในเลเบลนั้นมีเหตุผลในเชิงตรรกะหรือไม่

WebValid ใช้การทดสอบผ่าน Headless Browser ขั้นสูงเพื่อเลียนแบบวิธีที่โปรแกรมอ่านหน้าจอจริงๆ ประมวลผล DOM ของคุณ เพื่อค้นหาข้อผิดพลาดที่ AI Assistant ของคุณอาจทิ้งไว้เบื้องหลัง

Checklist การทดสอบ Accessibility ของคุณ

ก่อนจะ deploy โค้ดที่สร้างโดย AI ให้ลองตรวจสอบรายการด่วนเหล่านี้:

  1. การทดสอบปุ่ม Tab: ถอดเมาส์ออกแล้วลองนำทางไปรอบๆ ไซต์ของคุณโดยใช้เพียง Tab, Shift + Tab และ Enter เท่านั้น
  2. การทดสอบ Modal: เปิดทุกส่วนที่เป็น Modal หรือ Dropdown แล้วกด Esc มันปิดไหม?
  3. การทดสอบโปรแกรมอ่านหน้าจอ: เปิด VoiceOver (Mac) หรือ NVDA (Windows) แล้วลองหลับตาดู คุณสามารถกรอกข้อมูลในฟอร์มหลักของคุณได้หรือไม่?

AI Co-pilot ของคุณสามารถเขียนโค้ดที่ยอดเยี่ยมได้—มันแค่ไม่รู้ว่ามันทำผิดที่ตรงไหน หากคุณให้แผนที่ระบุข้อผิดพลาดกับมัน มันสามารถแก้ไขทุกอย่างได้ด้วยตัวเอง อย่าเดาว่าไซต์ของคุณสอดคล้องกับมาตรฐานหรือไม่ รับการตรวจสอบ DOM ที่แสดงผลออกมาอย่างเป็นระบบ เปลี่ยนมันให้เป็นพรอมต์สำหรับแก้ไข และแก้ปัญหาเหล่านี้ภายในไม่กี่นาที

เริ่มการตรวจสอบฟรีได้ที่นี่

บทความนี้มีประโยชน์หรือไม่?