10 คะแนน โดย GN⁺ 2025-11-02 | 7 ความคิดเห็น | แชร์ทาง WhatsApp
  • ในเว็บอินเทอร์เฟซ การใช้ <button> แทน <div> คือทางเลือกที่ถูกต้องกว่า ทั้งในแง่การเข้าถึงและการทำงาน
  • <div> ไม่ถูกโปรแกรมอ่านหน้าจอมองว่าเป็นองค์ประกอบที่โต้ตอบได้ และไม่ตอบสนองต่อการโฟกัสด้วยคีย์บอร์ดหรือการกด Enter, Spacebar
  • แม้จะเพิ่มแอตทริบิวต์ [role="button"] หรือ [tabindex="0"] ก็ยังมี ปัญหาเรื่องลำดับการโฟกัสและการจัดการอีเวนต์จากคีย์บอร์ด อยู่
  • การแก้ปัญหาเหล่านี้ด้วยการ เพิ่ม event listener และเงื่อนไขจำนวนมาก ทำให้เกิดความซับซ้อนที่ไม่จำเป็น
  • <button> มีการรองรับการเข้าถึง การโฟกัส และการจัดการอินพุตจากคีย์บอร์ดมาให้โดยอัตโนมัติ จึงเป็นทางออกที่เรียบง่ายและเป็นมาตรฐาน

แนวทางที่ผิด: สร้างปุ่มด้วย <div>

  • ในหมู่ผู้ใช้ React หรือ HTMX มักพบการเขียน <div onclick="..."> เพื่อ ทำอินเทอร์แอ็กชันอย่างการเปิดโมดัล
    • ตัวอย่างโค้ด:
      <div onclick="showSignIn()">Open Modal</div>
      
  • ปัญหาของวิธีนี้
    • โปรแกรมอ่านหน้าจอ ไม่รับรู้องค์ประกอบนี้ว่าเป็นองค์ประกอบแบบโต้ตอบได้
    • ไม่สามารถย้ายโฟกัสมาที่องค์ประกอบนี้ด้วยคีย์บอร์ดได้
    • มีเพียงอีเวนต์ click ที่ทำงาน และ ไม่ตอบสนองต่อการกด Enter หรือ Spacebar

ข้อจำกัดของความพยายามในการ “แก้” เรื่องการเข้าถึง

  • การเพิ่มแอตทริบิวต์ [role="button"] จะช่วย แก้ปัญหาการรับรู้ของโปรแกรมอ่านหน้าจอ ได้ แต่
    ปัญหาเรื่องการโฟกัสและการรับอินพุตจากคีย์บอร์ดยังคงอยู่
  • สามารถเพิ่ม [tabindex="0"] เพื่อให้โฟกัสได้ แต่
    ก็มีความเสี่ยงที่ลำดับการโฟกัสจะเพี้ยน หรือเกิดการย้ายตำแหน่งแบบไม่คาดคิด
  • หากต้องการรองรับอินพุตจากคีย์บอร์ด ต้องไปลงทะเบียนอีเวนต์ keydown แบบ global ไว้ที่ document และ
    ตรวจจับปุ่ม Enter หรือ ' ' (space) เพื่อ ค้นหาองค์ประกอบที่กำลังโฟกัสอยู่แล้วสั่งให้ทำงาน
    document.addEventListener('keydown', (event) => {
      if (event.key !== 'Enter' && event.key !== ' ') return;
      const notRealBtn = document.activeElement.closest('[onclick]');
      if (!notRealBtn) return;
      // 실행 코드
    });
    
  • สุดท้ายแล้ว มันก็คือ การนำสิ่งที่ <button> มีให้อยู่แล้วกลับมาสร้างใหม่แบบซับซ้อนโดยไม่จำเป็น

ฟีเจอร์พื้นฐานที่ <button> มีให้

  • องค์ประกอบ <button> รองรับสิ่งต่อไปนี้โดยอัตโนมัติ
    • บทบาทโดยนัย ([role="button"])
    • ความสามารถในการรับโฟกัสโดยอัตโนมัติ
    • เมื่ออยู่ในสถานะโฟกัส การกด Enter และ Spacebar จะทำให้เกิดอีเวนต์ click
  • หากต้องการทำพฤติกรรมเดียวกันด้วย <div> จะต้องมี หลายแอตทริบิวต์และสคริปต์ประกอบกัน แต่
    <button> แก้ได้ด้วยบรรทัดเดียว
    <button onclick="showSignIn()">Open Modal</button>
    

