🧰 ของที่ใช้ตรวจในบทนี้ (รันวันที่ 27 สิงหาคม 2026)
Chromium 148 (engine ของ Chrome / Edge / Brave) บน macOS
วัดด้วย getComputedStyle() และ getBoundingClientRect() ของจริงในหน้าเปล่า
ตัวเลขทุกตัวในบทนี้มาจากการวัดจริง ไม่ได้เขียนจากความจำ และกล่องสีเทาที่เขียนว่า "ผลลัพธ์จริง" คือหน้าเว็บย่อ ๆ ที่เบราว์เซอร์ของคุณเรนเดอร์เดี๋ยวนี้ จากโค้ดชุดเดียวกับกล่องดำข้างบนมันเป๊ะ ๆ — ไม่ใช่ภาพถ่าย
1 · เส้นแบ่งเส้นเดียวที่อธิบายได้ทั้งบท
แท็กใน HTML แบ่งพฤติกรรมตอนวางบนหน้าจอออกเป็นสองพันธุ์ใหญ่ ๆ:
- พันธุ์กินทั้งบรรทัด — วางแล้วยึดความกว้างทั้งแถว และตัวถัดไปต้องลงบรรทัดใหม่
แม้ที่ว่างด้านขวาจะเหลือเฟือ · เช่น
<div><p><h1><header><main><footer> - พันธุ์แทรกในบรรทัด — วางแล้วกว้างเท่าเนื้อข้างในเท่านั้น
และตัวถัดไปต่อท้ายในบรรทัดเดิม · เช่น
<span><img><a><strong>
ไม่ต้องเชื่อ — ดูของจริง โค้ดข้างล่างนี้ใส่พื้นหลังสีให้ทุกตัวเพื่อให้เห็น "ขอบเขต" ของแต่ละกล่อง:
<style>
.a { background: #cfe3ff; }
.b { background: #ffe0b3; }
</style>
<div class="a">div ตัวที่หนึ่ง</div>
<div class="b">div ตัวที่สอง</div>
<span class="a">span ตัวที่หนึ่ง</span>
<span class="b">span ตัวที่สอง</span>
สังเกตสามอย่าง:
① แถบสีของ div ลากยาวจนสุดขอบขวา ทั้งที่ข้อความสั้นนิดเดียว
② div สองอันอยู่คนละบรรทัด โดยไม่ต้องสั่งอะไรเลย
③ span สองอันอยู่บรรทัดเดียวกัน และแถบสีหุ้มพอดีตัวอักษร
ตัวเลขที่ผมวัดได้จริงในหน้าเปล่ากว้าง 482px:
div ทั้งสองอันกว้าง 482px เท่ากันเป๊ะและอยู่คนละแถว ·
span สองอันกว้าง 95px กับ 94px (เท่าความยาวข้อความ) และอยู่แถวเดียวกัน
นึกถึงสมุดจดที่มีเส้นบรรทัด
· พันธุ์กินทั้งบรรทัด คือย่อหน้า — เขียนจบย่อหน้าหนึ่ง
คุณขึ้นบรรทัดใหม่เสมอ ไม่ว่าย่อหน้านั้นจะยาวสิบบรรทัดหรือมีคำเดียว
และย่อหน้านั้น "จอง" ความกว้างทั้งหน้ากระดาษไว้แล้ว ใครมาเขียนต่อข้าง ๆ ไม่ได้
· พันธุ์แทรกในบรรทัด คือปากกาไฮไลต์ — คุณระบายทับคำว่า
"สำคัญมาก" กลางประโยค แล้วประโยคยังเป็นประโยคเดิม ไม่มีอะไรถูกดันลงบรรทัดใหม่
แถบสีก็หุ้มแค่คำนั้น ไม่ลากยาวไปทั้งบรรทัด
ที่ไม่เหมือนกัน: ปากกาไฮไลต์ระบายทับอะไรก็ได้
รวมทั้งลากทับทั้งย่อหน้ารวดเดียว — แต่ HTML มีกติกาเขียนไว้ว่าแท็กไหนอุ้มอะไรได้บ้าง
และเบราว์เซอร์บังคับใช้กติกานั้นเงียบ ๆ โดยไม่ฟ้อง
(จะเห็นตัวเป็น ๆ ในหัวข้อ 3 ตอนที่เอา <div> ไปใส่ใน <p>)
และปากกาไฮไลต์ "ความสูง" เท่าบรรทัดเสมอ สั่งให้สูงขึ้นไม่ได้ —
ตรงนี้ analogy พูดถูกพอดี และเป็นกับดักข้อใหญ่ของ <span> ที่จะเจอในหัวข้อ 5
- block-level element
- ชื่อจริงของ "พันธุ์กินทั้งบรรทัด" · ในภาษา CSS คือ element ที่
displayเป็นblock· พูดกับ senior ว่า “ตัวนี้เป็น block เลยดันบรรทัดใหม่” จะสื่อกว่า “มันตกลงไปข้างล่างเอง” - inline element
- ชื่อจริงของ "พันธุ์แทรกในบรรทัด" ·
display: inline· พิมพ์บอก AI ได้ว่า “this element is inline, so width and height are ignored — what should I use instead?” แล้วมันจะเสนอinline-blockหรือflexให้เอง - normal flow
- กติกาเริ่มต้นที่เบราว์เซอร์ใช้วาง element เรียงกันลงมา ก่อนที่คุณจะไปสั่ง
flexหรือgridทับ · เจอ layout เพี้ยน ให้ถามตัวเองก่อนว่า “ตอนนี้ยังเป็น normal flow อยู่ไหม” เพราะกฎ block/inline ในบทนี้ใช้ได้เฉพาะตอนยังเป็น normal flow
2 · <div> — กล่องเปล่าที่ไม่มีความหมาย
สไลด์หน้า 14 นิยามไว้ตรง ๆ ว่า "a plain box for grouping elements when no semantic meaning is needed"
ท่อนที่สำคัญที่สุดคือท่อนหลัง — <div> ไม่ได้แปลว่า "กล่อง" เฉย ๆ
มันแปลว่า "กล่องที่ผมยืนยันว่าไม่มีความหมายอะไรเป็นพิเศษ"
โค้ดจากสไลด์หน้า 14 ตรง ๆ:
<div class="title">
<p>Hello, My name is Joey Wasin</p>
<p>I'm a software developer</p>
</div>
Hello, My name is Joey Wasin
I'm a software developer
หน้าตาที่ได้เหมือนกันเป๊ะกับตอนที่ไม่มี <div> ครอบ —
ลบบรรทัดแรกกับบรรทัดสุดท้ายทิ้ง แล้วเหลือแค่ <p> สองอัน ก็ได้ภาพเดียวกัน
แปลว่า <div> ในตัวมันเอง ไม่ทำอะไรกับหน้าตาเลยสักอย่าง
ประโยชน์ของมันมีสองข้อล้วน ๆ:
- มีที่ให้แปะ
class— เพื่อให้ CSS ในบทหน้าเล็งกลุ่มนี้ทั้งกลุ่มได้ทีเดียว - มัดของให้อยู่ด้วยกัน — พอย้าย ก็ย้ายทั้งก้อน ไม่ต้องไล่ย้ายทีละ
<p>
<div> ไม่ต้องเสียเงินซื้อ คนเลยใส่ซ้อนกันห้าชั้นโดยไม่รู้ตัว
ราคาที่จ่ายไม่ได้อยู่ที่ความเร็ว — อยู่ที่วันที่คุณกลับมาอ่านโค้ดตัวเองแล้วไม่รู้ว่าชั้นไหนทำอะไร
กฎง่าย ๆ ที่ใช้ได้จริง: ใส่ <div> ตอนที่คุณตอบได้ว่าจะแปะ class อะไรให้มัน
ถ้ายังตอบไม่ได้ ยังไม่ต้องใส่
3 · <p> — ย่อหน้า และกับดักที่ทุกคนโดนครั้งแรก
สไลด์หน้า 15 บอกว่า <p> คือ "a block of text content"
คำว่า text content ตรงนี้ไม่ใช่คำบรรยายสวย ๆ — มันคือข้อบังคับ
ที่เขียนไว้ใน spec ของ HTML และเบราว์เซอร์บังคับใช้จริงแบบเงียบ ๆ
ทายก่อนดู — ผมใส่กรอบสีให้ <p> เป็นแดง และ <div> เป็นน้ำเงิน
แล้วเอา <div> ไปวางไว้กลาง <p>:
<style>
p { border: 2px solid #d33; padding: 6px; }
div { border: 2px solid #06c; padding: 6px; }
</style>
<p>ข้อความก่อน<div>ฉันคือ div</div>ข้อความหลัง</p>
คุณจะเห็นกรอบแดงกี่กรอบ? และกรอบน้ำเงินอยู่ข้างในหรือข้างนอกกรอบแดง?
(คำใบ้: คำตอบที่ถูกมีตัวเลขที่คุณไม่ได้พิมพ์ลงไปเองอยู่ด้วย)
กรอบแดง 2 กรอบ และกรอบน้ำเงินอยู่ข้างนอก — ทั้งที่ในโค้ดคุณเขียนแค่ <p> เดียว
ผมอ่าน DOM ที่เบราว์เซอร์สร้างขึ้นจริงออกมาด้วย innerHTML ได้แบบนี้เป๊ะ ๆ:
<p>ข้อความก่อน</p><div>ฉันคือ div</div>ข้อความหลัง<p></p>
อ่านทีละก้าวว่าเบราว์เซอร์คิดอะไร:
① เจอ <div> ทั้งที่ยังอยู่ใน <p> →
มันแอบปิด </p> ให้เอง เพราะ <p> รับ block ไว้ข้างในไม่ได้
② <div> จึงกลายเป็นพี่น้องของ <p> ไม่ใช่ลูก
③ คำว่า "ข้อความหลัง" หลุดออกมาลอย ๆ ไม่ได้อยู่ใน <p> ไหนเลย
④ พอเจอ </p> ที่คุณพิมพ์ไว้ ตอนนั้นไม่มี <p> เปิดค้างอยู่แล้ว
เบราว์เซอร์เลยสร้าง <p></p> เปล่า ๆ ขึ้นมาปิดให้ — นั่นคือกรอบแดงอันที่สอง
จุดที่โหดคือ ไม่มี error ไม่มีคำเตือน ไม่มีอะไรแดงในคอนโซล
หน้ายังเปิดได้ปกติ · คุณจะรู้ตัวก็ตอนที่เขียน CSS ว่า "ทำไม padding ที่ให้ p ไม่ครอบ div"
หรือตอนที่ p:last-child ไปโดนกรอบเปล่าที่คุณไม่รู้ว่ามีอยู่
และนี่คือของจริงที่เบราว์เซอร์คุณเรนเดอร์เดี๋ยวนี้ — โค้ดชุดเดียวกับข้างบนเป๊ะ:
ข้อความก่อน
ท่าที่ถูกคือสลับข้าง — เอา <div> ครอบ <p> ไม่ใช่ <p> ครอบ <div>
ซึ่งก็คือสิ่งที่สไลด์หน้า 14 ทำอยู่แล้วพอดี:
✗ p ครอบ div
<p>
<div>…</div>
</p>
เบราว์เซอร์แอบแก้ให้ ได้ DOM ที่ไม่ตรงกับที่พิมพ์
✓ div ครอบ p
<div>
<p>…</p>
</div>
DOM ที่ได้ตรงกับที่พิมพ์ทุกตัวอักษร
- content model
- กฎที่ spec ของ HTML เขียนไว้ว่า "แท็กนี้อนุญาตให้มีอะไรอยู่ข้างในได้บ้าง" ·
<p>มี content model ที่รับได้แค่ข้อความกับ inline element · ถาม AI ได้ตรง ๆ ว่า “what is the content model of the p element in the HTML spec?” - phrasing content
- ชื่อกลุ่มของ "ของที่วางในประโยคได้" — ข้อความ ·
<span>·<a>·<strong>·<img>· คือกลุ่มเดียวที่<p>ยอมรับ - error recovery (ของ HTML parser)
- HTML ไม่มี syntax error — เจอโครงผิด parser จะ "ซ่อมให้" ตามกฎที่ spec เขียนไว้แทนที่จะฟ้อง · ประโยคที่ใช้ได้จริง: “มันไม่ error หรอก HTML parser มัน recover ให้ — ต้องไปดู DOM จริงใน DevTools” เป็นคำตอบของอาการ "โค้ดถูกแต่หน้าไม่ตรง" ครึ่งหนึ่งของโลก
4 · <h1> ถึง <h6> — ลำดับความสำคัญ ไม่ใช่ขนาดตัวอักษร
สไลด์หน้า 16 เขียนว่า "six levels of headings to prioritize the level of importance"
ประโยคนี้ตรงมาก แต่พอเห็นภาพจริงคนมักอ่านเป็นอย่างอื่น เพราะขนาดตัวอักษรบังเอิญเรียงจากใหญ่ไปเล็กพอดี
นี่คือขนาดเริ่มต้นจริงที่ผมวัดได้ในหน้าเปล่า (ไม่มี CSS อะไรเลย):
| แท็ก | ขนาดตัวอักษรเริ่มต้น | เทียบกับข้อความปกติ (16px) |
|---|---|---|
<h1> | 32px | 2 เท่า |
<h2> | 24px | 1.5 เท่า |
<h3> | 18.72px | 1.17 เท่า |
<h4> | 16px | เท่ากันพอดี |
<h5> | 13.28px | เล็กกว่า |
<h6> | 10.72px | เล็กกว่ามาก |
สังเกต <h4> ลงไป — ตัวเท่าหรือเล็กกว่าข้อความธรรมดา
ถ้า "หัวข้อ" แปลว่า "ตัวใหญ่" <h5> กับ <h6> ก็จะไม่มีเหตุผลให้มีอยู่เลย
แถมขนาดพวกนี้เขียนทับได้หมดด้วย CSS บรรทัดเดียว:
<style>
.tiny { font-size: 12px; }
.huge { font-size: 30px; }
</style>
<h1 class="tiny">ฉันคือ h1 ที่ถูกสั่งให้เล็ก</h1>
<h6 class="huge">ฉันคือ h6 ที่ถูกสั่งให้ใหญ่</h6>
ฉันคือ h1 ที่ถูกสั่งให้เล็ก
ฉันคือ h6 ที่ถูกสั่งให้ใหญ่
ตาเห็น <h6> ใหญ่กว่า <h1> ชัด ๆ
แต่โปรแกรมยังอ่านว่า <h1> คือหัวข้อระดับ 1 และ <h6> คือระดับ 6 เหมือนเดิม
เลข 1–6 จึงไม่ใช่ขนาด มันคือความลึกของสารบัญ
เอกสารราชการเขียนหัวข้อเป็น 1 → 1.1 → 1.1.1
เลขพวกนี้ไม่ได้บอกว่าตัวอักษรต้องใหญ่แค่ไหน มันบอกว่าข้อไหนอยู่ใต้ข้อไหน
<h1> คือ "1" · <h2> คือ "1.1" · <h3> คือ "1.1.1"
และเหมือนรายงานที่ดี — หนึ่งหน้ามี "ข้อ 1" ใหญ่สุดได้อันเดียว คือ <h1> ที่เป็นชื่อเรื่องของหน้านั้น
ที่ไม่เหมือนกัน: ในรายงานกระดาษ ถ้าคุณข้ามจาก "1" ไป "1.1.1" เลย
คนอ่านยังเดาถูกว่ามันอยู่ใต้ข้อ 1 เพราะเห็นตัวเลขเต็ม ๆ พิมพ์อยู่ตรงนั้น
แต่ใน HTML ไม่มีเลขให้เห็น โปรแกรมอ่านหน้าจอได้ยินแค่ว่า "หัวข้อ ระดับสาม" ลอย ๆ
แล้วต้องเดาเองว่ามันหายไปไหนหนึ่งชั้น — ข้ามระดับใน HTML จึงแพงกว่าข้ามเลขในรายงานเยอะ
ลองไล่ลำดับหัวข้อในโค้ดของสไลด์: h1 → h2 → h2 → h4
ไม่มี h3 — <h4>Dec 2023 – Present</h4> โผล่ขึ้นมาใต้ <h2>Work Experience</h2> ตรง ๆ
หน้าเว็บพังไหม: ไม่พัง ตัวอักษรก็ดูดีด้วยซ้ำ (เพราะ h4 ขนาดพอดี ๆ)
แต่สารบัญที่โปรแกรมอ่านหน้าจอสร้างขึ้นจะมีชั้นที่หายไปหนึ่งชั้น
ถ้าอยากได้ขนาดของ h4 แต่ระดับของ h3 ทางที่ถูกคือใช้ <h3> แล้วสั่ง
font-size เอา — เลือกระดับตามโครงเรื่อง แล้วค่อยจัดขนาดด้วย CSS ทีหลังเสมอ
5 · <span> — กล่องเปล่าแบบ inline
สไลด์หน้า 17 บอกว่า "Like a <div> element, but used inside a sentence"
ถ้าเทียบกับหัวข้อ 1 ก็แปลง่าย ๆ ว่า: <span> คือ <div> ที่เกิดมาเป็นพันธุ์แทรกในบรรทัด
หน้าที่เหมือนกันเป๊ะ (เป็นที่แปะ class) ต่างกันแค่พันธุ์
โค้ดจากสไลด์หน้า 17:
<p>
Hello, My name is
<span class="joey-name" style="color: olive">Joey Wasin</span>
</p>
Hello, My name is Joey Wasin
ชื่อเปลี่ยนสีเป็นเขียวมะกอกโดยที่ประโยคยังเป็นประโยคเดียว ไม่มีอะไรถูกดันลงบรรทัดใหม่ —
นี่คือทั้งหมดที่ <span> มีให้
ทีนี้กับดักตัวจริง ลองสั่ง width กับ height ให้มันดู
โค้ดข้างล่างใช้ class เดียวกันเป๊ะกับทั้ง <div> และ <span>:
<style>
.box { background: #cfe3ff; width: 120px; height: 60px; }
</style>
<div class="box">div ที่สั่ง 120x60</div>
<span class="box">span ที่สั่ง 120x60</span>
<div> ได้กล่อง 120×60 ตามสั่ง · <span> ไม่สนใจทั้งสองค่า
ผมวัดของจริง: div ได้ 120×60 เป๊ะ · span ได้ 118×19
ซึ่งคือ "เท่าตัวอักษรพอดี" ทั้งกว้างและสูง
และเหมือนเดิม — ไม่มี error ไม่มีคำเตือน CSS ก็ยังอยู่ในไฟล์ครบทุกตัวอักษร มันแค่ไม่มีผล
แล้วถ้าอยากได้ทั้งสองอย่าง — อยู่ในบรรทัดเหมือน span แต่สั่งขนาดได้เหมือน div?
มีพันธุ์ที่สามชื่อ display: inline-block · จะเจอเต็ม ๆ ในบทเรื่อง CSS layout
ตอนนี้แค่รู้ว่ามีทางออก พอ ไม่ต้องจำ
และมีข้อยกเว้นหนึ่งตัวที่จะเจอในหัวข้อ 7: <img> เป็น inline เหมือน
<span> แต่สั่ง width/height ได้ผลจริง
เพราะเนื้อของมันเป็นไฟล์ภาพจากข้างนอก ไม่ใช่ตัวอักษรในหน้า (ศัพท์ของมันคือ replaced element) ·
กฎ "inline แล้วสั่งขนาดไม่ได้" จึงใช้กับพวกที่เนื้อเป็นข้อความอย่าง <span>
<a> <strong> เท่านั้น
6 · <header> <main> <footer> — ทำไมไม่ใช้ <div> ทุกอันไปเลย
สไลด์หน้า 18 บอกว่าสามตัวนี้ "represent areas of content in page"
คำถามที่สไลด์ไม่ได้ตอบและเป็นคำถามที่ถูกต้องที่สุดคือ: "แล้วมันต่างจาก <div> ตรงไหน"
คำตอบตรง ๆ ที่ต้องยอมรับก่อน คือ ตรงหน้าจอ: ไม่ต่างเลยแม้แต่พิกเซลเดียว ดูเอง:
<style>
header, main, footer, div { background: #eef1f5; margin-bottom: 4px; }
</style>
<header>ฉันคือ header</header>
<main>ฉันคือ main</main>
<footer>ฉันคือ footer</footer>
<div>ฉันคือ div ธรรมดา</div>
สี่แถบเท่ากันหมด ผมวัดได้ 482px ทั้งสี่อัน เรียงลงมาเหมือนกันเป๊ะ
และ display ของทั้งสี่คือ block เท่ากัน
ความต่างทั้งหมดจึงอยู่ในที่ที่ตามองไม่เห็น — และนั่นคือประเด็นทั้งหมดของหัวข้อนี้
ย้ายบ้านแล้วมีกล่องกระดาษ 20 ใบวางอยู่กลางห้อง เหมือนกันหมดทุกใบ
· ถ้าไม่เขียนอะไรข้างกล่อง = <div> ทั้งหมด — จะหาแก้วน้ำ ต้องเปิดไล่ทีละใบ
· ถ้าเขียนว่า "ครัว" "ห้องนอน" "เอกสารสำคัญ" = <header> <main> <footer>
— กล่องหน้าตาเหมือนเดิมทุกอย่าง แต่เดินตรงไปหยิบใบที่ต้องการได้เลย
ที่ไม่เหมือนกัน: กล่องย้ายบ้านคุณเปิดดูเองได้ ไม่มีป้ายก็แค่เสียเวลา
แต่คนที่ใช้โปรแกรมอ่านหน้าจอ (screen reader) "เปิดดู" ทั้งหน้าพร้อมกันไม่ได้ —
เขาได้ยินทีละชิ้นเรียงจากบนลงล่างเท่านั้น
ป้าย <main> คือทางลัดเดียวที่เขามีเพื่อกระโดดข้ามเมนู 30 ลิงก์ตรงไปที่เนื้อหา
ไม่มีป้าย = ต้องฟังเมนูใหม่ทั้งชุดทุกหน้าที่เปิด
ผลที่ตามมาในทางปฏิบัติมีสามข้อ และทั้งสามข้อไม่มีข้อไหนโผล่บนหน้าจอเลย:
| ใครได้ประโยชน์ | ได้อะไร | ถ้าใช้ <div> แทน |
|---|---|---|
| ผู้ใช้ screen reader | กระโดดตรงไป <main> ได้ในคำสั่งเดียว |
ต้องไล่ฟังตั้งแต่ต้นหน้าใหม่ทุกครั้ง |
| Google และ search engine | รู้ว่าเนื้อหาจริงของหน้าอยู่ตรงไหน แยกจากเมนูกับท้ายหน้า | ต้องเดาเอง ซึ่งเดาผิดได้ |
| คนที่มาแก้โค้ดต่อจากคุณ | เห็นโครงหน้าครบใน 3 บรรทัด ไม่ต้องไล่อ่าน class |
ต้องอ่าน <div class="wrapper-outer"> แล้วเดาเอง |
ก่อนพิมพ์ <div> ให้ถามหนึ่งคำถาม: "ก้อนนี้มีชื่อเรียกในภาษาคนไหม"
ถ้ามี (หัวเรื่องหน้า · เนื้อหาหลัก · ท้ายหน้า · เมนู · บทความ) → ใช้แท็กที่มีชื่อนั้น
ถ้าไม่มี ("ก้อนที่ผมอยากจัดให้อยู่ด้วยกันเฉย ๆ") → <div> คือคำตอบที่ถูก และไม่ต้องรู้สึกผิด
<div> ไม่ใช่ของแย่ — มันแย่เฉพาะตอนที่มีแท็กที่ตรงกว่าให้ใช้แล้วไม่ใช้
- semantic HTML
- การเลือกแท็กตามความหมายของเนื้อหา ไม่ใช่ตามหน้าตาที่อยากได้ ·
ประโยคที่ใช้ได้ใน code review: “ตรงนี้เป็นเนื้อหาหลักของหน้า ใช้
<main>แทน<div>ดีกว่าไหม” - landmark
- "จุดสังเกต" ที่ screen reader ใช้ทำเมนูลัดให้ผู้ใช้ ·
<header><main><footer><nav>กลายเป็น landmark ให้เองโดยไม่ต้องตั้งค่าอะไร · พิมพ์ถาม AI ได้ว่า “list the landmark roles my page exposes and tell me which ones are missing” - accessibility (a11y)
- การทำให้เว็บใช้ได้กับคนที่ใช้ไม่เหมือนเรา — ตาบอด · มือไม่สะดวก · เน็ตช้า · เขียนใน commit message ได้ว่า “a11y: replace layout divs with header/main/footer landmarks” เป็นคำที่ทีมฝั่งหน้าบ้านใช้กันทุกวัน
7 · <img> — และคำว่า alt ที่ไม่ใช่ของประดับ
สไลด์หน้า 19 บอกสองเรื่อง: ใช้ใส่รูป และ มันเป็น "self-closing tag" คือไม่มีแท็กปิด
เหตุผลง่ายมาก — แท็กปิดมีไว้บอกว่า "เนื้อข้างในจบตรงนี้" แต่ <img> ไม่มีเนื้อข้างใน
ทุกอย่างของมันอยู่ใน attribute หมด จึงไม่มีอะไรให้ปิด
เขียนได้ทั้ง <img …> และ <img … /> — เบราว์เซอร์เข้าใจเหมือนกัน สไลด์ใช้แบบมี />
ในบทนี้ผมไม่ใช้ไฟล์รูปจากอินเทอร์เน็ต แต่ใช้รูปที่เขียนด้วยตัวอักษรล้วน ๆ ฝังอยู่ใน src เลย
(เรียกว่า data URI) — ก็อปไปวางได้ ใช้ได้แม้ไม่มีเน็ต:
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Crect width='64' height='64' rx='12' fill='%232f6feb'/%3E%3C/svg%3E"
alt="สี่เหลี่ยมมุมมนสีน้ำเงิน" width="64" height="64">
<h1>Work Experience</h1>
Work Experience
สังเกตว่ารูปกับหัวข้ออยู่คนละบรรทัด ทั้งที่ในโค้ดเขียนติดกัน —
เพราะ <img> เป็นพันธุ์แทรกในบรรทัด (display: inline) แต่หัวข้อเป็นพันธุ์กินทั้งบรรทัด
จึงดันตัวเองลงมา · กฎจากหัวข้อ 1 ยังใช้ได้อยู่ทุกที่
สไลด์หน้า 19 ใช้ <h2> ตรงนี้ ผมเปลี่ยนเป็น <h1> ในกล่องตัวอย่าง
เพราะกล่องนี้คือหน้าเว็บย่อ ๆ ที่จบในตัว ไม่ได้อยู่ใต้หัวข้ออะไร —
หัวข้อบนสุดของหน้าจึงต้องเป็น <h1> ตามกฎในหัวข้อ 4
พฤติกรรมที่กำลังพิสูจน์ (block ดันบรรทัดใหม่) เหมือนกันทั้ง <h1> ถึง <h6> อยู่แล้ว
แล้ว alt คืออะไรกันแน่
alt คือข้อความที่ใช้แทนรูป เมื่อรูปไม่ได้ทำหน้าที่ของมัน ซึ่งเกิดขึ้นสองสถานการณ์ที่พบบ่อยกว่าที่คิด:
- คนที่มองไม่เห็นรูป — ผู้ใช้ screen reader จะได้ยิน
altอ่านออกมาแทนภาพ - ตอนรูปโหลดไม่ขึ้น — เน็ตหลุด · ไฟล์ถูกลบ · พิมพ์ path ผิด · โดนไฟร์วอลล์บล็อก
เบราว์เซอร์จะเอา
altมาแสดงตรงตำแหน่งรูปแทน
ทายก่อนดู — <img> สามอันนี้ชี้ไปหาไฟล์ที่ไม่มีอยู่จริงทั้งหมด
ต่างกันแค่ alt:
<img src="ไม่มีไฟล์นี้.png" alt="แมวส้มนอนบนคีย์บอร์ด" width="200" height="60">
<img src="ไม่มีไฟล์นี้.png" alt="" width="200" height="60">
<img src="ไม่มีไฟล์นี้.png" width="200" height="60">
ผู้ใช้จะเห็นอะไรตรงตำแหน่งของแต่ละอัน?
และอันที่ไม่มี alt เลย ต่างจากอันที่ alt="" ยังไง?
① มี alt ที่บรรยายภาพ → เห็นข้อความ "แมวส้มนอนบนคีย์บอร์ด" แทนที่รูป
· ผมวัดกล่องได้ 171×26px คือมันหดลงมาเท่าข้อความ ไม่ใช่ 200×60 ตามที่สั่งไว้
② alt="" → เห็นที่ว่างเปล่า · กล่องยังเป็น 200×60 ตามที่สั่ง
แต่ไม่มีตัวอักษรอะไรเลย · screen reader จะข้ามรูปนี้ไปเงียบ ๆ
ซึ่งเป็นสิ่งที่ถูกต้องสำหรับรูปประดับที่ไม่ได้ให้ข้อมูลอะไร (เส้นคั่น · ลายพื้นหลัง)
③ ไม่มี alt เลย → หน้าจอเห็นคล้ายข้อ ② แต่ความหมายตรงข้ามกัน:
screen reader ไม่รู้ว่ารูปนี้ควรข้ามหรือไม่ควรข้าม ส่วนใหญ่จึงเดาโดยอ่านชื่อไฟล์ออกมาดัง ๆ
ผู้ใช้จะได้ยินประมาณ "ไม่มีไฟล์นี้ จุด พีเอ็นจี" ซึ่งไม่ช่วยอะไรเลย
สรุปที่ต้องจำ: alt="" กับ "ไม่ใส่ alt" ไม่ใช่สิ่งเดียวกัน
alt="" แปลว่า "ผมคิดแล้ว รูปนี้ข้ามได้" · ไม่ใส่เลยแปลว่า "ผมลืม"
ทุก <img> ต้องมี alt เสมอ — คำถามมีแค่ว่าจะใส่ว่าอะไร ไม่ใช่จะใส่ไหม
ของจริง — <img> สามอันชุดเดิม เติมแค่กรอบเส้นประเพื่อให้เห็นขอบเขตของแต่ละอัน:
<style>
img { outline: 1px dashed #999; margin-right: 10px; }
</style>
<img src="ไม่มีไฟล์นี้.png" alt="แมวส้มนอนบนคีย์บอร์ด" width="200" height="60">
<img src="ไม่มีไฟล์นี้.png" alt="" width="200" height="60">
<img src="ไม่มีไฟล์นี้.png" width="200" height="60">
อันซ้ายสุดหดเหลือเท่าข้อความที่เขียนใน alt (วัดได้ 171×26)
ส่วนอีกสองอันเป็นกล่องเปล่าขนาด 200×60 เท่ากันเป๊ะ
ทั้งสามเรียงต่อกันไปในบรรทัดเดียว เพราะ <img> เป็น inline ตามกฎในหัวข้อ 1
— ถ้าคุณอ่านบนจอแคบ (หรือย่อหน้าต่างให้แคบลง) จะเห็นมันตัดขึ้นบรรทัดใหม่เมื่อที่ไม่พอ
เหมือนคำในประโยค ซึ่งก็คือพฤติกรรมของ inline เหมือนกัน ไม่ใช่คนละเรื่อง
อันที่สอง (alt="") กับอันที่สาม (ไม่ใส่ alt) ตาแยกไม่ออกเลย —
และนั่นแหละคือประเด็น: ตาแยกไม่ออก แต่ screen reader แยกออก
alt ในสไลด์หน้า 19 เป็นตัวอย่างของ alt ที่ไม่ช่วยอะไร
สไลด์เขียนว่า <img src="./assets/work-icon.png" alt="work-icon" />
alt ตัวนี้ลอกชื่อไฟล์มาเฉย ๆ คนที่มองไม่เห็นจะได้ยินคำว่า "work icon"
ซึ่งบอกแค่ว่า "มีไอคอนอันหนึ่ง" — ไม่ได้บอกว่าไอคอนนั้นสื่ออะไร
ในกรณีนี้ ไอคอนวางอยู่ข้าง ๆ หัวข้อ <h2>Work Experience</h2> ที่พูดเรื่องเดียวกันอยู่แล้ว
คำตอบที่ดีที่สุดจึงคือ alt="" — ปล่อยให้หัวข้อทำหน้าที่ ไม่ต้องให้ผู้ใช้ฟังคำเดิมสองรอบ
คำถามที่ใช้เขียน alt ให้ถูกทุกครั้ง: "ถ้ารูปนี้หายไป ผู้อ่านเสียข้อมูลอะไรไปบ้าง"
· เสียข้อมูล → เขียนข้อมูลนั้นลงไป · ไม่เสียอะไร (เพราะข้อความข้าง ๆ บอกอยู่แล้ว) → alt=""
- void element
- ชื่อจริงของ "self-closing tag" ที่สไลด์พูดถึง — แท็กที่ห้ามมีเนื้อข้างในและห้ามมีแท็กปิด ·
มีอยู่ไม่กี่ตัว:
<img><br><hr><input><meta><link>· ถ้าเผลอเขียน</img>เบราว์เซอร์จะเมินทิ้งเงียบ ๆ ไม่ฟ้อง - alt text
- ข้อความแทนภาพ ไม่ใช่คำบรรยายภาพ · ถาม senior ได้ว่า “รูปนี้เป็น informative หรือ decorative”
เพราะสองคำนี้ตัดสินได้ทันทีว่าจะเขียน
altยาว ๆ หรือใส่alt="" - data URI
- วิธีฝังไฟล์ทั้งไฟล์ลงไปใน
srcตรง ๆ แทนที่จะชี้ไปหาไฟล์ข้างนอก · ดีตรงไม่ต้องโหลดเพิ่ม แต่ใช้กับรูปเล็ก ๆ เท่านั้น เพราะมันบวมและ cache แยกไม่ได้ · บอก AI ว่า “inline this small SVG as a data URI” ได้เลย
8 · ทุกแท็กของบทนี้ในตารางเดียว
| แท็ก | พันธุ์ | ใช้ตอนไหน | จุดพลาดที่เจอบ่อยที่สุด |
|---|---|---|---|
<div> | block | มัดของเป็นก้อน เมื่อไม่มีแท็กที่มีความหมายตรงกว่า | ใส่ซ้อนกันโดยไม่มี class จะแปะ |
<p> | block | ย่อหน้าข้อความ | เอา block ไปใส่ข้างใน แล้วเบราว์เซอร์แอบปิดให้ |
<h1>–<h6> | block | หัวข้อ · เลือกระดับตามโครงเรื่อง | เลือกตามขนาดตัวอักษร แล้วข้ามระดับ |
<span> | inline | จับคำกลางประโยคเพื่อจัดสไตล์ | สั่ง width/height แล้วงงว่าไม่มีผล |
<header> | block | ส่วนหัวของหน้า (หรือของบทความ) | ใช้ <div> แทนทั้งที่ตัวจริงมีอยู่ |
<main> | block | เนื้อหาหลัก · หน้าละหนึ่งอัน | |
<footer> | block | ท้ายหน้า · ลิขสิทธิ์ · ลิงก์ติดต่อ | |
<img> | inline | ใส่รูป · ไม่มีแท็กปิด | ลืม alt หรือใส่ alt เป็นชื่อไฟล์ |
โครงหน้าเว็บที่ประกอบครบจากสไลด์หน้า 18 หน้าตาเป็นแบบนี้ — และนี่คือโครงที่คุณจะใช้ซ้ำไปทั้งคอร์ส
(สไลด์ยังมี <h2>Introduce</h2> คั่นอยู่บนสุดของ <main> ด้วย
ผมตัดออกเพื่อให้เห็นโครงสามชั้นชัด ๆ — ใส่กลับเข้าไปได้เลย):
<header>
<h1>Resume</h1>
</header>
<main>
<div class="joey-title">
<p>Hello, My name is Joey Wasin</p>
<p>I'm a software developer</p>
</div>
</main>
<footer>
<p>© Copyright 2025</p>
</footer>
Resume
Hello, My name is Joey Wasin
I'm a software developer
เห็น © ในโค้ดแล้วออกมาเป็น © ไหม —
นั่นเรียกว่า HTML entity · เป็นวิธีพิมพ์ตัวอักษรที่พิมพ์ตรง ๆ ไม่ได้หรือไม่สะดวก
ตัวที่ใช้บ่อยที่สุดสามตัวคือ < (ได้ <) ·
> (ได้ >) · & (ได้ &)
คุณต้องใช้มันเวลาอยากโชว์โค้ด HTML บนหน้าเว็บ ไม่งั้นเบราว์เซอร์จะนึกว่าเป็นแท็กจริง
ทดสอบความเข้าใจ
1. เขียน <span class="box">ข้อความ</span> แล้วสั่ง CSS ว่า .box { width: 120px; height: 60px; } — จะเกิดอะไรขึ้น?
ผมวัดของจริงจากโค้ดชุดเดียวกันในหัวข้อ 5: div ได้ 120×60 เป๊ะ
ส่วน span ได้ 118×19 ซึ่งเท่าตัวอักษรพอดี — ถูกเมินทั้งสองค่า
ตัวเลือกที่ 4 คือกับดักที่เนียนที่สุด เพราะฟังดูมีตรรกะ (inline = แนวนอน) และมันเกือบถูก —
แต่ค่าที่วัดได้คือ 118px ไม่ใช่ 120px แปลว่า width ก็ไม่ได้มีผลเหมือนกัน
ตัวเลือกที่ 2 ผิดตรงจุดที่เป็นหัวใจของบทนี้ทั้งบท: ฝั่งหน้าบ้านแทบไม่มีอะไรฟ้องคุณ
CSS ที่ไม่มีผลจะอยู่ในไฟล์ต่อไปเงียบ ๆ ไม่ต่างจาก HTML ที่โครงผิดในหัวข้อ 3
ตัวเลือกที่ 1 ผิดเพราะ CSS ไม่ได้มีผลเท่ากันกับทุก element —
width/height ไม่มีผลกับ inline element ที่เนื้อเป็นข้อความอย่าง <span>
(ข้อยกเว้นคือ <img> ซึ่งเป็น inline แต่สั่งขนาดได้ เพราะเนื้อเป็นไฟล์ภาพจากข้างนอก — เห็นของจริงในหัวข้อ 7)
จุดที่ต้องจำ: "สั่ง CSS แล้วไม่เกิดอะไรขึ้นเลย" คือสัญญาณอันดับหนึ่งว่า
element นั้นเป็น inline อยู่ — เปิด DevTools ดู display ของมันก่อนทำอย่างอื่น
2. พิมพ์ <p>ก่อน<div>กลาง</div>หลัง</p> ลงไฟล์ แล้วเปิดดูใน DevTools — DOM ที่ได้เป็นยังไง?
ผมอ่าน innerHTML ของจริงออกมาได้เป๊ะ ๆ แบบนี้:
<p>ก่อน</p><div>กลาง</div>หลัง<p></p>
ครบทั้งสามอาการ: </p> ถูกแทรกให้เอง · คำว่า "หลัง" หลุดออกมาลอยนอก <p> ·
และ </p> ที่คุณพิมพ์ไว้กลายเป็น <p></p> เปล่า
ตัวเลือกที่ 2 คือความเข้าใจผิดที่พบบ่อยที่สุด — <p> มี content model
ที่รับได้แค่ phrasing content ซึ่งไม่รวม <div>
ตัวเลือกที่ 3 ผิดเพราะ parser ไม่ลบเนื้อหาทิ้ง มันย้ายที่ให้เท่านั้น
ตัวเลือกที่ 4 ผิดที่แนวคิด: HTML ไม่มี parse error ให้ฟ้อง — spec เขียนวิธี "ซ่อม" ไว้ให้ทุกกรณี
จุดที่ต้องจำ: สิ่งที่คุณพิมพ์กับ DOM ที่เบราว์เซอร์สร้างอาจไม่ใช่อันเดียวกัน —
เวลา CSS หรือ JavaScript ทำตัวประหลาด ให้ไปดู DOM จริงใน DevTools ก่อนเสมอ อย่าอ่านแต่ไฟล์ต้นฉบับ
3. เปลี่ยน <div id="main"> เป็น <main> ทั้งหน้า — อะไรเปลี่ยนไปบ้าง?
ผมวัดจริงในหัวข้อ 6: header · main · footer · div
ได้ display: block เหมือนกันหมด และกว้าง 482px เท่ากันทั้งสี่ — ไม่ต่างกันสักพิกเซล
ตัวเลือกที่ 1 กับ 3 ผิดตรงที่คิดว่ามีสไตล์เริ่มต้นซ่อนอยู่ · ไม่มี
ตัวเลือกที่ 2 คือตัวที่อันตรายที่สุด เพราะถูกครึ่งเดียว — "ที่เห็น" ไม่เปลี่ยนจริง
แต่คำว่า "ที่มองไม่เห็นก็ไม่เปลี่ยน" คือส่วนที่ผิด และเป็นความเชื่อที่ทำให้คนใช้ <div> ทั้งเว็บ
<main> กลายเป็น landmark ให้เอง ผู้ใช้ screen reader จึงกระโดดข้ามเมนูมาที่เนื้อหาได้ในคำสั่งเดียว
จุดที่ต้องจำ: ประโยชน์ของ semantic HTML ไม่โผล่บนหน้าจอของคุณ —
ถ้าตัดสินใจโดยดูแค่ว่า "เปลี่ยนแล้วหน้าเหมือนเดิม" คุณจะเลือกผิดทุกครั้ง
4. หน้าเว็บมีไอคอนรูปกระเป๋าวางข้าง ๆ หัวข้อ <h2>Work Experience</h2> ที่บอกเรื่องเดียวกันอยู่แล้ว — ควรเขียน alt ว่าอะไร?
คำถามที่ใช้ตัดสินคือ "ถ้ารูปนี้หายไป ผู้อ่านเสียข้อมูลอะไร" —
ในกรณีนี้ไม่เสียอะไรเลย เพราะหัวข้อข้าง ๆ พูดเรื่องเดียวกันอยู่แล้ว
ตัวเลือกที่ 3 คือกับดักตัวจริง เพราะเหตุผลของมันถูก (รูปนี้เป็นของประดับจริง)
แต่วิธีทำผิด — alt="" กับ "ไม่ใส่ alt" ให้ผลคนละอย่าง:
alt="" สั่งให้ screen reader ข้ามเงียบ ๆ ส่วนการไม่ใส่ทำให้มันไม่รู้ แล้วมักไปอ่านชื่อไฟล์ออกมาแทน
ตัวเลือกที่ 1 คือ alt ที่สไลด์หน้า 19 ใช้จริง — ผู้ใช้จะได้ยินคำว่า "work icon"
ตามด้วยหัวข้อ "Work Experience" คือฟังเรื่องเดิมสองรอบ
ตัวเลือกที่ 4 ยิ่งแย่กว่า เพราะยาวกว่าและยังซ้ำอยู่ดี — alt คือข้อความแทนภาพ ไม่ใช่คำบรรยายภาพ
จุดที่ต้องจำ: ทุก <img> ต้องมี alt เสมอ
คำถามมีแค่ว่าใส่ว่าอะไร ไม่ใช่ว่าจะใส่หรือไม่ใส่
ภารกิจ
resume.html ของตัวเอง แล้วพิสูจน์ว่ามันถูกจริง ไม่ใช่แค่ดูดี
เป้าหมายไม่ใช่ "หน้าออกมาสวย" — หน้าสวยพิสูจน์อะไรไม่ได้เลยในบทนี้ เพราะทุกกับดักที่เจอวันนี้ ไม่มีอันไหนทำให้หน้าดูผิด เป้าหมายคือเขียนคำสั่งตรวจที่บอกผ่าน/ไม่ผ่านได้ แล้วรันแล้วผ่านจริง
- ตั้งโครง: สร้างไฟล์
resume.htmlใส่<header>·<main>·<footer>อย่างละหนึ่ง
ใน<header>ใส่<h1>ชื่อคุณ · ใน<main>ใส่<h2>อย่างน้อยสองหัวข้อ (เช่น เกี่ยวกับฉัน · ประสบการณ์) - เติมเนื้อ: ใต้แต่ละ
<h2>ใส่<div class="…">ครอบ<p>สองสามอัน · แล้วเลือกคำเดียวกลางประโยคมาห่อด้วย<span>แล้วเปลี่ยนสีมันด้วยstyle="color: …" - ใส่รูปโดยไม่ใช้เน็ต: ก็อป data URI จากหัวข้อ 7 ไปใส่เป็น
<img>หนึ่งอัน พร้อมaltที่คุณตอบคำถามได้ว่าทำไมเขียนแบบนั้น - ทำให้พัง แล้วดู DOM จริง: จงใจเอา
<div>ไปใส่ใน<p>หนึ่งจุด
เปิด DevTools (คลิกขวา → Inspect) แท็บ Elements แล้วเทียบกับไฟล์ที่คุณพิมพ์
ต้องเห็น<p></p>เปล่าที่คุณไม่ได้พิมพ์ ถ้าไม่เห็น แปลว่าคุณวางไม่ตรงจุด
เห็นแล้วให้แก้กลับ โดยสลับเป็น<div>ครอบ<p> - เขียนชุดตรวจแล้วรันจริง: เปิด DevTools แท็บ Console แล้ววางทีละคำสั่ง
(คำสั่งที่ 5 ยาว 3 บรรทัด ให้วางทั้งก้อนแล้วค่อยกด Enter)
ทั้งห้าคำสั่งต้องได้trueถ้าได้falseคือยังไม่ผ่าน ให้กลับไปแก้ HTML
อย่าแก้คำสั่งตรวจให้มันผ่าน — นั่นคือการโกงตัวเอง// 1. มี main อันเดียว document.querySelectorAll('main').length === 1 // 2. มี h1 อันเดียว document.querySelectorAll('h1').length === 1 // 3. ทุกรูปมี alt (จะว่างก็ได้ แต่ต้องมี attribute) [...document.images].every(i => i.hasAttribute('alt')) // 4. ไม่มี p ที่ว่างเปล่า (แปลว่าไม่มีจุดที่ parser แอบซ่อมให้) [...document.querySelectorAll('p')].every(p => p.textContent.trim() !== '') // 5. หัวข้อไม่ข้ามระดับ (ห่างกันได้ไม่เกินทีละ 1 ขั้น) [...document.querySelectorAll('h1,h2,h3,h4,h5,h6')] .map(h => +h.tagName[1]) .every((n, i, a) => i === 0 || n <= a[i - 1] + 1) - ทดสอบตอนรูปโหลดไม่ขึ้น: เปลี่ยน
srcของ<img>ให้ชี้ไปไฟล์ที่ไม่มีจริง แล้ว refresh
อ่านหน้าตัวเองใหม่ทั้งหน้าแล้วตอบว่า "ยังรู้เรื่องไหม" — ถ้ายังรู้เรื่องaltคุณเขียนถูก
เสร็จแล้วเปลี่ยนsrcกลับ - ท้าทาย: เพิ่มคำสั่งตรวจที่หกด้วยตัวเอง — ตรวจว่าไม่มี
<div>ตัวไหนที่ไม่มีclass(คำใบ้:[...document.querySelectorAll('div')].every(…))
แล้วตัดสินใจเองว่ากฎข้อนี้ควรมีอยู่ไหม — มีเหตุผลทั้งสองฝั่ง ตอบให้ได้ว่าคุณเลือกฝั่งไหนเพราะอะไร
ตอนที่คุณเขียน <p>ก่อน<div>กลาง</div>หลัง</p>
DOM ที่ได้จริงคือ <p>ก่อน</p><div>กลาง</div>หลัง<p></p>
<p></p> ตัวสุดท้ายไม่มีข้อความอยู่ข้างในเลย —
textContent.trim() ของมันจึงเป็นสตริงว่าง และคำสั่งตรวจคืน false ทันที
นี่คือรูปแบบของ "การเขียนเทส" ที่ใช้ได้กับ HTML: คุณหาสิ่งที่วัดได้ซึ่งจะปรากฏก็ต่อเมื่อโค้ดผิด
แล้วตรวจว่ามันไม่มีอยู่
เหมือนฝั่ง Go เป๊ะ ๆ — ต่างกันแค่ที่นี่คุณ assert บน DOM แทนที่จะ assert บนค่าที่ฟังก์ชันคืนมา
และเหมือนกับฝั่ง Go อีกข้อ: เทสที่ไม่เคยเห็นมันแดง คือเทสที่ยังพิสูจน์อะไรไม่ได้
ก่อนเชื่อคำสั่งที่ 4 ให้ลองใส่กับดักกลับเข้าไปแล้วดูว่ามันได้ false จริงไหม
ติดตรงไหนถามได้เลย — โดยเฉพาะสามคำถามนี้ ที่ถามตอนนี้คุ้มกว่าถามทีหลังมาก:
· "ก้อนนี้ควรใช้ <div> หรือมีแท็กที่ตรงกว่า"
· "รูปนี้ควรเขียน alt ว่าอะไร"
· "ทำไมสั่ง CSS แล้วไม่เกิดอะไรขึ้น" (คำตอบมักอยู่ในหัวข้อ 1 ของบทนี้)
อ้างอิง
- MDN —
<p>— อ่านหัวข้อ Technical summary ตรงบรรทัด "Permitted content" จะเห็นคำว่า Phrasing content ซึ่งคือกฎที่ทำให้เกิดกับดักในหัวข้อ 3 ของบทนี้ทั้งหมด - WHATWG HTML Standard — the
pelement — ต้นฉบับของกฎ · อ่านแค่บรรทัด "Content model" กับ "Tag omission" ก็เห็นเลยว่า spec เขียนไว้ตรง ๆ ว่า</p>ถูกละได้และเบราว์เซอร์ต้องเติมให้เมื่อไหร่ - MDN —
<h1>–<h6>— อ่านหัวข้อ Accessibility ซึ่งอธิบายว่าทำไมห้ามข้ามระดับ และทำไมหน้าหนึ่งควรมี<h1>อันเดียว - W3C WAI — An
altDecision Tree — แผนผังตอบคำถาม "รูปนี้ควรใส่ alt ว่าอะไร" ในหน้าเดียว เริ่มอ่านจากกล่องบนสุดแล้วตอบคำถามลงมา · ใช้ได้จริงตอนทำภารกิจข้อ 3 - MDN —
<main>— อ่านหัวข้อ Usage notes ซึ่งบอกว่าหน้าหนึ่งมี<main>ที่มองเห็นได้อันเดียว และอธิบายว่ามันกลายเป็น landmark ให้ screen reader ยังไง - MDN — Block and inline layout in normal flow — อ่านสองย่อหน้าแรก ก็ครบเนื้อหาของหัวข้อ 1 ในบทนี้แล้ว ที่เหลืออ่านทีหลังตอนเรียนเรื่อง layout