useMeasure วัดขนาดกล่องบนหน้าเว็บด้วย ResizeObserver ในบรรทัดเดียว แต่ค่า top ที่ได้คือ 16 ไม่ใช่ 300
useMeasure คือฮุคที่ย่อ ResizeObserver ของเบราว์เซอร์ ให้วัดขนาดกล่องบนหน้าเว็บแบบสดๆ ได้ในบรรทัดเดียว ข้อควรระวังคือค่า top กับ left ที่ได้ เป็นระยะขอบด้านในของกล่องเอง ไม่ใช่ตำแหน่งบนจอ

หน้าต่างเบราว์เซอร์ไม่ได้ขยับสักพิกเซล แต่กล่องในหน้าเว็บเปลี่ยนขนาดไปแล้ว และ ResizeObserver คือส่วนของเบราว์เซอร์ที่มีไว้จับจังหวะแบบนี้
ลองนึกถึงหน้าแดชบอร์ด พอพับแถบข้างซ้าย พื้นที่เนื้อหาตรงกลางจะกว้างขึ้นทันที กราฟที่วาดตามความกว้างเดิมจึงล้นกรอบ ส่วนฟอนต์ที่โหลดทีหลังทำให้การ์ดสูงขึ้น และเมื่อเนื้อหาเปลี่ยน ขนาดการ์ดก็เปลี่ยน ทั้งสามเหตุการณ์เกิดได้โดยไม่แตะขนาดหน้าต่าง
โค้ดที่เขียนกันจนติดมือมักไปดักการเปลี่ยนที่หน้าต่าง เช่น เรียก getBoundingClientRect() เพื่ออ่านขนาดกล่องเพียงครั้งเดียวตอนชิ้นส่วนหน้าเว็บขึ้นจอ จากนั้นก็ฟังอีเวนต์ resize ของ window เผื่อผู้ใช้ย่อขยาย ทั้งสองวิธีมองไม่เห็นสามเหตุการณ์ข้างบน
บทความบน dev.to ของ childrentime อธิบายเรื่องนี้ผ่าน useMeasure ฮุคสำเร็จรูปจากไลบรารี @reactuses/core มันห่อ ResizeObserver ไว้จนเรียกใช้ได้ในบรรทัดเดียว แล้วอัปเดตค่าขนาดให้เองทุกครั้งที่ขนาดกล่องเปลี่ยน
ดัก window resize แต่กล่องเปลี่ยน

