์›”๊ฐ„ ํฌ๋กฌ ์ด์Šˆ ๋ฆฌํฌํŠธ 2024๋…„ 4์›”ํ˜ธ


๋“ค์–ด๊ฐ€๋ฉฐ

ํ”„๋ŸฐํŠธ์—”๋“œ ๊ฐœ๋ฐœ์— ๊ฐ€์žฅ ๋งŽ์€ ์˜ํ–ฅ์„ ์ฃผ๋Š” ํฌ๋กฌ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ฒ„์ „๋ณ„ ๋ณ€๊ฒฝ ์˜ˆ์ • ํ•ญ๋ชฉ์„ ์ •๋ฆฌ ๋ฐ ๊ณต์œ ํ•œ๋‹ค.

๐Ÿ’ก ๊ฐ ํ•ญ๋ชฉ์€ Chrome Platform Status์˜ Roadmap๊ณผ ํ•œ ๋‹ฌ๊ฐ„์˜ blink-dev ํ™œ๋™ ์š”์•ฝ์„ ๋ฐ”ํƒ•์œผ๋กœ ์ •๋ฆฌํ–ˆ๋‹ค.

๐Ÿ’ก ๊ฐ ํ•ญ๋ชฉ์˜ โš ๏ธ๋Š” ์ง€์› ์ค‘๋‹จ(Deprecated), โœ…๋Š” ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ(Enabled by default), ๐Ÿงช๋Š” ๋ฏธ๋ฆฌ ๋ณด๊ธฐ(Developer Trial, Origin Trial)๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

๐Ÿ’ก ๊ฐ ํ•ญ๋ชฉ ์ค‘ ๊ธฐ์กด ์„œ๋น„์Šค์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์ด ํฌ๋‹ค๊ณ  ํŒ๋‹จํ•œ ํ•ญ๋ชฉ์€ ์†Œ์ œ๋ชฉ ๋’ค์— ๐Ÿ“Œ ํ‘œ์‹œ๋ฅผ ํ–ˆ๋‹ค.

๐Ÿ’ก ์ง€์› ์ค‘๋‹จ(โš ๏ธ) ์™ธ์˜ ํ•ญ๋ชฉ์€ ๊ณต์œ  ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ•œ ๊ฒฝ์šฐ์—๋งŒ ํฌํ•จํ–ˆ๋‹ค.

๐Ÿ’ก ๋ฏธ๋ฆฌ ๋ณด๊ธฐ(๐Ÿงช)๋Š” chrome://flags ํŽ˜์ด์ง€์—์„œ Experimental Web Platform features๋ฅผ ํ™œ์„ฑํ™”(Developer Trial) ๋˜๋Š” ์ถœ์ฒ˜ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ(Origin Trial)๋ฅผ ์‹ ์ฒญํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ก ๊ฐ ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ Chrome Platform Status๋ฅผ ๊ทธ๋Œ€๋กœ ์ธ์šฉํ–ˆ๋‹ค.


๋ชฉ์ฐจ

  1. Chrome 125

    • โš ๏ธ enable-new-base-url-inheritance-behavior ๊ธฐ๋ณธ๊ฐ’ Disabled๋กœ ๋ณ€๊ฒฝ
    • โš ๏ธ Permissions-Policy "window-placement" ๋ณ„์นญ ์ œ๊ฑฐ
    • โœ… WebSocket์—์„œ http(s)๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝ
    • โœ… Compute Pressure API
    • โœ… CSS Anchor ๋ฐฐ์น˜
    • โœ… CSS round(), mod(), rem()
    • โœ… mousemove ์ด๋ฒคํŠธ ์ทจ์†Œ ์‹œ ๋™์ž‘ ๋ณ€๊ฒฝ ๐Ÿ“Œ
    • ๐Ÿงช HTMLVideoElement ์ „์ฒด ํ™”๋ฉด ์ ‘๋‘์‚ฌ API ์ œ๊ฑฐ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ
    • ๐Ÿงช ํด๋”๋ธ” ๊ธฐ๊ธฐ API ๋ฏธ๋ฆฌ ๋ณด๊ธฐ
    • ๐Ÿ—“๏ธ ๋ฐฐํฌ ์˜ˆ์ •์ผ
  2. Chrome 127

    • โš ๏ธ Mutation ์ด๋ฒคํŠธ ์ œ๊ฑฐ ๐Ÿ“Œ
    • โœ… ๊ณต๊ฐœ ์‚ฌ์ดํŠธ์—์„œ ๋‚ด๋ถ€๋ง์— ํ•˜์œ„ ์ž์› ์š”์ฒญ ์‹œ ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ ๊ฐ•์ œ ๐Ÿ“Œ
    • ๐Ÿ—“๏ธ ๋ฐฐํฌ ์˜ˆ์ •์ผ
  3. Chrome NEXT

    • โš ๏ธ [Chrome 129] DOMParser.parseFromString()์˜ includeShadowRoots ์˜ต์…˜ ์ง€์› ์ค‘๋‹จ
    • โœ… [Chrome 130] ๋‚ด๋ถ€๋ง ํŽ˜์ด์ง€ ์ด๋™ ์‹œ ์‚ฌ์ „ ์š”์ฒญ ๋ฐœ์†ก - ๊ฒฝ๊ณ  ๋ชจ๋“œ
    • โš ๏ธ unload ์ด๋ฒคํŠธ ์ง€์› ์ค‘๋‹จ ๐Ÿ“Œ
    • โš ๏ธ CSS ๊ตฌํ˜• ์‚ฌ์šฉ์ž ์ง€์ • ์ƒํƒœ ๋ฌธ๋ฒ• ์ง€์› ์ค‘๋‹จ
    • โš ๏ธ ์ œ3์ž ์ฟ ํ‚ค ์ง€์› ์ค‘๋‹จ ๐Ÿ“Œ

