เชื่อมต่ออินเทอร์เน็ตมือถือเข้าด้วยกันด้วยการจัดตำแหน่ง Anchor ของ CSS

ในปัจจุบันคุณผูกโยงองค์ประกอบหนึ่งกับอีกองค์ประกอบหนึ่งได้อย่างไร คุณอาจลองติดตามตำแหน่งเหล่านั้น หรือใช้องค์ประกอบ Wrapper บางรูปแบบ

<!-- index.html -->
<div class="container">
  <a href="/link" class="anchor">I’m the anchor</a>
  <div class="anchored">I’m the anchored thing</div>
</div>
/* styles.css */
.container {
  position: relative;
}
.anchored {
  position: absolute;
}

โซลูชันเหล่านี้มักไม่เหมาะสำหรับ เนื่องจากจำเป็นต้องใช้ JavaScript หรือต้องใช้มาร์กอัปเพิ่มเติม API การวางตำแหน่ง Anchor ของ CSS มีวัตถุประสงค์เพื่อแก้ปัญหานี้โดยการระบุ CSS API สำหรับองค์ประกอบการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ วิธีการวางตำแหน่งและกำหนดขนาดขององค์ประกอบหนึ่งตามตำแหน่งและขนาดขององค์ประกอบอื่นๆ

รูปภาพแสดงหน้าต่างเบราว์เซอร์จำลองที่อธิบายรายละเอียดโครงสร้างของเคล็ดลับเครื่องมือ

การสนับสนุนเบราว์เซอร์

คุณสามารถลองใช้ API การวางตำแหน่ง Anchor ของ CSS ใน Chrome Canary ที่มี Flag "ฟีเจอร์แพลตฟอร์มเว็บรุ่นทดลอง" ได้ หากต้องการเปิดการตั้งค่าสถานะดังกล่าว ให้เปิด Chrome Canary แล้วไปที่ chrome://flags จากนั้นให้เปิดใช้ Flag "ฟีเจอร์แพลตฟอร์มเว็บรุ่นทดลอง"

นอกจากนี้ยังมี Polyfill ที่อยู่ระหว่างการพัฒนาโดยทีม Oddbird ด้วย อย่าลืมตรวจสอบที่เก็บที่ github.com/oddbird/css-anchor-positioning

คุณสามารถตรวจสอบการสนับสนุนการตรึงด้วยสิ่งต่อไปนี้

@supports(anchor-name: --foo) {
  /* Styles... */
}

โปรดทราบว่า API นี้ยังอยู่ในระยะทดลองและอาจมีการเปลี่ยนแปลง บทความนี้ครอบคลุมส่วนสําคัญในภาพรวม การใช้งานในปัจจุบันไม่ได้ซิงค์กับข้อกำหนดของคณะทำงานของ CSS โดยสมบูรณ์

ปัญหา

เหตุใดคุณจึงต้องทำเช่นนี้ กรณีการใช้งานที่เด่นชัดคือการสร้างเคล็ดลับเครื่องมือหรือประสบการณ์ที่เหมือนกับเคล็ดลับเครื่องมือ ในกรณีนี้ คุณมักจะต้องการเชื่อมโยงเคล็ดลับเครื่องมือกับเนื้อหาที่อ้างอิงอยู่ บ่อยครั้งจำเป็นต้องใช้วิธีเชื่อมโยงองค์ประกอบหนึ่งกับอีกองค์ประกอบหนึ่ง นอกจากนี้ คุณยังคาดหวังได้ว่าการโต้ตอบกับหน้าเว็บจะไม่ทำให้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหยุดชะงัก เช่น หากผู้ใช้เลื่อนหรือปรับขนาด UI

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

โซลูชันปัจจุบัน

ปัจจุบันคุณมีวิธีต่างๆ ในการจัดการปัญหานี้

อย่างแรกคือแนวทาง "รวมจุดยึด" ที่เป็นพื้นฐาน นำองค์ประกอบทั้ง 2 อย่างมารวมไว้ในภาชนะบรรจุ จากนั้นคุณสามารถใช้ position เพื่อจัดตำแหน่งเคล็ดลับเครื่องมือให้สัมพันธ์กับแท็ก Anchor

