ดึงเพื่อแสดง

"ดึงเพื่อแสดง" เป็นรูปแบบ UI ที่เนื้อหา (เช่น แถบค้นหาหรือตัวควบคุมการรีเฟรช) ถูกซ่อนไว้เหนือด้านบนของพื้นที่ที่เลื่อนได้เมื่อโหลดครั้งแรก และผู้ใช้สามารถดึงลง (เลื่อนขึ้น) เพื่อแสดงเนื้อหาได้ รูปแบบนี้มักใช้ในแอปบนอุปกรณ์เคลื่อนที่และเว็บแอปสำหรับแถบค้นหา ตัวกรอง และการควบคุมรองอื่นๆ ที่ควรเข้าถึงได้แต่ไม่แสดงทันที

พร็อพเพอร์ตี้ CSS scroll-initial-target มีวิธีประกาศที่ใช้ CSS เท่านั้นในการใช้รูปแบบนี้ การตั้งค่า scroll-initial-target: nearest ในองค์ประกอบเนื้อหาหลักจะทำให้คอนเทนเนอร์การเลื่อนแสดงผลโดยที่เนื้อหาที่ซ่อนอยู่เลื่อนออกไปจากมุมมอง ก่อนหน้านี้ นักพัฒนาแอปต้องอาศัย JavaScript (Element.scrollIntoView()) หรือตัวระบุส่วนย่อย URL (#content-id) เพื่อดำเนินการนี้ ซึ่งทั้ง 2 วิธีมีข้อจำกัดและใช้งานได้ยาก

วิธีการนำไปใช้งาน

วิธีใช้รูปแบบดึงเพื่อแสดง

  1. ตรวจสอบว่ามีคอนเทนเนอร์การเลื่อน: องค์ประกอบเป้าหมายต้องอยู่ภายในคอนเทนเนอร์การเลื่อน (องค์ประกอบที่มีรายการเพิ่มเติมที่อนุญาตให้เลื่อนได้ เช่น overflow: auto) ซึ่งอาจเป็นองค์ประกอบระดับบนสุดใดก็ได้ รวมถึงองค์ประกอบ <html> ระดับรูท
  2. กำหนดองค์ประกอบที่ซ่อนอยู่: วางเนื้อหาที่ต้องการซ่อน (เช่น แถบค้นหา) เป็นองค์ประกอบสืบทอดแรกภายในคอนเทนเนอร์การเลื่อน องค์ประกอบนี้จะเลื่อนออกจากมุมมองเมื่อโหลดครั้งแรก
  3. กำหนดเนื้อหาหลัก: วางองค์ประกอบเนื้อหาหลักไว้หลังองค์ประกอบที่ซ่อนอยู่ทันที นี่คือองค์ประกอบที่ผู้ใช้ควรเห็นเป็นอันดับแรก
  4. กำหนดเป้าหมายเนื้อหาหลัก: ใช้ scroll-initial-target: nearest กับองค์ประกอบเนื้อหาหลักเพื่อให้คอนเทนเนอร์การเลื่อนแสดงผลโดยเลื่อนเข้าไปในมุมมอง ซึ่งจะซ่อนองค์ประกอบที่อยู่ด้านบน
  5. เพิ่มการสแนปการเลื่อน: เพื่อให้องค์ประกอบที่ซ่อนอยู่แสดงอย่างสมบูรณ์หรือซ่อนอย่างสมบูรณ์เสมอ (และไม่อยู่ในสถานะที่เลื่อนบางส่วน) ให้เพิ่ม scroll-snap-type: y mandatory ลงในคอนเทนเนอร์การเลื่อน และเพิ่ม scroll-snap-align: start ลงในทั้งองค์ประกอบที่ซ่อนอยู่และองค์ประกอบเนื้อหาหลัก
/**
 * ANCESTOR: Define the scroll container.
 * Scroll snapping ensures the search bar is always
 * either fully visible or fully hidden.
 */
.scroll-container {
  height: 100vh;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}

/**
 * HIDDEN ELEMENT: The search bar hidden above the fold on load.
 * It has scroll-snap-align so it snaps into place when pulled down.
 */
.search-bar {
  height: 60px;
  scroll-snap-align: start;
}

/**
 * MAIN CONTENT + TARGET: The element the user sees first.
 * scroll-snap-align makes it a valid snap point.
 * scroll-initial-target tells the browser to scroll here on
 * initial render, hiding the search bar above it.
 */
.main-content {
  scroll-snap-align: start;
  scroll-initial-target: nearest;
}

การนำไปใช้เชิงกลยุทธ์และแนวทางปฏิบัติแนะนำ

  • ควรใช้ scroll-initial-target: nearest เมื่อต้องการดึงดูดความสนใจของผู้ใช้ไปยังส่วนที่เฉพาะเจาะจงของพื้นที่ที่เลื่อนได้เมื่อโหลด และตั้งใจซ่อนหน่วย UI อุปกรณ์ต่อพ่วง เช่น แถบค้นหาที่ด้านบนสุด
  • อย่าสับสนระหว่างการโฟกัสนี้กับการโฟกัสการช่วยเหลือพิเศษ พร็อพเพอร์ตี้นี้จะย้ายเฉพาะวิวพอร์ตภาพเท่านั้น โดยจะไม่ย้ายโฟกัสของแป้นพิมพ์ คุณต้องจัดการ element.focus() ด้วยตนเองหากต้องการให้เป้าหมายเป็นจุดเริ่มต้นสำหรับผู้ใช้แป้นพิมพ์
  • อย่าใช้พร็อพเพอร์ตี้นี้หากต้องการภาพเคลื่อนไหว "การเลื่อน" ที่ราบรื่นเมื่อโหลด พร็อพเพอร์ตี้นี้ไม่ต่อเนื่องและจะตั้งค่าตำแหน่งทันทีในระหว่างระยะเลย์เอาต์
  • อย่าตั้งค่า scroll-initial-target ในองค์ประกอบหลายรายการภายในคอนเทนเนอร์ที่เลื่อนได้เดียวกัน หากมีองค์ประกอบหลายรายการที่ระบุ scroll-initial-target: nearest เบราว์เซอร์จะเลือกองค์ประกอบที่ปรากฏเป็นอันดับแรกในลำดับแผนผัง DOM
  • ควรพิจารณาลำดับชั้นความสำคัญ: ส่วนย่อย URL (เช่น example.com/#top) และพร็อพเพอร์ตี้ scroll-start ระดับคอนเทนเนอร์มีความสำคัญเหนือกว่า scroll-initial-target

กลยุทธ์สำรอง

สำหรับเบราว์เซอร์ที่ยังไม่รองรับ API ให้ใช้ JavaScript สำรอง โปรดทราบว่าสำหรับการดึงเนื้อหาเพื่อแสดง คุณต้องการให้เนื้อหาหลักเชื่อมโยงกับ start (ด้านบน) ของคอนเทนเนอร์

/**
 * Progressive Enhancement Fallback
 */
document.addEventListener("DOMContentLoaded", () => {
  // Check for native CSS support
  if (!CSS.supports("scroll-initial-target", "nearest")) {
    const targetContent = document.querySelector('.main-content.target');
    if (targetContent) {
      // Use behavior: "instant" to mimic the native CSS behavior
      // 'block: start' should match your CSS 'scroll-snap-align' (or expected top position)
      targetContent.scrollIntoView({ behavior: 'instant', block: 'start' });
    }
  }
});