1. Chrome 125

โš ๏ธ enable-new-base-url-inheritance-behavior ์„ค์ • ์ œ๊ฑฐ

chrome://flags#enable-new-base-url-inheritance-behavior ์„ค์ •์„ ์ œ๊ฑฐํ•œ๋‹ค.

์œ„ ์„ค์ •์€ ์ž์‹ ์ฐฝ์—์„œ srcdoc์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ about:blank ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ ๋ถ€๋ชจ์˜ <base> ์†์„ฑ์„ ๋ช…์„ธ์—์„œ ์ •์˜ํ•œ ๋Œ€๋กœ ์ƒ์†๋ฐ›์ง€ ์•Š๋Š” ๋ฒ„๊ทธ์˜ ์ž„์‹œ ์กฐ์น˜๋ฅผ ์œ„ํ•ด ์ถ”๊ฐ€ํ•œ ์†์„ฑ์ด๋‹ค. Chrome 118๋ถ€ํ„ฐ ๊ธฐ๋ณธ๊ฐ’์ด Enabled์˜€์œผ๋ฉฐ, ํ•ด๋‹น ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•ด ์ž„์‹œ ์ถ”๊ฐ€ํ–ˆ๋˜ ์„ค์ •์„ ์ œ๊ฑฐํ•œ๋‹ค.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Firefox: ์˜๊ฒฌ ์—†์Œ
  • Safari: ์˜๊ฒฌ ์—†์Œ
  • ์›น ๊ฐœ๋ฐœ์ž: ์˜๊ฒฌ ์—†์Œ

์ฐธ์กฐ


โš ๏ธ Permissions-Policy "window-placement" ๋ณ„์นญ ์ œ๊ฑฐ

window-management๋Š” ๋ธŒ๋ผ์šฐ์ € ์ฐฝ์„ ์ œ์–ดํ•˜๋Š” Window Management API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ถŒํ•œ์ด๋‹ค.

์ฒ˜์Œ์— ์ด API๋Š” ํ•˜์œ„ ์ฐฝ(window.open)์˜ ์œ„์น˜๋ฅผ ์ œ์–ดํ•˜๋Š” ๊ธฐ๋Šฅ์—๋งŒ ์ดˆ์ ์„ ๋‘์—ˆ๋‹ค. ๊ถŒํ•œ์˜ ์ด๋ฆ„๋„ window-placement์˜€์œผ๋‚˜, API๊ฐ€ ์ฐฝ์˜ ํฌ๊ธฐ ๋“ฑ ์œ„์น˜ ๋ง๊ณ ๋„ ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋„๋ก ๋ฐ”๋€Œ๋ฉด์„œ ๋ณด๋‹ค ๋„“์€ ์˜๋ฏธ์˜ window-management๋กœ ๋ช…์„ธ๋ฅผ ์ˆ˜์ •ํ–ˆ๋‹ค.

๋น„ํ‘œ์ค€ API์ธ ๋งŒํผ Chrome ํŒ€์€ ๋”ฐ๋กœ ์ง€์› ์ค‘๋‹จ ๊ธฐ๊ฐ„ ์—†์ด ์ด๋ฒˆ ์—…๋ฐ์ดํŠธ์—์„œ ๋ฐ”๋กœ window-placement๋ฅผ ์ œ๊ฑฐํ•  ์˜ˆ์ •์ด๋‹ค. Chrome 111๋ถ€ํ„ฐ window-management๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์—…๋ฐ์ดํŠธ ์ „์— ๋ฏธ๋ฆฌ ๋ณ€๊ฒฝํ•˜๊ธฐ๋ฅผ ๊ถŒ์žฅํ•œ๋‹ค.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Firefox: ์˜๊ฒฌ ์—†์Œ
  • Safari: ํ•ด๋‹น ์—†์Œ
  • ์›น ๊ฐœ๋ฐœ์ž: ์˜๊ฒฌ ์—†์Œ

์ฐธ์กฐ


โœ… WebSocket์—์„œ http(s)๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝ

WebSocket ์ƒ์„ฑ์ž๊ฐ€ http ๋˜๋Š” https๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•œ๋‹ค. ๊ธฐ์กด์—๋Š” ws๋‚˜ wss์„ ์‚ฌ์šฉํ•˜๋Š” ์ ˆ๋Œ€ ๊ฒฝ๋กœ์˜ URL๋งŒ ํ—ˆ์šฉํ•ด WebSocket ์‚ฌ์šฉ ์‹œ ๋ถˆํŽธํ•จ์ด ์žˆ์—ˆ๋‹ค. ์—…๋ฐ์ดํŠธ ์ดํ›„์—๋Š” http, https ํ”„๋กœํ† ์ฝœ๊ณผ ์ƒ๋Œ€ ๊ฒฝ๋กœ URL์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด WebSocket ๊ฐœ๋ฐœ์ด ์ข€ ๋” ์‰ฌ์›Œ์งˆ ์˜ˆ์ •์ด๋‹ค.

// ํ˜„์žฌ๋Š” ์ƒ๋Œ€ ๊ฒฝ๋กœ ์‚ฌ์šฉ ์‹œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
// Failed to construct 'WebSocket': The URL '/channel' is invalid.
const socket = new WebSocket('/channel');