<div class="containing-block">
  <div class="tooltip">Anchor me!</div>
  <a class="anchor">The anchor</a>
</div>
.containing-block {
  position: relative;
}

.tooltip {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
}

คุณสามารถย้ายคอนเทนเนอร์ได้เพื่อให้ทุกอย่างอยู่ในที่ที่คุณต้องการมากที่สุด

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

<div class="tooltip">Anchor me!</div>
<a class="anchor">The anchor</a>
:root {
  --anchor-width: 120px;
  --anchor-top: 40vh;
  --anchor-left: 20vmin;
}

.anchor {
  position: absolute;
  top: var(--anchor-top);
  left: var(--anchor-left);
  width: var(--anchor-width);
}

.tooltip {
  position: absolute;
  top: calc(var(--anchor-top));
  left: calc((var(--anchor-width) * 0.5) + var(--anchor-left));
  transform: translate(-50%, calc(-100% - 10px));
}

แต่หากคุณไม่ทราบตำแหน่งของ Anchor ล่ะ คุณอาจต้องแทรกแซง JavaScript คุณสามารถทำสิ่งต่างๆ ได้เหมือนที่โค้ดต่อไปนี้ทำได้ แต่ตอนนี้รูปแบบเริ่มรั่วไหลจาก CSS และเข้าสู่ JavaScript

const setAnchorPosition = (anchored, anchor) => {
  const bounds = anchor.getBoundingClientRect().toJSON();
  for (const [key, value] of Object.entries(bounds)) {
    anchored.style.setProperty(`--${key}`, value);
  }
};

const update = () => {
  setAnchorPosition(
    document.querySelector('.tooltip'),
    document.querySelector('.anchor')
  );
};

window.addEventListener('resize', update);
document.addEventListener('DOMContentLoaded', update);

สิ่งนี้จะเริ่มทำให้เกิดคำถามต่างๆ:

  • ฉันจะคำนวณสไตล์เมื่อใด
  • ฉันจะคำนวณสไตล์ได้อย่างไร
  • ฉันคำนวณสไตล์บ่อยเพียงใด

วิธีนี้ช่วยแก้ปัญหาได้หรือไม่ อาจเพื่อ Use Case ของคุณ แต่มีปัญหาเดียวคือโซลูชันของเราปรับไม่ได้ อุปกรณ์ไม่ตอบสนอง จะเกิดอะไรขึ้นหากองค์ประกอบที่ตรึงไว้ของฉันถูกตัดโดยวิวพอร์ต

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

คุณอาจหาโซลูชัน JavaScript เพื่อช่วยคุณแก้ไขปัญหาดังกล่าว ซึ่งจะก่อให้เกิดค่าใช้จ่ายในการเพิ่มทรัพยากร Dependency ในโปรเจ็กต์ และอาจทำให้เกิดปัญหาด้านประสิทธิภาพ ทั้งนี้ขึ้นอยู่กับวิธีที่คุณใช้งาน เช่น แพ็กเกจบางรายการใช้ requestAnimationFrame เพื่อให้ตำแหน่งถูกต้อง ซึ่งหมายความว่าคุณและทีมจะต้องทำความคุ้นเคยกับแพ็กเกจและตัวเลือกการกำหนดค่า ด้วยเหตุนี้ คำถามและการตัดสินใจของคุณอาจไม่ลดลง แต่มีการเปลี่ยนแปลงแทน ซึ่งเป็นส่วนหนึ่งของ "เหตุผล" สำหรับการวางตำแหน่ง Anchor ของ CSS ขณะคำนวณอันดับ นั่นจะทำให้คุณไม่คิดถึงปัญหาด้านประสิทธิภาพ

ต่อไปนี้คือหน้าตาของโค้ดเมื่อใช้ "floating-ui" ซึ่งเป็นแพ็กเกจยอดนิยมสำหรับปัญหานี้

import {computePosition, flip, offset, autoUpdate} from 'https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.2.1/+esm';

const anchor = document.querySelector('.anchor')
const tooltip = document.querySelector('.tooltip')

const updatePosition = () => {  
  computePosition(anchor, tooltip, {
    placement: 'top',
    middleware: [offset(10), flip()]
  })
    .then(({x, y}) => {
      Object.assign(tooltip.style, {
        left: `${x}px`,
        top: `${y}px`
      })
  })
};

