CSS anchor positioning ใช้ได้ทุก browser แล้ว: tooltip และเมนู ไม่ต้องเขียน JS
anchor positioning เป็น Baseline ตั้งแต่ Firefox 147 ผูก tooltip หรือเมนูกับปุ่มด้วย CSS ล้วน หลบขอบจอเองด้วย position-try-fallbacks พร้อมทางสำรองสำหรับ browser เก่า
- ตั้งแต่มกราคม 2026 anchor positioning เป็น Baseline ใช้ได้ใน Chrome/Edge 125, Safari 26 และ Firefox 147
- สามส่วนหลักคือ anchor-name บนปุ่ม position-anchor บนกล่องที่ลอย และ position-area บอกว่าจะวางด้านไหน
- popover ที่เปิดด้วย popovertarget ผูกกับปุ่มให้เองแบบ implicit ทำเมนูได้โดยไม่มี JavaScript สักบรรทัด
- position-try-fallbacks ลองตำแหน่งสำรองตามลำดับจนกว่าจะพอดีจอ แทนโค้ดคำนวณตำแหน่งที่เคยต้องใช้ library
ทุกเว็บมี tooltip เมนูสามจุด หรือ dropdown ที่ต้องโผล่ติดกับปุ่ม และต้องหลบเมื่อปุ่มอยู่ชิดขอบจอ ที่ผ่านมางานนี้ต้องใช้ JavaScript วัดตำแหน่งปุ่ม คำนวณพิกัด และคอยฟัง scroll กับ resize CSS anchor positioning ทำเรื่องนี้ได้ใน CSS ล้วน และตั้งแต่มกราคม 2026 ใช้ได้ครบทุก browser หลักแล้ว
ทดสอบใน Chromium 152 ที่หน้าจอกว้าง 375 และ 800 px วัดตำแหน่งจริงด้วย getBoundingClientRect สถานะ browser ตรวจกับ MDN, caniuse และ web.dev ณ ตุลาคม 2026
สถานะ ณ ตุลาคม 2026
| browser | รองรับตั้งแต่ |
|---|---|
| Chrome / Edge | 125 |
| Safari (macOS, iOS) | 26.0 |
| Firefox | 147 (มกราคม 2026) |
Firefox 147 เป็นตัวสุดท้ายที่ตามมา ทำให้ฟีเจอร์นี้เป็น Baseline newly available ตั้งแต่มกราคม 2026 ข้อควรรู้คือ caniuse ยังติดป้าย “partial” ให้หลาย browser เพราะส่วนย่อยบางตัวยังรองรับไม่เท่ากัน ส่วนที่ใช้ในบทความนี้ (anchor-name, position-anchor, position-area, position-try-fallbacks, anchor-size()) คือส่วนแกนที่ใช้ได้แล้ว ส่วนย่อยที่ใหม่กว่าให้เช็กตาราง compat แยกทีละตัว
สามส่วนที่ต้องรู้
anchor-nameตั้งชื่อให้องค์ประกอบที่เป็นจุดยึด ชื่อต้องขึ้นต้นด้วย--position-anchorบนกล่องที่จะลอย บอกว่ายึดกับชื่อไหน กล่องนี้ต้องเป็นposition: absoluteหรือfixed- ตำแหน่ง บอกได้สองแบบ:
position-areaแบบตาราง 3×3 รอบจุดยึด (top,bottom span-right, …) หรือฟังก์ชันanchor()ในtop/leftเมื่อต้องคุมระดับพิกเซล
anchor-size(width) ใช้ขนาดของจุดยึดได้ด้วย เช่นให้เมนูกว้างไม่น้อยกว่าปุ่ม
Tooltip ด้วย CSS ล้วน
<button class="help" aria-describedby="tip1">?</button>
<span class="tip" id="tip1" role="tooltip">Draft จะเก็บไว้ 30 วัน</span>
.help { anchor-name: --help; }
.tip {
position: absolute;
position-anchor: --help;
position-area: top; /* เหนือปุ่ม กึ่งกลาง */
margin-bottom: 8px;
position-try-fallbacks: flip-block; /* ไม่มีที่ด้านบน ย้ายลงล่าง */
width: max-content;
max-width: 240px;
opacity: 0;
pointer-events: none;
}
.help:hover + .tip,
.help:focus-visible + .tip { opacity: 1; }
ผลที่วัดได้: ปุ่มอยู่กลางจอ (x 416–439, y 216–237) tooltip ลอยเหนือปุ่ม ขอบล่างที่ y 208 ห่าง 8 px ตาม margin และจุดกึ่งกลางตรงกับปุ่มพอดีที่ x 427.5 พอย้ายปุ่มไปชิดขอบบน (y 18–39) tooltip สลับลงไปใต้ปุ่มที่ y 47 = 39 + 8 เอง margin ก็กลับด้านให้ด้วย
aria-describedby ทำให้ screen reader อ่านข้อความ tooltip ตอน focus ปุ่ม และใช้ :focus-visible ด้วยเพื่อให้คนใช้คีย์บอร์ดเห็น บนมือถือไม่มี hover ข้อมูลที่สำคัญจึงไม่ควรอยู่ใน tooltip อย่างเดียว
เมนูด้วย popover: ไม่มี JS สักบรรทัด
Popover API เปิดปิดกล่องด้วย attribute popovertarget และเมื่อเปิดแบบนี้ browser ผูกปุ่มกับ popover เป็นจุดยึดแบบ implicit ให้เอง ไม่ต้องตั้ง anchor-name
<button popovertarget="actions">Actions</button>
<div popover id="actions" class="menu">
<button>Edit</button>
<button>Duplicate</button>
<button>Delete</button>
</div>
[popover].menu {
margin: 0;
inset: auto; /* ล้างค่าเริ่มต้นที่จัด popover ไว้กลางจอ */
position-anchor: auto; /* ใช้จุดยึด implicit จาก popovertarget */
position-area: bottom span-right; /* ใต้ปุ่ม เริ่มที่ขอบซ้ายแล้วขยายไปขวา */
position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
min-width: anchor-size(width);
margin-top: 4px;
}
ได้ทั้งการเปิดปิด กด Esc ปิด คลิกนอกกล่องปิด และวางตำแหน่ง โดยไม่ต้องเขียน JavaScript
ตัวอย่างตัวเลข: browser เลือกตำแหน่งสำรองยังไง
position-try-fallbacks คือรายการตำแหน่งสำรอง browser ใช้ตำแหน่งหลักก่อน ถ้าล้นจอจะลองตัวถัดไปตามลำดับ และเลือกตัวแรกที่อยู่ในจอได้ทั้งกล่อง ถ้าไม่มีตัวไหนพอดีเลย กลับไปใช้ตำแหน่งหลัก
วัดจริงบนจอ 375 × 640 px ปุ่ม Actions อยู่มุมขวาล่าง (x 299–359, y 599–620) เมนูขนาด 82 × 79 px ห่างปุ่ม 4 px:
| ลอง | ตำแหน่ง | แนวตั้ง | แนวนอน | ผล |
|---|---|---|---|---|
| หลัก | ใต้ปุ่ม ขยายไปขวา | 624–703 เกิน 640 | 299–381 เกิน 375 | ล้น |
flip-block | เหนือปุ่ม ขยายไปขวา | 516–595 | 299–381 เกิน 375 | ล้น |
flip-inline | ใต้ปุ่ม ขยายไปซ้าย | 624–703 เกิน 640 | 277–359 | ล้น |
flip-block flip-inline | เหนือปุ่ม ขยายไปซ้าย | 516–595 | 277–359 | พอดี |
ค่าที่ browser วางจริงคือ x 277–359, y 516–595 ตรงกับแถวสุดท้าย คำนวณได้จาก 599 − 4 − 79 = 516 และ 359 − 82 = 277 เมื่อย้ายปุ่มไปมุมขวาบน เมนูไปอยู่ใต้ปุ่ม (y 74) แต่ขยายไปซ้าย (x 277) คือได้ flip-inline
ใส่
flip-block flip-inlineเป็นตัวเลือกสุดท้ายเสมอ ปุ่มที่อยู่มุมจอต้องกลับทั้งสองแกน ถ้าไม่มีตัวนี้ browser จะกลับไปใช้ตำแหน่งหลักที่ล้นจอ
ต้องการตำแหน่งสำรองที่ซับซ้อนกว่านี้ (เช่นวางซ้ายแล้วจำกัดความกว้าง) สร้างเองด้วย @position-try --ชื่อ { ... } แล้วใส่ชื่อในรายการ
ซ่อนเมื่อปุ่มหายไปจากจอ
ถ้าปุ่มอยู่ในกล่องที่ scroll ได้ แล้วปุ่ม scroll หายไป tooltip อาจลอยค้าง ใช้ position-visibility
.tip { position-visibility: anchors-visible; } /* ซ่อนเมื่อจุดยึดหายไปทั้งตัว */
อีกค่าคือ no-overflow ซ่อนเมื่อกล่องเริ่มล้นจอหรือล้นกล่องที่บรรจุ
ทางสำรองสำหรับ browser เก่า
ผู้ใช้บางส่วนยังใช้ browser รุ่นก่อนตารางข้างบน เช่น iPhone ที่ยังไม่อัปเดตเป็น iOS 26 ใช้ @supports เขียนทางสำรองให้ใช้งานได้ แม้จะไม่สวยเท่า
@supports not (anchor-name: --a) {
[popover].menu { inset: 0; margin: auto; } /* แสดงกลางจอแบบ dialog */
}
Popover API เองรองรับกว้างกว่า anchor positioning เมนูจึงยังเปิดปิดได้ แค่ไม่ติดกับปุ่ม
ข้อผิดพลาดที่เจอบ่อย
- ลืมล้าง style เริ่มต้นของ popover popover มี
inset: 0และmargin: autoมาจาก browser ถ้าไม่ล้าง กล่องจะไม่ไปติดปุ่ม - ใช้ชื่อเก่าจากบทความปี 2024
inset-areaใช้position-areaแทน และposition-try-optionsใช้position-try-fallbacksแทน ชื่อเก่าใช้ไม่ได้แล้ว - จุดยึดเป็น
display: noneหรือvisibility: hiddenผูกไม่ได้ กล่องไปอยู่ผิดที่ - ตั้ง
anchor-nameชื่อเดียวกันหลายที่ เช่นปุ่มในทุกแถวของตาราง กล่องจะยึดกับตัวสุดท้ายในหน้า ใช้ popover แบบ implicit หรือanchor-scopeแยกขอบเขต - ใส่แค่
flip-blockปุ่มที่ชิดมุมจอยังล้นแนวนอน - ไม่ลองที่จอมือถือ ตำแหน่งสำรองทำงานจริงเฉพาะเมื่อพื้นที่ไม่พอ ต้องเปิดดูที่ 375 px แบบที่เล่าใน ให้ AI ตรวจหน้าเว็บบนมือถือ
แหล่งอ้างอิง
- anchor-name — MDN Web Docs
- Using CSS anchor positioning — MDN Web Docs
- Fallback options and conditional hiding for overflow — MDN Web Docs
- position-anchor — MDN Web Docs
- New to the web platform in January 2026 — web.dev
- Anchor positioning syntax changes — Chrome for Developers
- CSS Anchor Positioning — caniuse.com
คำถามที่พบบ่อย
ยังต้องใช้ Floating UI หรือ Popper อยู่ไหม
สำหรับ tooltip เมนู และ dropdown ทั่วไป CSS ทำได้เองแล้ว ยังมีเหตุผลใช้ library ถ้าต้องรองรับ browser รุ่นก่อนที่ระบุในบทความให้หน้าตาเหมือนกันทุกเครื่อง หรือโค้ดเดิมพึ่งความสามารถเฉพาะของ library นั้นอยู่มาก
browser เก่าที่ไม่รองรับจะเห็นอะไร
กล่องที่ใช้ position absolute หรือ fixed จะไปอยู่ตำแหน่งตาม inset ปกติ ซึ่งมักผิดที่ ให้เขียนทางสำรองใน @supports not (anchor-name: --a) เช่นให้เมนู popover แสดงกลางจอแบบ dialog
บทความเก่าใช้ inset-area และ position-try-options ใช้ได้ไหม
เป็นชื่อเก่าก่อนสเปกนิ่ง Chrome เปลี่ยนเป็น position-area (Chrome 129) และ position-try-fallbacks (Chrome 128) แล้ว ให้ใช้ชื่อใหม่เท่านั้น
คำสั่งและค่าตั้งในบทความทดสอบบนระบบตัวอย่าง ลองบนเครื่องทดสอบก่อนใช้กับระบบจริงเสมอ