WebSocket ์ƒ์„ฑ์ž๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ž๊ฐ€ http(s) ํ”„๋กœํ† ์ฝœ์ด๋‚˜ ์ƒ๋Œ€ ๊ฒฝ๋กœ์ผ ๊ฒฝ์šฐ, URL์„ ๋Œ€์‘ํ•˜๋Š” ws(s)๋กœ ๋ฐ”๊พธ์–ด ์š”์ฒญํ•œ๋‹ค.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


โœ… Compute Pressure API

Compute Pressure API๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ์‹œ์Šคํ…œ์˜ ๋ถ€ํ•˜ ์ •๋„์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ œ๊ณตํ•˜๋Š” API๋กœ, ํ™”์ƒ ํšŒ์˜๋‚˜ ๊ฒŒ์ž„ ๋“ฑ ๋ฌด๊ฑฐ์šด ์›น ์•ฑ์—์„œ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

if ('PressureObserver' in globalThis) {
  const observer = new PressureObserver(
    (records) => {
      records.forEach((record) => {
        if (record.source === 'cpu') {
          console.log(`CPU ๋ถ€ํ•˜ ์ƒํƒœ(time: ${record.time}): ${record.state}`);
          // ์˜ˆ์‹œ) CPU ๋ถ€ํ•˜ ์ƒํƒœ(time: 1708051909444): critical

          if (record.state === 'critical') {
            setResolution(360);
          } else if (record.state === 'serious') {
            setResolution(720);
          }
        }
      });
    },
    {
      sampleInterval: 2000, // ๋‹จ์œ„: ๋ฐ€๋ฆฌ์ดˆ(ms)
    }
  );

  await observer.observe('cpu');

  buttonElement.onclick = () => {
    observer.disconnect();
  };
}

์ด๋ฒˆ ์—…๋ฐ์ดํŠธ์—์„œ๋Š” CPU ์ƒํƒœ๋งŒ ์ง€์›ํ•˜๋‚˜, ๋‚˜์ค‘์—๋Š” ์˜จ๋„๋‚˜ ๋ฐฐํ„ฐ๋ฆฌ ์ƒํƒœ ๋“ฑ์˜ ์ •๋ณด๋„ ํฌํ•จํ•  ์˜ˆ์ •์ด๋‹ค. ๋‹ค๋งŒ Safari๋Š” ํ•ด๋‹น ๊ธฐ๋Šฅ์— ๋ถ€์ •์ ์ธ ์ž…์žฅ์ด๋‹ค. ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€ํ•˜๋Š” ๋ถ€ํ•˜ ์ •๋ณด๋ฅผ ์ •ํ™•ํžˆ ์ „๋‹ฌํ•˜๊ธฐ ์–ด๋ ต๊ณ , ์‹œ์Šคํ…œ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋งŒํผ ๋ณด์•ˆ ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๊ฒฌ์ด๋‹ค.

Chrome์€ Safari์˜ ์˜๊ฒฌ์„ ๋ฐ›์•„๋“ค์—ฌ ์ผ๋‹จ ๋ถ€ํ•˜ ์ƒํƒœ๋ฅผ ๊ฐ„๋žตํ•˜๊ฒŒ๋งŒ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ช…์„ธ๋ฅผ ์ˆ˜์ •ํ–ˆ๋‹ค. ์•„์ง ์ œ์•ˆ ์ค‘์ธ API์ธ ๋งŒํผ ๋ช…์„ธ๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์ž.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


โœ… CSS Anchor ๋ฐฐ์น˜

ํŠน์ • ์š”์†Œ์— ๊ธฐ๋ฐ˜ํ•ด ํ˜„์žฌ ์š”์†Œ๋ฅผ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ๋Š” Anchor ๋ฐฐ์น˜ ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ํŠนํžˆ ํˆดํŒ ๋“ฑ์„ ๊ตฌํ˜„ํ•  ๋•Œ ์œ ์šฉํ•œ๋ฐ, absolute ๋ฐฐ์น˜์™€ ๋น„์Šทํ•˜๋‚˜ DOM ๊ตฌ์กฐ์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  ํˆดํŒ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ๋‹ค๋ฅด๋‹ค.

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

.tooltip {
  position: fixed;
  position-anchor: --tooltip;
  inset-area: top right;
  position-try: flip-block;
  min-width: anchor-size(width);
}

์˜ˆ์ œ์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด .tooltip์€ .anchor ์š”์†Œ์˜ ์˜ค๋ฅธ์ชฝ ์œ„์— ๋‚˜ํƒ€๋‚œ๋‹ค. ๋งŒ์•ฝ .tooltip์ด ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด์„ ๋ฒ—์–ด๋‚œ๋‹ค๋ฉด position-try: flip-block์— ์˜ํ•ด .anchor ์š”์†Œ์˜ ์•„๋ž˜์— ๋ฐฐ์น˜๋œ๋‹ค.

anchor-name์—๋Š” ํ•ด๋‹น Anchor์˜ ์ด๋ฆ„์„ ์„ ์–ธํ•˜๋ฉฐ, ํ•ด๋‹น Anchor์— ๋ฐฐ์น˜ํ•  ์š”์†Œ์—์„œ ์ด ์ด๋ฆ„์œผ๋กœ ํ•ด๋‹น ์š”์†Œ์˜ ์œ„์น˜๋‚˜ ํฌ๊ธฐ ๋“ฑ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. anchor() ํ•จ์ˆ˜๋Š” ํ•ด๋‹น Anchor์˜ ์œ„์น˜๊ฐ’์„, anchor-size()๋Š” ํ•ด๋‹น Anchor์˜ ํฌ๊ธฐ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋กœ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์•„๋ž˜์ฒ˜๋Ÿผ Anchor์˜ ์ด๋ฆ„์„ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค.