const clean = autoUpdate(anchor, tooltip, updatePosition);

ลองจัดตำแหน่งแท็ก Anchor ใหม่ในการสาธิตที่ใช้โค้ดดังกล่าว

"เคล็ดลับเครื่องมือ" อาจทำงานได้ไม่ตรงตามที่คุณคาดหวัง โดยจะตอบสนองต่อการออกไปนอกวิวพอร์ตบนแกน Y แต่ไม่ใช่แกน X อ่านเอกสารประกอบ แล้วคุณอาจพบวิธีแก้ปัญหาที่เหมาะกับคุณ

แต่การค้นหาแพ็กเกจที่เหมาะกับโครงการของคุณอาจใช้เวลานาน เป็นการตัดสินใจเพิ่มเติมและอาจทำให้น่าหงุดหงิดหากดำเนินการไม่ได้ตามที่ต้องการ

การใช้การวางตำแหน่งจุดยึด

ป้อน API การวางตำแหน่ง Anchor ของ CSS แนวคิดก็คือการคงสไตล์ไว้ใน CSS และลดจำนวนการตัดสินใจที่ต้องทำ คุณหวังว่าจะได้รับผลลัพธ์เดียวกัน แต่เป้าหมายคือการทำให้นักพัฒนาแอปได้รับประสบการณ์ที่ดียิ่งขึ้น

  • ไม่ต้องใช้ JavaScript
  • ให้เบราว์เซอร์ทำงานในตำแหน่งที่ดีที่สุดจากคำแนะนำของคุณ
  • ไม่มีทรัพยากร Dependency ของบุคคลที่สามแล้ว
  • ไม่มีองค์ประกอบ Wrapper
  • ทำงานร่วมกับองค์ประกอบที่อยู่ในเลเยอร์บนสุด

มาลองแก้ไขปัญหาที่เราพยายามแก้ไขข้างต้นอีกครั้ง แต่ให้ใช้การอุปมาอุปไมยของเรือที่มีสมอ องค์ประกอบเหล่านี้แสดงถึงองค์ประกอบที่ตรึงไว้และแท็ก Anchor ส่วนน้ำแสดงถึงบล็อกที่มี

ก่อนอื่น คุณต้องเลือกวิธีกำหนดแท็ก Anchor ซึ่งทำได้ภายใน CSS โดยการตั้งค่าพร็อพเพอร์ตี้ anchor-name ในองค์ประกอบ Anchor ยอมรับค่า id-ident

.anchor {
  anchor-name: --my-anchor;
}

หรือจะกำหนดแท็ก Anchor ใน HTML ด้วยแอตทริบิวต์ anchor ก็ได้ ค่าแอตทริบิวต์คือรหัสขององค์ประกอบแท็ก Anchor ซึ่งจะสร้าง Anchor โดยนัย

<a id="my-anchor" class="anchor"></a>
<div anchor="my-anchor" class="boat">I’m a boat!</div>

เมื่อคุณกำหนดแท็ก Anchor แล้ว คุณสามารถใช้ฟังก์ชัน anchor ได้ ฟังก์ชัน anchor รับอาร์กิวเมนต์ 3 รายการ ดังนี้

  • องค์ประกอบ Anchor: anchor-name ของแท็ก Anchor ที่จะใช้ หรือคุณสามารถละเว้นค่าเพื่อใช้แท็ก Anchor implicit ก็ได้ ซึ่งสามารถกำหนดผ่านความสัมพันธ์ HTML หรือพร็อพเพอร์ตี้ anchor-default ที่มีค่า anchor-name
  • ด้าน Anchor: คีย์เวิร์ดของตําแหน่งที่ต้องการใช้ ซึ่งอาจเป็น top, right, bottom, left, center ฯลฯ หรือคุณจะส่งผ่านเปอร์เซ็นต์ก็ได้ เช่น 50% จะเท่ากับ center
  • วิดีโอสำรอง: เป็นค่าสำรองที่ไม่บังคับซึ่งยอมรับความยาวหรือเปอร์เซ็นต์

