๐Ÿ™„ ์ƒ์„ธ ๋‚ด์šฉ ๋ณด๊ธฐ ( <details>, <summary> ) ๐Ÿ™„

๋ฐ•์ƒ์€ยท2022๋…„ 6์›” 16์ผ
1
post-thumbnail

๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ๋‹ซ์•„๋†จ๋‹ค๊ฐ€ ๋ˆ„๋ฅด๋ฉด ์•„๋ž˜๋กœ ์—ด๋ฆฌ๊ณ  ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ดค์Šต๋‹ˆ๋‹ค.
์˜ˆ์ „์— HTML5๋ฅผ ๊ณต๋ถ€ํ•˜๋‹ค๊ฐ€ ๋ณด๊ธฐ๋งŒ ํ•˜๊ณ  ์ง€๋‚˜๊ฐ”๋˜ <details>์™€ <summary>๊ฐ€ ์ƒ๊ฐ๋‚˜์„œ ๊ด€๋ จํ•ด์„œ ๊ตฌ๊ธ€๋งํ•ด๋ณด๋ฉด์„œ ๋ฐฉ๋ฒ•์„ ์ฐพ๊ณ  ์ ์šฉํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

๐Ÿ™ <details> ์‚ฌ์šฉ

๋ฐ”๋กœ ์•„๋ž˜ gif๋Š” ์Šคํƒ€์ผ๋ง ์ฒ˜๋ฆฌ๋งŒ ํ•œ ๊ฒฐ๊ณผ๋ฌผ์ธ๋ฐ ์ƒ๊ฐ๋ณด๋‹ค ๋„ˆ๋ฌด ์ •์ ์ธ ๋Š๋‚Œ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
transition์„ ์ ์šฉํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ˆ„๋ฅด๋ฉด ์„œ์„œํžˆ ์—ด๋ฆฌ๋Š” ๊ฒƒ์„ ์›ํ–ˆ์ง€๋งŒ ์ƒ๊ฐ์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜์ง€ ์•Š์•„์„œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ดค์Šต๋‹ˆ๋‹ค.

๐Ÿค” ResizeObserver ์‚ฌ์šฉ

๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ๋‹ค๊ฐ€ ResizeObserver์˜ ์กด์žฌ๋ฅผ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
ResizeObserver๋Š” ํŠน์ • ์—˜๋ฆฌ๋จผํŠธ์˜ ํฌ๊ธฐ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.
ํ•ด๋‹น ๊ธฐ๋Šฅ๊ณผ <details>๋ฅผ ํด๋ฆญํ•˜๋ฉด height๊ฐ€ ๋Š˜์–ด๋‚˜๋Š” ๊ฒƒ์„ ์ด์šฉํ•ด์„œ transition์„ ์ ์šฉํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ํšจ๊ณผ๋ฅผ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ResizeObserver ์‚ฌ์šฉ๋ฒ•
const RO = new ResizeObserver(callback)
RO.observe(element)

/*
 * callback์˜ ์ธ์ž๋Š” ResizeObserverEntry[]๊ฐ’์ด ๋“ค์–ด์˜ต๋‹ˆ๋‹ค.
 * ๊ด€์ฐฐํ•˜๋Š” ๋ชจ๋“  ์—˜๋ฆฌ๋จผํŠธ์˜ ํŠน์ • ์ •๋ณด๋ฅผ ๋‹ด์€ ResizeObserverEntry์˜ ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค.
*/
  • ResizeObserverEntry์˜ ์†์„ฑ๋“ค ( ์ž์„ธํ•œ ์ •๋ณด๋Š” mdn )
    1. target: ๊ด€์ฐฐ ๋Œ€์ƒ์ž…๋‹ˆ๋‹ค.
    2. contentRect: ๊ด€์ฐฐ ๋Œ€์ƒ์˜ ์‚ฌ๊ฐํ˜• ์ •๋ณด์ž…๋‹ˆ๋‹ค.
    3. ๋‚˜๋จธ์ง€๋Š” ์‚ฌ์šฉ ์•ˆํ•ด๋ด์„œ ์ƒ๋žต...

๐Ÿง ์‹ค์ œ ์ ์šฉ ์˜ˆ์‹œ

์•„๋ž˜์˜ ์˜ˆ์‹œ๋ฅผ ๋ณด๋ฉด์„œ ์–ด๋–ป๊ฒŒ ์ ์šฉํ–ˆ๋Š”์ง€ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ( ์ฐธ๊ณ ํ•œ ํฌ์ŠคํŠธ )