.tooltip {
  bottom: anchor(--tooltip top);
  max-width: anchor-size(--tooltip width);
}

๋งŒ์•ฝ ํ•ด๋‹น ์š”์†Œ์— position-anchor๋ฅผ ์„ค์ •ํ–ˆ๋‹ค๋ฉด ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.

.tooltip {
  position-anchor: --tooltip;
  bottom: anchor(top);
  max-width: anchor-size(width);
}

@position-try ๊ทœ์น™์„ ์„ ์–ธํ•˜๋ฉด ํ•ด๋‹น ์š”์†Œ๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด์„ ๋ฒ—์–ด๋‚  ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์Šคํƒ€์ผ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

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

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

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

#tooltip {
  position: fixed;
  position-try-options: --tooltip-position;
}

์œ„ ์ฝ”๋“œ๋Š” ๋จผ์ € Anchor์˜ ์™ผ์ชฝ ์•„๋ž˜์— ๋ฐฐ์น˜๋ฅผ ์‹œ๋„ํ•˜๋ฉฐ, ๋งŒ์•ฝ ํ™”๋ฉด์„ ๋ฒ—์–ด๋‚˜๋ฉด Anchor์˜ ์™ผ์ชฝ ์œ„, ๋งˆ์ง€๋ง‰์œผ๋กœ Anchor์— ์˜ค๋ฅธ์ชฝ ์•„๋ž˜์— #tooltip์„ ๋ฐฐ์น˜ํ•˜๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ์•„์ง ์ดˆ์•ˆ์œผ๋กœ ๋ช…์„ธ๋‚˜ ๋™์ž‘์ด ๋ฐ”๋€” ์ˆ˜ ์žˆ์Œ์— ์ฃผ์˜ํ•˜์ž.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


โœ… CSS round(), mod(), rem()

๊ฐ’์„ ์—ฐ์‚ฐํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” round(), mod(), rem() CSS ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

round()๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ž์˜ ๊ฐ’์— ๋”ฐ๋ผ ๋‘ ๋ฒˆ์งธ ๊ฐ’์„ ์—ฐ์‚ฐํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

width: round(nearest, var(--height), 50px);

round()์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ๋Š” up, down, to-zero, nearest๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ์ด๋“ค์€ ๊ฐ๊ฐ ์˜ฌ๋ฆผ, ๋‚ด๋ฆผ, ๋ฒ„๋ฆผ, ๋ฐ˜์˜ฌ๋ฆผ์„ ์„ธ ๋ฒˆ์งธ ์ธ์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ๊ธฐ๋ณธ๊ฐ’์€ nearest์ด๋‹ค.

width: round(up, 101px, 50px); /* 150px */
width: round(down, -101px, 10px); /* -110px */
width: round(to-zero, -101px, 10px); /* -100px */
width: round(27px, 5px); /* 25px, ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋ฅผ ์ƒ๋žตํ•˜๋ฉด ๊ธฐ๋ณธ๊ฐ’์ธ nearest๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. */

mod()์™€ rem()์€ ๋‚˜๋จธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ % ์—ฐ์‚ฐ์ž์™€ ๊ธฐ๋Šฅ์ ์œผ๋กœ ์œ ์‚ฌํ•˜๋‹ค. ๋‘ ํ•จ์ˆ˜๋Š” ๋ถ€ํ˜ธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์ด ๋‹ค๋ฅธ๋ฐ, mod()๋Š” ๋ถ€ํ˜ธ๋ฅผ ๋‘ ๋ฒˆ์งธ ์ธ์ž์—์„œ ๊ฐ€์ ธ์˜ค๋ฉฐ, rem()์€ ์ฒซ ๋ฒˆ์งธ ์ธ์ž์—์„œ ๋ถ€ํ˜ธ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

rotate: mod(-90deg, 20deg); /* 10deg */
rotate: mod(90deg, -20deg); /* -10deg */
rotate: rem(-90deg, 20deg); /* -10deg */
rotate: rem(90deg, -20deg); /* 10deg */

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Firefox: ๋ฐฐํฌ ์™„๋ฃŒ
  • Safari: ๋ฐฐํฌ ์™„๋ฃŒ
  • ์›น ๊ฐœ๋ฐœ์ž: ๊ธ์ •์ 

์ฐธ์กฐ


โœ… mousemove ์ด๋ฒคํŠธ ์ทจ์†Œ ์‹œ ๋™์ž‘ ๋ณ€๊ฒฝ ๐Ÿ“Œ

๋ช…์„ธ์— ๋”ฐ๋ผ mousemove ์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œ(event.preventDefault())ํ–ˆ์„ ๋•Œ ํ…์ŠคํŠธ ์„ ํƒ, ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ์„ ์ทจ์†Œํ•˜์ง€ ์•Š๋„๋ก ๋ณ€๊ฒฝํ•œ๋‹ค. ํ…์ŠคํŠธ ์„ ํƒ๊ณผ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ์„ mousemove ์ด๋ฒคํŠธ์˜ ๊ธฐ๋ณธ ๋™์ž‘์—์„œ ์ œ์™ธํ•˜๋Š” ๊ฒƒ์œผ๋กœ, Safari์™€ Firefox๋Š” ์ž‘๋…„ ํ•˜๋ฐ˜๊ธฐ์— ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ๋ฐ˜์˜ํ–ˆ๋‹ค.