คุณใช้ฟังก์ชัน anchor เป็นค่าสำหรับพร็อพเพอร์ตี้ Inset (top, right, bottom, left หรือเทียบเท่าทางตรรกะ) ขององค์ประกอบที่ตรึงไว้ คุณยังใช้ฟังก์ชัน anchor ใน calc ได้ด้วย โดยทำดังนี้

.boat {
  bottom: anchor(--my-anchor top);
  left: calc(anchor(--my-anchor center) - (var(--boat-size) * 0.5));
}

 /* alternative with anchor-default */
.boat {
  anchor-default: --my-anchor;
  bottom: anchor(top);
  left: calc(anchor(center) - (var(--boat-size) * 0.5));
}

ไม่มีพร็อพเพอร์ตี้ Inset center ดังนั้นตัวเลือกหนึ่งคือการใช้ calc หากคุณทราบขนาดขององค์ประกอบที่ตรึงไว้ เหตุใดจึงไม่ใช้ translate โดยคุณสามารถใช้คำสั่งต่อไปนี้

.boat {
  anchor-default: --my-anchor;
  bottom: anchor(top);
  left: anchor(center);
  translate: -50% 0;
}

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

คุณอาจสังเกตเห็นว่าด้านบนใช้พร็อพเพอร์ตี้ที่กำหนดเอง --boat-size แต่หากต้องการยึดขนาดองค์ประกอบที่ตรึงไว้ตามขนาดของ Anchor ก็เข้าถึงขนาดดังกล่าวได้เช่นกัน คุณใช้ฟังก์ชัน anchor-size แทนการคำนวณด้วยตนเองได้ เช่น หากต้องการทำให้เรือของเรากว้างเป็น 4 เท่าของความกว้างของสมอเรือ

.boat {
  width: calc(4 * anchor-size(--my-anchor width));
}

คุณยังเข้าถึงความสูงได้ด้วยanchor-size(--my-anchor height) และจะใช้เพื่อกำหนดขนาดของแกนใดแกนหนึ่งหรือทั้ง 2 แกนได้

หากคุณต้องการตรึงองค์ประกอบที่มีการจัดตำแหน่ง absolute กฎคือองค์ประกอบต้องไม่เป็นระดับเดียวกัน ในกรณีดังกล่าว คุณจะรวม Anchor กับคอนเทนเนอร์ที่มีตําแหน่ง relative ได้ จากนั้นคุณก็จะยึดติดกับชิ้นงานนั้นได้

<div class="anchor-wrapper">
  <a id="my-anchor" class="anchor"></a>
</div>
<div class="boat">I’m a boat!</div>

ลองดูการสาธิตที่คุณสามารถลากสมอหมุนไปรอบๆ แล้วเรือจะตามมา

ตำแหน่งการเลื่อนการติดตาม

ในบางกรณี องค์ประกอบ Anchor อาจอยู่ในคอนเทนเนอร์แบบเลื่อน ในขณะเดียวกัน องค์ประกอบที่ตรึงไว้อาจอยู่นอกคอนเทนเนอร์นั้น เนื่องจากการเลื่อนเกิดขึ้นในชุดข้อความที่ต่างจากเลย์เอาต์ คุณจึงต้องมีวิธีติดตาม พร็อพเพอร์ตี้ anchor-scroll ทำสิ่งต่อไปนี้ได้ โดยตั้งค่าในองค์ประกอบที่ตรึงไว้ในองค์ประกอบที่กำหนด และระบุค่าของ Anchor ที่ต้องการติดตาม

.boat { anchor-scroll: --my-anchor; }

ลองดูการสาธิตนี้ ซึ่งคุณจะเปิดและปิด anchor-scroll ได้ด้วยช่องทำเครื่องหมายที่มุม

แต่ตัวเทียบเคียงจะมีลักษณะเป็นแนวราบเล็กน้อย ดังเช่นในอุดมคติ เรือและสมอเรือของคุณต่างก็จมอยู่ในน้ำ นอกจากนี้ ฟีเจอร์ต่างๆ อย่าง Popover API ก็โปรโมตว่าสามารถเก็บองค์ประกอบที่เกี่ยวข้องไว้ใกล้ตัวได้ แต่การวางตำแหน่งจุดยึดจะทำงานร่วมกับองค์ประกอบที่อยู่ในเลเยอร์บนสุด ซึ่งหนึ่งในประโยชน์หลักของ API นี้คือความสามารถในการเชื่อมต่ออินเทอร์เน็ตผ่านองค์ประกอบต่างๆ ในช่องทางต่างๆ