อีเวนต์ resize ของ window เกิดเมื่อพื้นที่แสดงผลของเบราว์เซอร์เปลี่ยนขนาด มันจึงเห็นแค่ตอนลากขอบหน้าต่างหรือหมุนจอมือถือ
กล่องบนหน้าเว็บยังโตหรือหดได้โดยไม่เกี่ยวกับหน้าต่าง ต้นทางยกไว้สามกรณี คือกล่องข้างๆ ยุบจนแบ่งพื้นที่ใหม่ ฟอนต์โหลดเสร็จแล้วตัวอักษรกินที่เปลี่ยนไป และเนื้อหาในกล่องเปลี่ยน ทั้งหมดนี้ไม่ก่ออีเวนต์ resize ของหน้าต่าง
ส่วน getBoundingClientRect() ที่เรียกตอนชิ้นส่วนหน้าเว็บขึ้นจอ ให้ค่าที่แม่นเฉพาะตอนนั้น มันเป็นภาพนิ่ง พอการจัดหน้าเปลี่ยน ตัวเลขก็เก่าทันที กราฟจึงปกติตอนเปิดหน้า แล้วเพี้ยนเมื่อผู้ใช้เริ่มกดอะไร
ResizeObserver เป็นของเบราว์เซอร์ ไม่ใช่ไลบรารี
ResizeObserver เป็นส่วนของเบราว์เซอร์สำหรับดูขนาดองค์ประกอบทีละตัว ไม่ใช่ดูทั้งหน้าต่าง
หน้าเอกสารของ MDN Web Docs ระบุว่า ResizeObserver รายงานการเปลี่ยนแปลงของพื้นที่วางเนื้อหา (content box) หรือพื้นที่ที่รวมเนื้อหา ระยะขอบด้านใน และเส้นขอบ (border box) ขององค์ประกอบ และรายงานกรอบของ SVG ได้ด้วย
หน้าเดียวกันยังระบุว่า ResizeObserver ใช้ข้ามเบราว์เซอร์ได้ตั้งแต่กรกฎาคม 2020 ความสามารถนี้จึงอยู่ในเครื่องผู้ใช้มาหลายปีแล้วโดยไม่ต้องติดตั้งอะไรเพิ่ม
useMeasure ย่อเหลือ const [rect, stop] = useMeasure(ref)
ฮุคตัวนี้จัดการงานรอบ ResizeObserver ให้หมด ตั้งแต่สร้าง เริ่มดู จนเลิกดูเมื่อชิ้นส่วนหน้าเว็บหายจากจอ เหลือโค้ดแค่นี้
import { useRef } from 'react';
import { useMeasure } from '@reactuses/core';
function Chart() {
const ref = useRef<HTMLDivElement>(null);
const [rect] = useMeasure(ref);
return (
<div ref={ref} style={{ width: '100%', height: '400px' }}>
<svg width={rect.width} height={rect.height}>
{/* วาดด้วยขนาดพิกเซลจริง */}
</svg>
</div>
);
}แปะจุดเชื่อม ref ที่กล่องแล้วเรียก useMeasure(ref) หน้าเว็บจะอัปเดตชิ้นส่วนนั้นใหม่ทุกครั้งที่ content box เปลี่ยนขนาด ไม่ว่าจะมาจากการย่อหน้าต่าง จัดหน้าใหม่ พับแถบข้าง หรือสลับฟอนต์ ฮุคจะตัดการเชื่อมต่อเองเมื่อชิ้นส่วนนั้นถูกถอดจากจอ
ค่าที่คืนมามีสองตัว ตัวแรกเป็นชุดตัวเลขชื่อ rect ที่มีแปดช่อง ได้แก่ x, y, width, height, top, left, bottom และ right ตัวที่สองเป็นฟังก์ชัน stop สำหรับหยุดวัดเอง เหมาะกับงานที่ต้องการค่าแค่ครั้งเดียว เช่น วัดขนาดตั้งต้นเพื่อทำอนิเมชันแล้วไม่ต้องอัปเดตใหม่ต่อ
top กับ left ของ useMeasure ไม่ใช่ตำแหน่งบนจอ