๊ธฐ์กด์ฒ˜๋Ÿผ ํ…์ŠคํŠธ ์„ ํƒ์€ selectstart ์ด๋ฒคํŠธ๋ฅผ, ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ์€ dragstart ์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ธฐ๋ณธ ๋™์ž‘์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ mousemove ์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์œ„ ๊ธฐ๋Šฅ์„ ๋ง‰์•˜๋‹ค๋ฉด selectstart์™€ dragstart ์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

element.addEventListener('selectstart', (event) => {
  event.preventDefault();
});
element.addEventListener('dragstart', (event) => {
  event.preventDefault();
});

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


๐Ÿงช HTMLVideoElement ์ „์ฒด ํ™”๋ฉด ์ ‘๋‘์‚ฌ API ์ œ๊ฑฐ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ

<video> ์š”์†Œ์˜ ์ผ๋ถ€ ์ ‘๋‘์‚ฌ API ์ œ๊ฑฐ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

์ง€๊ธˆ์€ ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ Element.requestFullscreen() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด <video> ์š”์†Œ๊ฐ€ ์•„๋‹ˆ๋ผ๋„ ํŠน์ • ์š”์†Œ๋ฅผ ์ „์ฒด ํ™”๋ฉด์œผ๋กœ ๋„์šธ ์ˆ˜ ์žˆ๋‹ค. ์ œ๊ฑฐ ์˜ˆ์ •์ธ API๋Š” ๊ณผ๊ฑฐ <video> ์š”์†Œ์˜ ์ „์ฒด ํ™”๋ฉด ์ง€์›์„ ์œ„ํ•ด ์ ‘๋‘์‚ฌ(webkit)๋ฅผ ๋ถ™์—ฌ ์ถ”๊ฐ€ํ–ˆ๋˜ ์†์„ฑ์œผ๋กœ, Chrome 38 ๋ฒ„์ „๋ถ€ํ„ฐ ์ง€์› ์ค‘๋‹จ๋˜์—ˆ๋‹ค.

Chrome๋„ 71 ๋ฒ„์ „๋ถ€ํ„ฐ Fullscreen API๋ฅผ ์ง€์›ํ•˜๋‹ˆ ์•„์ง ์ด์ „ API๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ํ•ด๋‹น API๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฒˆ์— ์ œ๊ฑฐ๋˜๋Š” ์†์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

- boolean webkitSupportsFullscreen;
- boolean webkitDisplayingFullscreen;
- void webkitEnterFullscreen();
- void webkitExitFullscreen();
- void webkitEnterFullScreen();
- void webkitExitFullScreen();

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


๐Ÿงช ํด๋”๋ธ” ๊ธฐ๊ธฐ API ๋ฏธ๋ฆฌ ๋ณด๊ธฐ

ํด๋”๋ธ” ๊ธฐ๊ธฐ์˜ ์ ‘์Œ/ํŽผ์นจ ์ƒํƒœ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋Š” Device Posture API์™€ ํ™”๋ฉด ๋ถ„ํ•  ๊ฐœ์ˆ˜์— ๋”ฐ๋ฅธ ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” Viewport Segments Enumeration API์˜ ์ถœ์ฒ˜ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ๋‘ API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํด๋”๋ธ” ๊ธฐ๊ธฐ์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ๋งž์ถค UI๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

navigator.devicePosture.addEventListener('change', () => {
  const postureType = navigator.devicePosture.type; // "continuous" ๋˜๋Š” "folded"

  console.log(postureType === 'folded' ? '์ ‘ํž˜' : 'ํŽผ์นจ');
});
@media (device-posture: folded) and (horizontal-viewport-segments: 2) and (vertical-viewport-segments: 1) {
  .main {
    grid-template-columns: repeat(3, 200px);
  }
}

horizontal-viewport-segments์™€ vertical-viewport-segments๋Š” ๊ฐ๊ฐ ํžŒ์ง€ ๋“ฑ์œผ๋กœ ๋‚˜๋ˆ„์–ด์ง„ ๊ฐ€๋กœ, ์„ธ๋กœ ๋…ผ๋ฆฌ์  ํ™”๋ฉด์˜ ๊ฐœ์ˆ˜๋ฅผ ๋งํ•œ๋‹ค. ์ด API๋Š” ์•„์ง ์ดˆ์•ˆ์œผ๋กœ ๋ช…์„ธ๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์ž.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Firefox: ์˜๊ฒฌ ์—†์Œ
  • Safari: ์˜๊ฒฌ ์—†์Œ
  • ์›น ๊ฐœ๋ฐœ์ž: ์˜๊ฒฌ ์—†์Œ

์ฐธ์กฐ


๐Ÿ—“๏ธ ๋ฐฐํฌ ์˜ˆ์ •์ผ

Chrome 125๋Š” 2024๋…„ 5์›” 8์ผ์— ์ •์‹ ๋ฐฐํฌ ์˜ˆ์ •์ด๋‹ค.


2. Chrome 127

โš ๏ธ Mutation ์ด๋ฒคํŠธ ์ œ๊ฑฐ ๐Ÿ“Œ

MutationEvent๋Š” DOM ์š”์†Œ์— ๋ณ€๊ฒฝ์ด ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋กœ, DOMSubtreeModified, DOMNodeInserted, DOMNodeRemoved ๋“ฑ์ด ์žˆ๋‹ค.