ลองดูการสาธิตนี้ซึ่งมีคอนเทนเนอร์แบบเลื่อนซึ่งมีแท็ก Anchor ซึ่งมีเคล็ดลับเครื่องมือ องค์ประกอบเคล็ดลับเครื่องมือที่เป็นป๊อปอัปอาจไม่ได้ตั้งอยู่ร่วมกับ Anchor ดังนี้

แต่คุณจะสังเกตเห็นวิธีที่ป๊อปอัปติดตามลิงก์ Anchor ที่เกี่ยวข้อง คุณปรับขนาดคอนเทนเนอร์แบบเลื่อนได้และระบบจะอัปเดตตำแหน่งให้คุณ

ตำแหน่งสำรองและการวางตำแหน่งอัตโนมัติ

นี่คือจุดที่กำลังของตำแหน่งของจุดยึดจะสูงขึ้นหนึ่งระดับ position-fallback จะจัดตำแหน่งองค์ประกอบที่ตรึงไว้ในตำแหน่งตามชุดวิดีโอสำรองที่คุณให้ไว้ได้ คุณเป็นผู้กำหนดสไตล์ให้กับเบราว์เซอร์และปล่อยให้เบราว์เซอร์ทำงานให้เหมาะสมกับคุณ

Use Case ที่พบได้ทั่วไปคือเคล็ดลับเครื่องมือที่ควรเปลี่ยนระหว่างการแสดงเหนือหรือใต้แท็ก Anchor และลักษณะการทำงานนี้ขึ้นอยู่กับว่าคอนเทนเนอร์จะตัดเคล็ดลับเครื่องมือไปหรือไม่ คอนเทนเนอร์นั้นมักจะเป็นวิวพอร์ต

หากเจาะลึกโค้ดของการสาธิตล่าสุด คุณจะเห็นว่ามีการใช้พร็อพเพอร์ตี้ position-fallback อยู่ หากคุณเลื่อนคอนเทนเนอร์ คุณอาจเห็นว่าป๊อปอัปที่ยึดตำแหน่งอยู่เหล่านั้นกระโดดขึ้น เหตุการณ์นี้เกิดขึ้นเมื่อ Anchor ที่เกี่ยวข้องอยู่ใกล้ขอบเขตของวิวพอร์ต ในตอนนี้ ป๊อปอัปกำลังพยายามปรับเพื่อให้อยู่ในวิวพอร์ตต่อไป

ก่อนที่จะสร้าง position-fallback ที่ชัดเจน การกำหนดตำแหน่งจุดยึดจะเสนอการกำหนดตำแหน่งอัตโนมัติด้วย คุณพลิกนี้ไปได้ฟรีโดยใช้ค่า auto ทั้งในฟังก์ชัน Anchor และพร็อพเพอร์ตี้ Inset ตรงกันข้าม เช่น หากคุณใช้ anchor สําหรับ bottom ให้ตั้งค่า top เป็น auto

.tooltip {
  position: absolute;
  bottom: anchor(--my-anchor auto);
  top: auto;
}

อีกทางเลือกหนึ่งที่ใช้แทนการจัดตำแหน่งอัตโนมัติคือการใช้ position-fallback ที่ชัดเจน โดยคุณต้องกำหนดชุดตำแหน่งสำรอง เบราว์เซอร์จะตรวจสอบสิ่งเหล่านี้จนกว่าจะพบเบราว์เซอร์ที่ใช้ได้ จากนั้นจึงใช้การกำหนดตำแหน่งดังกล่าว หากไม่พบเครื่องมือที่ใช้งานได้ จะใช้ค่าเริ่มต้นเป็นกฎแรกที่กำหนดไว้

position-fallback ที่พยายามแสดงเคล็ดลับเครื่องมือด้านบนอาจมีลักษณะดังนี้

@position-fallback --top-to-bottom {
  @try {
    bottom: anchor(top);
    left: anchor(center);
  }

  @try {
    top: anchor(bottom);
    left: anchor(center);
  }
}