บทสรุป: ความเรียบง่ายคือสิ่งที่ดีที่สุด

  • <button> คือ วิธีที่เรียบง่ายที่สุดในการรองรับมาตรฐานการเข้าถึง พร้อมกับลดปริมาณโค้ด
  • การ ใช้องค์ประกอบ HTML มาตรฐาน โดยไม่เพิ่มการจัดการอีเวนต์หรือแอตทริบิวต์ที่ไม่จำเป็น จะดีกว่าในแง่การบำรุงรักษาและประสิทธิภาพ
  • ข้อความสำคัญคือ “ยิ่งเป็นนักพัฒนาที่ขี้เกียจ ก็ยิ่งควรใช้องค์ประกอบให้ถูกต้อง”
    โดย เน้นความสำคัญของนิสัยการพัฒนาที่หลีกเลี่ยงความซับซ้อนที่ไม่จำเป็น และใช้ประโยชน์จากความสามารถพื้นฐานที่มีอยู่แล้ว

7 ความคิดเห็น

 
come2mecome 2025-11-04

เป็นบทความที่ดีมากครับ ใจความสำคัญของเนื้อหาสามารถสรุปได้ว่า "เราควรใช้แท็ก HTML อย่างมีความหมาย" หากให้ div (หรือแท็กอื่น) ทำหน้าที่รองรับเหตุการณ์คลิก ผมคิดว่ามันก็ไม่ได้ต่างอะไรจากสมัยก่อนที่เราใช้แท็ก table จัดเลย์เอาต์เลย

 
carnoxen 2025-11-11

แน่นอนว่าใส่พร็อพเพอร์ตี aria-* ลงไปก็อาจทำให้ชัดเจนขึ้นได้ แต่ถ้าต้องลำบากขนาดนั้นก็ใช้แท็กที่เหมาะสมไปเลยดีกว่า 555555

 
roxie 2025-11-06

คิดถึงจังเลย 555

 
carnoxen 2025-11-02