element.addEventListener(
  'DOMNodeInserted',
  (event) => {
    console.log('์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ๊ฐ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค.', event.srcElement);
  },
  false
);

element.append(document.createElement('span'));

// ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ๊ฐ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค. <span></span>

์ด ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด DOM ๋ณ€๊ฒฝ์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, ์„ค๊ณ„์ƒ ๊ฒฐํ•จ๊ณผ ์น˜๋ช…์ ์ธ ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ์ด์œ ๋กœ 2011๋…„์— ํ‘œ์ค€์—์„œ ํ‡ด์ถœ๋˜์—ˆ๋‹ค.

2012๋…„์— ๋” ์•ˆ์ •์ ์ธ MutationObserver๊ฐ€ ๋“ฑ์žฅํ•˜์—ฌ ํ˜„์žฌ ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ด ์ด๋ฒคํŠธ ์‚ฌ์šฉ ์‹œ ์ฝ˜์†”์— ๊ฒฝ๊ณ ๋ฅผ ๋…ธ์ถœํ•œ๋‹ค. ์—…๋ฐ์ดํŠธ ํ›„์—๋Š” ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ธฐ์— ์•„์ง MutationEvent๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด MutationObserver๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

const observer = new MutationObserver((mutations) => {
  for (const mutation of mutations) {
    if (mutation.type === 'childList') {
      console.log('์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ๊ฐ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค.', ...mutation.addedNodes);
    }
  }
});

observer.observe(element, { childList: true });
element.append(document.createElement('span'));

// ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ๊ฐ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค. <span></span>

๋งŒ์•ฝ ์ข€ ๋” MutationEvent๋ฅผ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ํ•œ๋‹ค๋ฉด ์ถœ์ฒ˜ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๋ฅผ ์‹ ์ฒญํ•ด Chrome 134(2025๋…„ 3์›” ๋ฐฐํฌ ์˜ˆ์ •) ๋ฒ„์ „๊นŒ์ง€ MutationEvent๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


โœ… ๊ณต๊ฐœ ์‚ฌ์ดํŠธ์—์„œ ๋‚ด๋ถ€๋ง์— ํ•˜์œ„ ์ž์› ์š”์ฒญ ์‹œ ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ ๊ฐ•์ œ ๐Ÿ“Œ

๊ณต๊ฐœ ์›น ์‚ฌ์ดํŠธ์—์„œ ๋‚ด๋ถ€๋ง์— ํ•˜์œ„ ์ž์›(.js, .css ๋“ฑ) ์š”์ฒญ ์‹œ ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ(TLS)๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฐ•์ œํ•œ๋‹ค. Private Network Access ์ ์šฉ์˜ ์ผ๋ถ€๋กœ, ์‚ฌ์šฉ์ž์˜ ๊ธฐ๊ธฐ ๋“ฑ ๋‚ด๋ถ€๋ง์— ์ž์›์„ ์š”์ฒญํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ๋ณด์•ˆ ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๋ธŒ๋ผ์šฐ์ €๋Š” ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์—ฐ๊ฒฐ์ด ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋ฉฐ, ๋ณด์•ˆ ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์š”์ฒญ์„ ์‹คํŒจ ์ฒ˜๋ฆฌํ•œ๋‹ค. Chrome 124์—์„œ ํ•ด๋‹น ๊ทœ์น™์˜ ์™„ํ™” ๊ธฐ๋Šฅ์„ ํ•ด๋‹น ๊ทœ์น™์˜ ์™„ํ™” ๊ธฐ๋Šฅ์„ ์ ์šฉํ–ˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์ž.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


๋ฐฐํฌ ์˜ˆ์ •์ผ

Chrome 127๋Š” 2024๋…„ 7์›” 17์ผ์— ์ •์‹ ๋ฐฐํฌ ์˜ˆ์ •์ด๋‹ค.


3. Chrome NEXT

โš ๏ธ [Chrome 129] DOMParser.parseFromString()์˜ includeShadowRoots ์˜ต์…˜ ์ง€์› ์ค‘๋‹จ

DOMParser.parseFromString()์˜ includeShadowRoots ์˜ต์…˜์„ ์ง€์› ์ค‘๋‹จํ•œ๋‹ค. DOMParser.parseFromString()์€ ์ธ์ž๋กœ ๋ฐ›์€ HTML์„ ํŒŒ์‹ฑํ•ด ๋ฌธ์„œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

const html = `
    <div>
      <template shadowroot="open"></template>
    </div>
  `;
const fragment = new DOMParser().parseFromString(html, 'text/html', {
  includeShadowRoots: true,
});

// output: <html>...<template>#document-fragment</template>...</html>

์ด ShadowRoot API์˜ ์ดˆ์•ˆ์—์„œ๋Š” includeShadowRoots๋ฅผ ์‚ฌ์šฉํ•ด ์„€๋„ DOM์˜ ํฌํ•จ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋…ผ์˜ ๊ณผ์ •์—์„œ ๋ช…์„ธ๊ฐ€ ๋ฐ”๋€Œ์–ด parseHTMLUnsafe()๋ฅผ ์“ฐ๋Š” ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค.

์ด๋ฒˆ ์—…๋ฐ์ดํŠธ์—์„œ๋Š” includeShadowRoots ์˜ต์…˜ ์ œ๊ฑฐ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ๋งŒ์•ฝ ์ด ์˜ต์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์—…๋ฐ์ดํŠธ ์ „์— Chrome 124์—์„œ ๋ฐฐํฌ๋œ parseHTMLUnsafe()๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Firefox: ์˜๊ฒฌ ์—†์Œ
  • Safari: ์˜๊ฒฌ ์—†์Œ
  • ์›น ๊ฐœ๋ฐœ์ž: ์˜๊ฒฌ ์—†์Œ