การนำค่านั้นไปใช้กับเคล็ดลับเครื่องมือจะมีลักษณะดังนี้

.tooltip {
  anchor-default: --my-anchor;
  position-fallback: --top-to-bottom;
}

การใช้ anchor-default หมายความว่าคุณจะใช้ position-fallback ซ้ำกับองค์ประกอบอื่นๆ ได้ คุณยังใช้พร็อพเพอร์ตี้ที่กำหนดเองซึ่งกำหนดขอบเขตเพื่อตั้งค่า anchor-default ได้ด้วย

ลองพิจารณาการสาธิตนี้โดยใช้เรืออีกครั้ง มีชุด position-fallback อยู่ เมื่อคุณเปลี่ยนตำแหน่งของสมอ เรือจะปรับให้ยังอยู่ในภาชนะบรรจุ ลองเปลี่ยนค่าระยะห่างจากขอบด้วย ซึ่งจะปรับระยะห่างจากขอบเนื้อหาด้วย สังเกตวิธีที่เบราว์เซอร์แก้ไขตำแหน่ง ตำแหน่งจะเปลี่ยนโดยการเปลี่ยนการจัดแนวตารางกริดของคอนเทนเนอร์

คราวนี้ลองจัดตำแหน่งในทิศทางตามเข็มนาฬิกามากกว่า position-fallback

.boat {
  anchor-default: --my-anchor;
  position-fallback: --compass;
}

@position-fallback --compass {
  @try {
    bottom: anchor(top);
    right: anchor(left);
  }

  @try {
    bottom: anchor(top);
    left: anchor(right);
  }

  @try {
    top: anchor(bottom);
    right: anchor(left);
  }

  @try {
    top: anchor(bottom);
    left: anchor(right);
  }
}


ตัวอย่าง

ตอนนี้คุณมีไอเดียเกี่ยวกับคุณลักษณะหลักๆ สำหรับการกำหนดตำแหน่งจุดยึดแล้ว มาดูตัวอย่างที่น่าสนใจนอกเหนือจากเคล็ดลับเครื่องมือกันดีกว่า ตัวอย่างเหล่านี้มีเป้าหมายที่จะทำให้ไอเดียของคุณลื่นไหลในการใช้การวางตำแหน่งโฆษณา Anchor วิธีที่ดีที่สุดในข้อกำหนดเพิ่มเติมคือการให้ข้อมูลจากผู้ใช้จริงเช่นคุณ

เมนูตามบริบท

เรามาเริ่มกันที่เมนูตามบริบทที่ใช้ Popover API แนวคิดคือการคลิกปุ่มที่มีเครื่องหมายบั้งจะแสดงเมนูตามบริบท และเมนูดังกล่าวจะมีเมนูของตัวเองให้ขยายออก

มาร์กอัปไม่ใช่ส่วนสำคัญในที่นี้ แต่มีปุ่ม 3 ปุ่มที่ใช้แต่ละปุ่ม popovertarget จากนั้นคุณก็มีองค์ประกอบ 3 อย่างโดยใช้แอตทริบิวต์ popover ซึ่งจะช่วยให้คุณเปิดเมนูตามบริบทได้โดยไม่ต้องใช้ JavaScript ซึ่งจะมีลักษณะดังนี้

<button popovertarget="context">
  Toggle Menu
</button>        
<div popover="auto" id="context">
  <ul>
    <li><button>Save to your Liked Songs</button></li>
    <li>
      <button popovertarget="playlist">
        Add to Playlist
      </button>
    </li>
    <li>
      <button popovertarget="share">
        Share
      </button>
    </li>
  </ul>
</div>
<div popover="auto" id="share">...</div>
<div popover="auto" id="playlist">...</div>

ตอนนี้คุณสามารถกำหนด position-fallback และแชร์ระหว่างเมนูตามบริบทได้แล้ว อย่าลืมยกเลิกการตั้งค่าสไตล์ inset สำหรับป๊อปอัปด้วย

[popovertarget="share"] {
  anchor-name: --share;
}

[popovertarget="playlist"] {
  anchor-name: --playlist;
}