เว็บไซต์หน่วยงานราชการบ้านเราดูเหมือนจะใช้ &lt;a&gt; กันเยอะมาก...

 
GN⁺ 2025-11-02
ความเห็นจาก Hacker News
  • หนึ่งในเรื่องที่ฉันไม่ชอบคือเว็บไซต์ที่ทำ navigation ด้วย ตัวจัดการ onclick
    แค่ใช้แท็ก <a> ทุกอย่างก็ทำงานได้ดีเองโดยอัตโนมัติ ทั้งการเปิดแท็บใหม่ การทำงานร่วมกับอุปกรณ์ช่วยการเข้าถึง เมนูคลิกขวา ฯลฯ
    ถ้าเป็น navigation ก็ควรใช้ลิงก์แทน JavaScript soup

    • ในช่วงไม่กี่ปีที่ผ่านมา มีกรณีที่ทำแบบนี้เพิ่มขึ้น
      น่าจะเป็นเพราะอิทธิพลของเฟรมเวิร์กหรือไม่ก็ความไม่ใส่ใจ
      ถึงอย่างนั้น วิธีดั้งเดิม ก็แทบจะดีกว่าในแง่ UX เสมอ
      ฉันหวังว่าคนที่พยายามมาแทนที่แท็ก <a> จะเจอกับความไม่สะดวกเล็กน้อยบ้าง
    • ฉันคิดว่าปัญหาคือคนที่เริ่มจาก React กระโดดไปทำ “ของสนุก” เลยโดยไม่ได้เรียนรู้ แนวคิด HTML พื้นฐาน
      คนพวกนี้สร้างแพตเทิร์นที่ผิดไว้ แล้วนักพัฒนารุ่นถัดมาก็ทำตามกันต่อ
      แทบไม่มีกรณีไหนเลยที่จำเป็นต้องแต่ง <div> ให้เป็นปุ่ม
    • ควรเลิกใช้การเลื่อนแบบอิง JS ด้วย
      ฉันใช้ปุ่มกลางเมาส์เพื่อเลื่อนบ่อยมาก แต่หลายเว็บทำให้มันพัง
    • พอได้ยินเรื่องนี้ก็ทำให้นึกถึง ตัวตรวจลิงก์ของ Microsoft Office 365
      ถ้าคลิกซ้ายจะพาไปหน้าตรวจสอบความปลอดภัย แต่ถ้าคลิกกลางจะเข้าไปปลายทางเลย
    • แม้แต่ในโปรเจกต์ React ที่เพิ่งร่วมทำล่าสุด navigation ทั้งหมดก็ทำด้วย onClick
      แม้แต่องค์ประกอบที่จริง ๆ แล้วก็คือลิงก์ก็ยังถูกจัดการด้วย click handler ทั้งหมด เลยไม่เข้าใจจริง ๆ
  • ปุ่มส่วนใหญ่ควรระบุ type="button" ให้ชัดเจน
    ค่าเริ่มต้นคือ submit ดังนั้นถ้าอยู่ในฟอร์มก็จะ submit อัตโนมัติ
    น่าจะมีนักพัฒนาบางคนไม่รู้เรื่องนี้เลยใช้ <div> แทน

    • ฉันคิดว่าจากบทความยาว ๆ ของ OP ข้อมูล แกนสำคัญ นี้หายไป
      ปุ่มที่ใช้ type เริ่มต้นมีพฤติกรรมแปลก ๆ และบางครั้งก็ข้าม JS handler ไปเลย
    • ค่าเริ่มต้นนั้นเทียบเท่ากับ <input type="submit"> และต่างจาก <button>
    • ฉันเองก็ เรียนรู้เรื่องนี้จากประสบการณ์ตรง
    • ถ้าใช้ <div> ก็หลีกเลี่ยงปัญหา type="submit" ได้
      <div> ว่างเปล่ามาตั้งแต่ต้น จึงใส่เฉพาะความสามารถที่ต้องการได้ และแก้ทีหลังก็ง่าย
      ในทางกลับกัน <button> ถ้าจะเข้าใจพฤติกรรมเริ่มต้นก็ต้องไปเปิดเอกสารดู
      สุดท้ายแล้วมันคือทางเลือกระหว่าง การควบคุมแบบ explicit กับความสามารถที่มีมาในตัว
  • อยากให้บทความขยายไปในทิศทางของ “ใช้ element HTML ที่สร้างมาเพื่อจุดประสงค์นั้นไปเลย
    นักพัฒนา SPA จำนวนมากไม่ค่อยเข้าใจความหมายของ element HTML เลยสร้างล้อขึ้นมาใหม่ทุกครั้ง

    • ถ้า element ต่าง ๆ จัดสไตล์ได้ง่ายกว่านี้ ก็คงดี
      อย่างเช่น date picker เริ่มต้นนั้นหน้าตาแย่มากจนต้องเอาแบบอิง JS มาแทน
    • คำว่า “ใช้แพลตฟอร์มตามที่มันเป็น” ถูกพูดถึงบ่อยในฝั่งฟรอนต์เอนด์หลัง HTML5 แต่ก็ยังไม่แพร่ไปทุกที่
    • ในความเป็นจริง นักพัฒนาส่วนใหญ่แทบไม่รู้จัก element HTML เลย และพยายาม แก้ทุกอย่างด้วย DIV ตัวเดียว
    • ราวปี 2010 ปุ่มในแต่ละเบราว์เซอร์มีสไตล์ต่างกัน เลยต้องทำเอง
      นั่นจึงเป็นที่มาของปุ่มแบบ custom
  • ทุกวันนี้มีคนรุ่นหนึ่งที่ต้องคอยกดไปทั่วหน้าจอเพื่อหาว่าตรงไหนคลิกได้
    เมื่อ 10 ปีก่อนมีใครบางคนทำให้ การลากลิงก์ สำคัญกว่าการเลือกข้อความ จนตอนนี้แทบจะเลือกข้อความไม่ได้เลย
    ถ้าจะซ่อมเรื่องนี้อาจต้อง fork เบราว์เซอร์

    • ฉันมีนิสัย ลากลิงก์เพื่อเปิดเป็นแท็บพื้นหลัง
      ถ้ากด Alt (หรือ Option) ค้างไว้ ก็จะเลือกข้อความในลิงก์ได้
    • บน iOS เวลาพยายามคัดลอกเบอร์โทรศัพท์แล้วมันโทรออกอัตโนมัติก็น่ารำคาญในทำนองเดียวกัน
      เป็นพฤติกรรมที่ไม่ต้องการจริง ๆ
    • ข้อความที่เลือกไม่ได้ทำให้ฉันแทบคลั่ง
      ถ้าใช้แอป TextSniper บน macOS จะเลือกพื้นที่แล้ว OCR เพื่อคัดลอกข้อความได้
      เลยทำให้ Google Analytics พอใช้งานได้ขึ้นมาหน่อย
    • ฉันเองก็เจอบ่อยที่พยายามเลือกข้อความบางส่วนในลิงก์แล้วทำไม่ได้
      ปัญหาแบบนี้ควรถูกพูดถึงให้บ่อยกว่านี้
    • มีส่วนขยายเบราว์เซอร์สำหรับเลือกข้อความในลิงก์ด้วย
      เมื่อก่อนชื่อ Select Like A Boss ตอนนี้ชื่อ Drag-Select Link Text
  • ใน stylesheet เริ่มต้นของ Chrome มี button {align-items: flex-start} อยู่ ทำให้ฉันงงกับ บั๊กขนาด flexbox อยู่นานมาก
    ถึงอย่างนั้นก็ยังพยายามใช้ element HTML ที่ถูกต้องเท่าที่ทำได้ แต่ใน side project เล็ก ๆ บางครั้ง <div> ก็สะดวกกว่า

    • พร็อพเพอร์ตี appearance: none มีประโยชน์มากสำหรับรีเซ็ตสไตล์ปุ่ม
      ฉันสร้างคลาส .unbuttonify ไว้เพื่อให้มันทำงานเหมือนปุ่มแต่หน้าตาเป็นอย่างอื่น
    • อยากเน้นว่านักพัฒนาฟรอนต์เอนด์ควรรู้ พื้นฐาน CSS
  • ควรใช้ element ต่าง ๆ ให้ตรงกับเจตนาเดิมของมัน ให้มากที่สุด

  • ฉันมีข้อบ่นเกี่ยวกับปุ่มอยู่สองอย่าง
    อย่างหนึ่งคือสุดท้ายแล้วก็ต้อง จัดสไตล์ใหม่อยู่ดี
    อีกอย่างคือคำเตือนว่าห้ามซ้อนปุ่มกัน
    ในทางปฏิบัติมันเจอบ่อยพอสมควร

  • LLM มักสร้าง แพตเทิร์นที่ผิด แบบนี้บ่อย
    หลายครั้งมันมองข้ามความสามารถพื้นฐานของเบราว์เซอร์แล้วไปทำให้ซับซ้อน
    ฉันมักสั่ง Claude ให้ทำโค้ดแบบนี้ให้ง่ายลง
    ใน TypeScript มันก็มีแนวโน้มจะทำรูปแบบการจัดการ error แปลก ๆ ด้วย

    • LLM เขียนโค้ด ได้เก่ง แต่ยังขาด เซนส์ด้านวิศวกรรมซอฟต์แวร์
    • ด้วยธรรมชาติของการทำนายโทเค็น LLM จึงเลือกแพตเทิร์นที่ซับซ้อนบ่อยกว่า
  • ฉันพยายาม ใช้ปุ่มเป็นค่าเริ่มต้น ให้มากที่สุด
    แต่ถ้ากรณีไหนจริง ๆ แล้วควรทำงานเหมือนลิงก์ ก็จะใช้แท็ก <a>

    • ฉันมักแยกแบบนี้: ถ้า URL เปลี่ยนคือลิงก์ ถ้าไม่เปลี่ยนคือปุ่ม
    • ถ้าเป็น “ไฮเปอร์ลิงก์ที่ใช้ย้ายภายในเว็บแอป” มันก็คือแท็ก <a>
  • ฉันสงสัยว่าทำไมถึงมีคนเสนอให้ใช้ <div>

    • น่าจะเป็นเพราะ <div> เอื้อต่อการ custom หน้าตา แบบแปลก ๆ มากกว่า
      เลยลงเอยด้วยสิ่งที่ทั้งไม่ดูเหมือนปุ่มและไม่ทำงานเหมือนปุ่ม
    • ตัวอย่างเช่นเว็บอย่าง TV Tropes เคยทำรายการยาว ๆ แบบ “โฟลเดอร์” ที่พับและขยายได้ด้วย <div onclick>
    • เหตุผลที่พบบ่อยที่สุดคือ ขี้เกียจ override สไตล์ปุ่มเริ่มต้น
 
nemorize 2025-11-02

ใช้ปุ่มเถอะ

background, border, outline, appearance, -webkit-appearance, cursor
มีสไตล์ชีตเริ่มต้นที่ต้องเขียนทับเยอะเกินไปเลย ฮือๆ

 
rtyu1120 2025-11-03

ก็เลยมี CSS Reset ไงล่ะ