ResizeObserver ส่งค่าพื้นที่เนื้อหามาในชื่อ entry.contentRect ค่านี้วัดเทียบกับกล่อง ไม่ใช่หน้าจอ width กับ height จึงนับเฉพาะ content box โดยตัดระยะขอบด้านใน เส้นขอบ และแถบเลื่อนออกไป ส่วน top, left, x และ y คือระยะจาก border box เข้ามาถึง content box ในทางปฏิบัติก็คือ padding-top กับ padding-left ของกล่องนั้นเอง
ต้นทางยกตัวอย่างว่า กล่องที่ตั้ง padding: 16px แล้ววางห่างจากขอบบนของหน้าลงมา 300px จะรายงานกลับมาว่า top: 16 ไม่ใช่ top: 300
ส่วนใครที่กำลังหาตำแหน่งของกล่องบนหน้าจอ เพื่อเอาทูลทิปไปแปะให้ตรงจุด กางดรอปดาวน์ หรือวางเลเยอร์ไฮไลต์ทับ ให้ใช้ตัวคืนพิกัด useElementBounding แทน มันคำนวณตำแหน่งเทียบพื้นที่แสดงผลใหม่ตอนสกรอลล์
useMeasure บอกได้ว่ากล่องใหญ่แค่ไหน ส่วนคำถามว่าอยู่ตรงไหน เป็นงานของ useElementBounding
สามงานที่ต้องรู้ขนาดกล่องจริง
หนึ่ง การ์ดที่จัดเลย์เอาต์ตามกล่องของตัวเอง มีเดียคิวรีดูขนาดจอ แต่ชิ้นส่วนหน้าเว็บอยู่ในกล่อง การ์ดใบเดียวกันในคอลัมน์กว้างกับแถบข้างแคบจึงควรจัดต่างกันแม้อยู่บนจอเดียวกัน ต้นทางให้การ์ดเรียงลงเมื่อกล่องกว้างน้อยกว่า 320
const [rect] = useMeasure(ref);
const compact = rect.width > 0 && rect.width < 320;เกณฑ์นี้ดูตัวเลขจากกล่อง ไม่ใช่หน้าจอ
สอง พื้นที่วาดภาพ canvas กับ SVG ที่ต้องรู้ขนาดพิกเซลก่อนวาด ทั้งคู่ต้องรู้ความกว้างและสูงเป็นตัวเลข เมื่อให้ภาพวาดตามขนาดปัจจุบันของกล่องแม่ ภาพก็จะวาดใหม่ด้วยความละเอียดที่ถูกต้องทุกครั้งที่การจัดหน้าเปลี่ยน ทั้งตอนลากขอบแผงบนหน้าเว็บ พับแถบข้าง และหมุนจอ โค้ดที่ฟัง resize ของหน้าต่างมองไม่เห็นสองกรณีแรก
สาม กล่องเปิดปิดที่มีอนิเมชันความสูง การสั่ง CSS ให้ความสูงค่อยๆ เปลี่ยนไปยัง height: auto ทำไม่ได้ ทางออกคือวัดความสูงจริงของเนื้อหาออกมาเป็นตัวเลข แล้วทำอนิเมชันไปหาเลขนั้น ค่าที่อัปเดตตลอดช่วยให้กล่องยังสูงพอดีเมื่อเนื้อหาเปลี่ยนระหว่างเปิดค้าง เช่น รูปเพิ่งโหลด ถ้าวัดครั้งเดียว ตัวเลขจะเก่าทันทีที่เนื้อหาเปลี่ยน
เรนเดอร์รอบแรกได้ 0 ทุกฟิลด์
ก่อน ResizeObserver สังเกตกล่องรอบแรก ทุกช่องใน rect เป็น 0 ระบบที่เตรียมหน้าเว็บบนเซิร์ฟเวอร์ก่อนส่งมาให้เบราว์เซอร์ก็ใช้ค่า 0 ตามที่เอกสารไลบรารีระบุ
ResizeObserver เริ่มทำงานหลังชิ้นส่วนหน้าเว็บขึ้นจอ จึงไม่ทำงานในขั้นตอนบนเซิร์ฟเวอร์ เซิร์ฟเวอร์เตรียมหน้าด้วยค่าศูนย์ เบราว์เซอร์ประกอบหน้าด้วยค่าเดียวกันโดยไม่ขัดกัน แล้วค่าจริงจึงตามมา
วิธีป้องกันคือเช็กก่อนคำนวณ
const [rect] = useMeasure(ref);
return (
<div ref={ref}>
{rect.width > 0 && <Chart width={rect.width} height={rect.height} />}
</div>
);สี่ฮุคในไลบรารีเดียวกัน ใช้ตอนไหน
| ฮุค | คืนอะไรกลับมา | เหมาะกับงานแบบไหน |
|---|---|---|
useMeasure | rect ครบแปดช่อง พร้อม stop | อยากได้ขนาดของ content box และอยากสั่งเลิกวัดเองได้ |
useElementSize | [width, height] | อยากได้แค่กว้างยาว หรืออยากรวมระยะขอบด้านในกับเส้นขอบด้วย { box: 'border-box' } |
useElementBounding | พิกัดเทียบพื้นที่แสดงผล | วางทูลทิป ป็อปโอเวอร์ หรือเลเยอร์ที่ต้องเกาะตำแหน่งบนจอ และต้องขยับตามตอนสกรอลล์ |
useResizeObserver | รายการ ResizeObserverEntry[] ดิบที่ส่งกลับไปให้โค้ดจัดการ | อยากกำหนดวิธีจัดการเอง ดูหลายกล่องพร้อมกัน โดยไม่ให้หน้าเว็บอัปเดตตามทุกครั้ง |
useElementSize เป็นตัวเดียวที่ค่าที่วัดเปลี่ยนตามค่าตั้ง box ส่วน useMeasure รายงาน content box เสมอ เพราะค่าตั้งนี้กำหนดแค่ว่ากล่องแบบไหนจะทำให้เริ่มวัดใหม่
ส่วน useElementBounding เป็นตัวเดียวที่ตามตำแหน่งตอนสกรอลล์ จึงทำงานหนักกว่าตัวอื่น ถ้าต้องการแค่ขนาดหน้าจอ ต้นทางแนะนำ useWindowSize ไม่ใช่สี่ตัวนี้
หัวใจคือ ResizeObserver ไลบรารีแค่ช่วยให้สะดวก
บทความต้นทางเขียนโดยคนทำไลบรารี และลงท้ายด้วยการชวนใช้ @reactuses/core ความสามารถจริงอยู่ในเบราว์เซอร์ ส่วนฮุคพวกนี้เพียงย่องานสร้าง ResizeObserver และสั่งเลิกดูให้ถูกจังหวะจนเหลือบรรทัดเดียว นี่คล้ายกับ JavaScript ปี 2026 ที่มีของซึ่งเมื่อก่อนต้องพึ่ง lodash มาให้ในตัวภาษาแล้ว
ต้นทางไม่ได้วัดตัวเลขไว้ ไม่มีทั้งเปอร์เซ็นต์ความเร็วหรือจำนวนครั้งที่หน้าเว็บอัปเดตน้อยลง มันบอกได้แค่ความต่างของพฤติกรรม วิธีเดิมมองไม่เห็นการเปลี่ยนขนาดบางแบบ แต่วิธีนี้มองเห็น
ส่วนถ้าสั่ง AI ทำหน้าเว็บแล้วของล้นกล่องจนไม่รู้จะบอกอย่างไร ให้ใส่คำว่า ResizeObserver ในคำสั่ง ไม่ใช่ชื่อไลบรารี เพราะนี่คือกลไกที่ทำงานจริง
การให้โค้ดทั้งหมดรอการเปลี่ยนขนาดของ window ไม่ใช่ความมักง่าย แต่มาจากยุคที่เบราว์เซอร์บอกได้แค่ว่าหน้าต่างเปลี่ยนขนาด ความสามารถที่ตรงกว่ามีมาตั้งแต่กลางปี 2020 ส่วนโค้ดเก่ายังรอให้กลับไปแก้
ที่มา:
- บทความ React useMeasure Hook: Measure DOM Elements with ResizeObserver (2026) จาก dev.to
- เอกสารทางการของ useMeasure – Element Hook Usage & Examples
- เอกสารทางการของ ResizeObserver - Web APIs
ชอบเรื่องแนวนี้ มีอีบุ๊คฟรีให้อ่านต่อ
NotebookLM ฉบับเข้าใจง่าย โยนเอกสารให้ AI อ่าน แล้วได้สรุป พอดแคสต์ และคลังความรู้ส่วนตัว
กดสมัครแล้วเราจะส่งเทคนิค AI และของแจกใหม่ๆ ให้ทางอีเมล เลิกรับได้ตลอด
Claude Cowork · The Business Playbook

ฉบับภาษาไทย 15 บท เรียนรู้ผ่านโปรเจกต์จำลองต่อเนื่องทั้งเล่ม ตั้งแต่ตั้งค่า Workspace จัดการไฟล์ เชื่อมแอป ตั้งระบบอัตโนมัติ จนถึงสร้าง Plugin