[popovertarget="context"] {
  anchor-name: --context;
}

#share {
  anchor-default: --share;
  position-fallback: --aligned;
}

#playlist {
  anchor-default: --playlist;
  position-fallback: --aligned;
}

#context {
  anchor-default: --context;
  position-fallback: --flip;
}

@position-fallback --aligned {
  @try {
    top: anchor(top);
    left: anchor(right);
  }

  @try {
    top: anchor(bottom);
    left: anchor(right);
  }

  @try {
    top: anchor(top);
    right: anchor(left);
  }

  @try {
    bottom: anchor(bottom);
    left: anchor(right);
  }

  @try {
    right: anchor(left);
    bottom: anchor(bottom);
  }
}

@position-fallback --flip {
  @try {
    bottom: anchor(top);
    left: anchor(left);
  }

  @try {
    right: anchor(right);
    bottom: anchor(top);
  }

  @try {
    top: anchor(bottom);
    left: anchor(left);
  }

  @try {
    top: anchor(bottom);
    right: anchor(right);
  }
}

ซึ่งจะแสดง UI เมนูตามบริบทที่ซ้อนกันแบบปรับขนาดได้ ลองเปลี่ยนตำแหน่งเนื้อหาด้วยรายการที่เลือก ตัวเลือกที่คุณเลือกจะอัปเดตการจัดแนวตารางกริด ซึ่งจะส่งผลต่อการวางตำแหน่งหมุดยึดตำแหน่งป๊อปโอเวอร์

จดจ่อและทำตาม

เดโมนี้รวมค่าดั้งเดิมของ CSS ด้วยการนำ :has() เข้ามาด้วย แนวคิดคือเปลี่ยนสัญญาณบอกสถานะสำหรับ input ที่โฟกัสอยู่

ซึ่งทำได้โดยการตั้งค่า Anchor ใหม่ระหว่างรันไทม์ ในการสาธิตนี้ พร็อพเพอร์ตี้ที่กำหนดเองซึ่งกำหนดขอบเขตจะได้รับการอัปเดต ณ จุดโฟกัสของอินพุต

#email {
    anchor-name: --email;
  }
  #name {
    anchor-name: --name;
  }
  #password {
    anchor-name: --password;
  }
:root:has(#email:focus) {
    --active-anchor: --email;
  }
  :root:has(#name:focus) {
    --active-anchor: --name;
  }
  :root:has(#password:focus) {
    --active-anchor: --password;
  }

:root {
    --active-anchor: --name;
    --active-left: anchor(var(--active-anchor) right);
    --active-top: calc(
      anchor(var(--active-anchor) top) +
        (
          (
              anchor(var(--active-anchor) bottom) -
                anchor(var(--active-anchor) top)
            ) * 0.5
        )
    );
  }
.form-indicator {
    left: var(--active-left);
    top: var(--active-top);
    transition: all 0.2s;
}

แต่คุณจะพัฒนาไปไกลอีกได้อย่างไร ซึ่งคุณสามารถใช้สำหรับการซ้อนทับการสอนบางรูปแบบได้ เคล็ดลับเครื่องมือจะย้ายไปมาระหว่างจุดสนใจและอัปเดตเนื้อหาได้ คุณสามารถข้ามเนื้อหาไปได้ ภาพเคลื่อนไหวแบบต่อเนื่องที่อนุญาตให้คุณ ทำให้ display เคลื่อนไหว หรือ ดูการเปลี่ยน อาจทำงานที่นี่

การคำนวณแผนภูมิแท่ง

ความสนุกอีกอย่างที่คุณทำได้โดยใช้การกำหนดตำแหน่ง Anchor คือการรวมกับ calc ลองจินตนาการถึงแผนภูมิที่มีป๊อปอัปที่ใส่คำอธิบายประกอบในแผนภูมิ

คุณสามารถติดตามค่าสูงสุดและต่ำสุดได้โดยใช้ CSS min และ max CSS จะมีลักษณะดังนี้

.chart__tooltip--max {
    left: anchor(--chart right);
    bottom: max(
      anchor(--anchor-1 top),
      anchor(--anchor-2 top),
      anchor(--anchor-3 top)
    );
    translate: 0 50%;
  }