export const setDetailsHeight = (wrapper: HTMLElement) => {
  // ํŠน์ • <details>์˜ ๋‹ซํž˜๊ณผ ์—ด๋ฆผ์˜ ๊ฐ’์„ ๋ฏธ๋ฆฌ ๊ธฐ๋กํ•จ ( --expanded์™€ --collapsed์— ๊ธฐ๋ก )
  // width๋ฅผ dataset์— ๋„ฃ์–ด๋‘๋Š” ์ด์œ ๋Š” ์ฒ˜์Œ ์‹คํ–‰์ธ์ง€ ์•„๋‹Œ์ง€ ์ฆ‰, ๋‹ซํž˜๊ณผ ์—ด๋ฆผ์˜ ํฌ๊ธฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ธฐ๋กํ•˜๋Š” ๊ฒƒ์ธ์ง€ ํŒ๋‹จ์„ ์œ„ํ•ด์„œ
  const setHeight = (detail: HTMLDetailsElement, open = false) => {
    detail.open = open;
    const { width, height } = detail.getBoundingClientRect();
    detail.dataset.width = width + "";
    detail.style.setProperty(
      open ? `--expanded` : `--collapsed`,
      `${height}px`
    );
  };

  // ResizeObserver ๊ฐ์ฒด ์ƒ์„ฑ
  const RO = new ResizeObserver((entries) =>
    entries.forEach((entry) => {
      const detail = entry.target as HTMLDetailsElement;
      const width = detail.dataset.width ? +detail.dataset.width : -1;

      // ์ฒ˜์Œ ์‹คํ–‰์ด๋ผ๋ฉด ์ฆ‰, ํด๋ฆญ์— ์˜ํ•œ ์‹คํ–‰์ด ์•„๋‹ˆ๋ผ๋ฉด ์‹คํ–‰
      // ๋‹จ, ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์ด "entry.contentRect.width"๊ฐ’์—๋Š” padding์ด๋‚˜ border๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์€ ๊ฐ’์ž„
      // ๋”ฐ๋ผ์„œ ํ•ญ์ƒ width๊ฐ’์ด ๋งž์ง€ ์•Š์•„ if๋ฌธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์„œ <details>๊ฐ€ ์•ˆ์—ด๋ฆด ์ˆ˜ ์žˆ์Œ
      // ๊ทธ๋Ÿฌ๋ฏ€๋กœ details์— ์ง์ ‘์ ์œผ๋กœ padding์ด๋‚˜ border๋ฅผ ์•ˆ์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๊ณ  ๋งŒ์•ฝ ๊ฐ’์ด ์ค€๋‹ค๋ฉด ์ˆ˜์น˜๋ฅผ ๊ณ„์‚ฐํ•ด์„œ ์ง์ ‘ ๋”ํ•ด์ค˜์•ผ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•จ
      if (width !== entry.contentRect.width) {
        detail.removeAttribute("style");
        // ๋‹ซํž˜ ํฌ๊ธฐ ๊ธฐ๋ก
        setHeight(detail);
        // ์—ด๋ฆผ ํฌ๊ธฐ ๊ธฐ๋ก
        setHeight(detail, true);
        // ์›๋ž˜ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆผ
        detail.open = false;
      }
    })
  );

  // wrapper ๋‚ด๋ถ€์˜ ๋ชจ๋“  <details>์„ ์ฐพ์•„์„œ ๊ด€์ฐฐ ๋Œ€์ƒ์œผ๋กœ ์ง€์ •
  const details = wrapper.querySelectorAll("details");
  details.forEach((detail) => RO.observe(detail));
};

// setDetailsHeight()์— <details>๋“ค์„ ํฌํ•จํ•˜๋Š” ๊ฐ€์žฅ ์ƒ์œ„ ํƒœ๊ทธ๋ฅผ ์ธ์ž๋กœ ๋„ฃ์–ด์ฃผ๋ฉด ๋จ
// ๋ฌผ๋ก  document๋ฅผ ๋ฐ”๋กœ ๋„ฃ์–ด์ค˜๋„ ๋˜์ง€๋งŒ ์ „์ฒด ํƒ์ƒ‰๋ณด๋‹ค๋Š” <details>๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ œ์ผ ์ƒ์œ„ํƒœ๊ทธ๋ฅผ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒŒ ๋” ํšจ์œจ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•จ
  • global.css์— ์ž‘์„ฑํ•˜๊ธฐ
details {
  height: var(--collapsed);
  overflow: hidden;
  transition: height 300ms cubic-bezier(0.4, 0.01, 0.165, 0.99);
}
details[open] {
  height: var(--expanded);
}

๐Ÿ˜ฎ ResizeObserver ์ ์šฉ ๊ฒฐ๊ณผ๋ฌผ

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2023๋…„ 8์›” 30์ผ

๋„ˆ๋ฌด ์ข‹๋„ค์š”! ๋‚˜์ค‘์— ๊ผญ ์‚ฌ์šฉํ•ด๋ด์•ผ๊ฒ ์–ด์šฉ~

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