์ฐธ์กฐ


โœ… [Chrome 130] ๋‚ด๋ถ€๋ง ํŽ˜์ด์ง€ ์ด๋™ ์‹œ ์‚ฌ์ „ ์š”์ฒญ ๋ฐœ์†ก - ๊ฒฝ๊ณ  ๋ชจ๋“œ

๋‚ด๋ถ€๋ง ๋ณด์•ˆ ๊ฐ•ํ™”๋ฅผ ์œ„ํ•œ ๋‚ด๋ถ€๋ง ์ ‘๊ทผ ๊ทœ์น™(Private Network Access)์˜ ์ผ๋ถ€๋ฅผ ์ ์šฉํ•œ๋‹ค. ๋‚ด๋ถ€๋ง์—์„œ ํŽ˜์ด์ง€ ์ด๋™ ์‹œ ์ ‘๊ทผ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ๋จผ์ € ํ™•์ธํ•˜๋ฉฐ, ์‹คํŒจ ์‹œ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์— ๊ฒฝ๊ณ ๋ฅผ ๋…ธ์ถœํ•œ๋‹ค.

๋‚ด๋ถ€๋ง์—์„œ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„๊ฐ€ ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์ „ ์š”์ฒญ์„ ๋ณด๋‚ด ์„œ๋ฒ„๊ฐ€ ๋‚ด๋ถ€๋ง ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Private-Network: true

์„œ๋ฒ„๊ฐ€ ์œ„์ฒ˜๋Ÿผ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋ฉด ์š”์ฒญ์„ ๊ทธ๋Œ€๋กœ ์ง„ํ–‰ํ•˜๋ฉฐ, ๊ฑฐ๋ถ€ํ•˜๋ฉด ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์— ๊ฒฝ๊ณ ๋ฅผ ๋…ธ์ถœํ•œ๋‹ค. Chrome์€ ๋ณด์•ˆ ๊ฐ•ํ™”๋ฅผ ์œ„ํ•ด ์ ์ฐจ ๊ฒฝ๊ณ  ๋…ธ์ถœ ๋Œ€์‹  ์š”์ฒญ์„ ์‹คํŒจ ์ฒ˜๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค. Chrome 104์—์„œ ํ•˜์œ„ ๋ฆฌ์†Œ์Šค(.js, .css ๋“ฑ)์—๋Š” ๋ฏธ๋ฆฌ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ–ˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์ž.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


โš ๏ธ unload ์ด๋ฒคํŠธ ์ง€์› ์ค‘๋‹จ ๐Ÿ“Œ

unload ์ด๋ฒคํŠธ๋Š” ํ•ด๋‹น ๋ฌธ์„œ๋ฅผ ๋– ๋‚˜๊ฑฐ๋‚˜ ํ•˜์œ„ ์ž์›(.js, .css ๋“ฑ)์„ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋‹ค. ์ด ์ด๋ฒคํŠธ๋ฅผ ์ด์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์ข…๋ฃŒํ•˜๊ธฐ ์ „์— ํŠน์ • ๋™์ž‘์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

window.addEventListener('unload', (event) => {
  navigator.sendBeacon('/api/log', 'unload!');
});

ํ•˜์ง€๋งŒ unload ์ด๋ฒคํŠธ๋Š” beforeunload ์ด๋ฒคํŠธ์™€ ๋‹ฌ๋ฆฌ ๊ธฐ๋ณธ ๋™์ž‘์„ ์ทจ์†Œ(event.preventDefault())ํ•  ์ˆ˜ ์—†์–ด ์ด๋ฒคํŠธ๊ฐ€ ์•„์˜ˆ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ธฐ๋„ ํ•œ๋‹ค. W3C์˜ ํ†ต๊ณ„์— ๋”ฐ๋ฅด๋ฉด unload ์ด๋ฒคํŠธ๊ฐ€ ์ œ๋Œ€๋กœ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ Chrome ๋ฐ์Šคํฌํƒ‘์—์„œ๋Š” 95%, ๋ชจ๋ฐ”์ผ์—์„œ๋Š” 57% ~ 68% ์ •๋„๋กœ, ์ด๋Š” ๋ชจ๋ฐ”์ผ ํ™˜๊ฒฝ์˜ ํŠน์„ฑ์ƒ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ์•ฑ์„ ๋ณด๋‹ค๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ์ž์ฒด๋ฅผ ์ข…๋ฃŒํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์˜ํ–ฅ๋„๊ฐ€ ํฐ ๋งŒํผ, Chrome์€ ์ ์ง„์ ์œผ๋กœ unload ์ด๋ฒคํŠธ๋ฅผ ์ œ๊ฑฐํ•  ๊ณ„ํš์ด๋‹ค. ๋จผ์ € Permissions-Policy๋ฅผ ์ถ”๊ฐ€ํ•ด ์‚ฌ์šฉ ์—ฌ๋ถ€ ํ—ˆ์šฉ์„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ , ๋‚˜์ค‘์—๋Š” ํ•ด๋‹น ๊ถŒํ•œ์˜ ๊ธฐ๋ณธ ๊ฐ’์„ deny๋กœ ๋ฐ”๊ฟ€ ์˜ˆ์ •์ด๋‹ค. Chrome 117์—์„œ unload ์ด๋ฒคํŠธ์˜ ํ—ˆ์šฉ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” Permissions-Policy์˜ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์ž.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