โดยมี JavaScript บางส่วนเพื่ออัปเดตค่าของแผนภูมิและ CSS บางรายการเพื่อปรับรูปแบบแผนภูมิ แต่การวางตำแหน่ง Anchor จะช่วยเราจัดการการอัปเดตเลย์เอาต์

ปรับขนาดแฮนเดิล

คุณไม่จำเป็นต้องตรึงเพียงองค์ประกอบเดียว คุณอาจใช้จุดยึดหลายรายการสำหรับองค์ประกอบหนึ่งๆ คุณอาจสังเกตเห็นว่าในตัวอย่างแผนภูมิแท่ง เคล็ดลับเครื่องมือตรึงอยู่กับแผนภูมิและแท่งที่เหมาะสม หากคุณเข้าใจแนวคิดดังกล่าวมากขึ้นอีกเล็กน้อย คุณสามารถใช้แนวคิดนั้นเพื่อปรับขนาดองค์ประกอบได้

คุณอาจใช้จุดยึดอย่างเช่นแฮนเดิลปรับขนาดที่กำหนดเอง และใช้ค่า inset

.container {
   position: absolute;
   inset:
     anchor(--handle-1 top)
     anchor(--handle-2 right)
     anchor(--handle-2 bottom)
     anchor(--handle-1 left);
 }

ในการสาธิตนี้ GreenSock Draggable จะทำให้แฮนเดิลลากได้ แต่องค์ประกอบ <img> จะปรับขนาดให้เต็มคอนเทนเนอร์ซึ่งปรับให้เต็มช่องว่างระหว่างแฮนเดิล

เลือกเมนู?

ข้อสุดท้าย นี้เป็นเพียงตัวอย่างเล็กน้อยเกี่ยวกับสิ่งที่จะเกิดขึ้น แต่คุณสามารถสร้างป๊อปอัปที่โฟกัสได้ และตอนนี้คุณมีตำแหน่งจุดยึดแล้ว คุณจะสร้างพื้นฐานขององค์ประกอบ <select> ที่กำหนดค่าได้

<div class="select-menu">
<button popovertarget="listbox">
 Select option
 <svg>...</svg>
</button>
<div popover="auto" id="listbox">
   <option>A</option>
   <option>Styled</option>
   <option>Select</option>
</div>
</div>

การกำหนด anchor โดยนัยจะช่วยให้ดำเนินการได้ง่ายขึ้น แต่ CSS สำหรับจุดเริ่มต้นเบื้องต้นอาจมีลักษณะดังนี้

[popovertarget] {
 anchor-name: --select-button;
}
[popover] {
  anchor-default: --select-button;
  top: anchor(bottom);
  width: anchor-size(width);
  left: anchor(left);
}

รวมฟีเจอร์ของ Popover API เข้ากับตำแหน่ง Anchor ของ CSS แค่นี้ก็เสร็จแล้ว

การเริ่มแนะนำสิ่งต่างๆ อย่าง :has() จะช่วยได้ คุณสามารถหมุนเครื่องหมายขณะเปิดได้โดยทําดังนี้

.select-menu:has(:open) svg {
  rotate: 180deg;
}

คุณจะพัฒนาไปตรงไหนต่อไป มีอะไรที่เราต้องมีอีกบ้างเพื่อทำให้เป็น select ที่ใช้งานได้ เราจะบันทึกไว้สำหรับบทความถัดไป แต่ไม่ต้องกังวล เรากำลังจะเปิดตัวองค์ประกอบที่เลือกสไตล์ได้ โปรดอดใจรอ


เท่านี้ก็เรียบร้อย

แพลตฟอร์มเว็บกำลังพัฒนา การจัดตำแหน่ง Anchor ของ CSS เป็นส่วนสำคัญในการปรับปรุงวิธีพัฒนาการควบคุม UI แต่จะทำให้คุณขจัดความยุ่งยากในการตัดสินใจ นอกจากนี้ยังช่วยให้คุณทำในสิ่งที่ไม่เคยได้ทำมาก่อนอีกด้วย เช่น การจัดรูปแบบองค์ประกอบ <select> บอกให้เรารู้ว่าคุณคิดอย่างไร

รูปภาพโดย CHUTTERSNAP ใน Unsplash