โš ๏ธ CSS ๊ตฌํ˜• ์‚ฌ์šฉ์ž ์ง€์ • ์ƒํƒœ ๋ฌธ๋ฒ• ์ง€์› ์ค‘๋‹จ

CSS์˜ ์‚ฌ์šฉ์ž ์ง€์ • ์ƒํƒœ ๋ฌธ๋ฒ•์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์š”์†Œ์˜ ์ƒํƒœ๋ฅผ ์ง€์ •ํ•ด ๊ฐ€์ƒ ์„ ํƒ์ž ๋“ฑ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์œผ๋กœ, ์•„์ง ํ‘œ์ค€์ด ์•„๋‹Œ ์ดˆ์•ˆ ์ƒํƒœ๋‹ค.

// MyCustomElement.js
class MyCustomElement extends HTMLElement {
  set checked(flag) {
    if (flag) {
      this._internals.states.add('--foo');
    } else {
      this._internals.states.delete('--foo');
    }

    console.log(this._internals.states.has('--foo'));
  }
}
/* styles.css */
.custom:--foo {
  color: red;
}

๊ธฐ์กด์—๋Š” ์˜ˆ์‹œ์ฒ˜๋Ÿผ --foo์™€ ๊ฐ™์€ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ์œผ๋‚˜, ์ด ๋ฌธ๋ฒ•์ด ํ˜„์žฌ ์ œ์•ˆ ์ค‘์ธ @custom-selectors ๋ฌธ๋ฒ•๊ณผ ๊ฒน์ณ :state(foo)๋กœ ๋ช…์„ธ๋ฅผ ๋ณ€๊ฒฝํ–ˆ๋‹ค.

/* styles.css */
.custom:state(foo) {
  color: red;
}

ํ˜„์žฌ Chrome 90์—์„œ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜• ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์ดํŠธ๋Š” ์•ฝ 0.03%์œผ๋กœ, Chrome ํŒ€์€ ๊ตฌํ˜• ๋ฌธ๋ฒ•์„ ์ง€์› ์ค‘๋‹จํ•˜๊ธฐ ์œ„ํ•œ ์ผ์ •์„ ๋…ผ์˜ ์ค‘์ด๋‹ค. Chrome 122 ์ด์ƒ์—์„œ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๋กœ ์ƒˆ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์ž.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ฐธ์กฐ


โš ๏ธ ์ œ3์ž ์ฟ ํ‚ค ์ง€์› ์ค‘๋‹จ ๐Ÿ“Œ

์ œ3์ž ์ฟ ํ‚ค(Third-Party Cookies)๋Š” ํ˜„์žฌ ๋„๋ฉ”์ธ๊ณผ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์—์„œ ๋ฐœํ–‰ํ•œ ์ฟ ํ‚ค๋ฅผ ๋งํ•œ๋‹ค. ์ œ3์ž ์ฟ ํ‚ค๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž์˜ ์ทจํ–ฅ, ํ™œ๋™ ์ •๋ณด ๋“ฑ์„ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์–ด ๊ด‘๊ณ  ๋งˆ์ผ€ํŒ… ๋ถ„์•ผ์—์„œ ์ž์ฃผ ์‚ฌ์šฉํ–ˆ์œผ๋‚˜, ์›ํ•˜์ง€ ์•Š๋Š” ๊ฐœ์ธ์ •๋ณด๊นŒ์ง€ ์œ ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ํฐ ๋‹จ์ ์ด ์žˆ๋‹ค.

ํฌ๋กฌ์€ ์ด๋ฏธ ๊ด€๋ จ ๋ฒ• ์ค€์ˆ˜๋ฅผ ์œ„ํ•ด 2020๋…„ 1์›”๋ถ€ํ„ฐ ์ œ3์ž ์ฟ ํ‚ค์˜ ์ค‘๋‹จ์„ ์˜ˆ๊ณ ํ–ˆ๋‹ค. ๊ทธ๋™์•ˆ ์˜ํ–ฅ์ด ํฐ ์ ์„ ๊ณ ๋ คํ•ด ์ง€์› ์ค‘๋‹จ์„ ๊ณ„์† ๋ฏธ๋ค„์™”์œผ๋‚˜, 2024๋…„์—๋Š” ์ ์ง„์ ์œผ๋กœ ์ œ3์ž ์ฟ ํ‚ค๋ฅผ ์ง€์› ์ค‘๋‹จํ•  ์˜ˆ์ •์ด๋‹ค.

๊ตฌ๊ธ€์ด ๋Œ€์•ˆ์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ๊ฐœ์ธ์ •๋ณด๋Š” ๋ณดํ˜ธํ•˜๋˜, ๊ธฐ์กด์˜ ์ œ3์ž ์ฟ ํ‚ค๊ฐ€ ํ•˜๋˜ ์—ญํ• ์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” Privacy Sandbox๋ฅผ ๊ฐœ๋ฐœ ์ค‘์ด๋‹ˆ ์ฐธ๊ณ ํ•˜์ž.

์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ ์›น ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Firefox: ๋ฐฐํฌ ์™„๋ฃŒ
  • Safari: ๋ฐฐํฌ ์™„๋ฃŒ
  • ์›น ๊ฐœ๋ฐœ์ž: ๋ณตํ•ฉ์ 

์ฐธ์กฐ


์ด์›ํ‘œ2024.04.29
Back to list