Skip to content

Latest commit

ย 

History

History
799 lines (641 loc) ยท 33.1 KB

step40.md

File metadata and controls

799 lines (641 loc) ยท 33.1 KB

๋ฌธ์„œ ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

STEP 40, 41, 42

๐Ÿ’ก์งˆ์˜์‘๋‹ต์€ https://github.com/pul8219/TIL Issues ํƒญ์˜ ์•Œ๋งž์€ step ์ด์Šˆ์•ˆ์— ๋‚จ๊ฒจ์ฃผ์„ธ์š”. โžก๏ธ Issueํƒญ์œผ๋กœ ์ด๋™

๋ณด์ถฉ ํ•„์š”

๋ชฉ์ฐจ

๐Ÿ’ฌ

CSSOM

  • CSSOM(CSS Object Model): ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ CSS๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” API ์ง‘ํ•ฉ. CSS๋ฅผ ๊ฐ์ฒดํ™” ์‹œ์ผœ ๋ชจ๋ธ๋งํ•œ ๊ฒƒ์ด๋‹ค.
  • DOM(Document Object Model): HTML(Document)์„ ๊ฐ์ฒดํ™”์‹œ์ผœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“  ๊ฒƒ. ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๊ฐ€ DOM ๊ตฌ์กฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ฌธ์„œ ๊ตฌ์กฐ, ์Šคํƒ€์ผ, ๋‚ด์šฉ ๋“ฑ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ DOM API๋ฅผ ์ด์šฉํ•˜๋ฉด html์„ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ DOM์š”์†Œ์— ๋ณ€ํ™”๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

ํƒœ๊ทธ์˜ ์‹ค์ œ ๋‚ด์šฉ์€ ํƒœ๊ทธ ์ž์ฒด๊ฐ€ ์•„๋‹Œ ํƒœ๊ทธ ๋‚ด๋ถ€์— ์žˆ๋‹ค.

ํƒœ๊ทธ ๊ทธ ์ž์ฒด๋Š” ์‹ค์ฒด๊ฐ€ ์•„๋‹Œ ์ผ์ข…์˜ ์ปจํ…Œ์ด๋„ˆ ๋ฐ•์Šค๊ฐ™์€ ๊ฒƒ์ด๊ณ , ์‹ค์ œ ๋‚ด์šฉ์€ ํƒœ๊ทธ ์•ˆ์— ์žˆ๋‹ค.

ex) ์˜ˆ๋ฅผ ๋“ค์–ด <style> ํƒœ๊ทธ ์ž์ฒด์—๋Š” sheet๋ผ๋Š” ์‹ค์ฒด๊ฐ€ ์žˆ๊ณ  <canvas> ํƒœ๊ทธ์˜ ์‹ค์ฒด๋Š” getContext๋กœ ์–ป์€ canvastocontext์— ์žˆ๋‹ค. ์ด๋ฅผ DOM์— ํฌํ•จ์‹œํ‚ค๋ ค๋ฉด ๋ฐ˜๋“œ์‹œ canvas๋ผ๋Š” ํƒœ๊ทธ๋กœ ๊ฐ์‹ธ์•ผ๋งŒ(wrapping) html์— ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ํƒœ๊ทธ ๋‚ด์˜ ๋‚ด์šฉ๋“ค์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ html ๋ฒ„์ „๋งˆ๋‹ค ๊ฐ๊ธฐ ๋‹ค๋ฅด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด canvas๋Š” getcontext๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์‚ฌ์šฉํ•˜์ง€๋งŒ ๊ตฌํ˜• element๋“ค์€ ์†์„ฑ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

CSSOM ์‚ฌ์šฉ๋ฒ•

Style DOM Element
  ใ„ด sheet: CSSStyleSheet
    ใ„ด CSSRules: CSSRuleList
      ใ„ด Item: CSSStyleRule -> Type, SelectorText, Style(CSSStyleDeclaration), ...

์˜ˆ์ œ์ฝ”๋“œ๋กœ CSSOM์˜ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด์ž. style ํƒœ๊ทธ์˜ sheet ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด CSSStyleSheet๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

<style id="s">
  .test {
    background: #ff0;
  }
</style>
const el = document.querySelector('#s');
const sheet = el.sheet;
const rules = sheet.cssRules;

๋˜ํ•œ sheet์•ˆ์— cssRules๋ผ๋Š” list๋ฅผ ๊ฐ–๊ณ ์žˆ๋‹ค. ์ด ์•ˆ์—๋Š” ์—ฌ๋Ÿฌ rule๋“ค์ด ๋“ค์–ด์žˆ๋‹ค. (์ด๋Š” ์œ ์‚ฌ๋ฐฐ์—ด๋กœ ๋ฐฐ์—ด๊ณผ ๋น„์Šทํ•œ ์นœ๊ตฌ์ด๋‹ค. length๋ผ๋Š” ์†์„ฑ์€ ์žˆ์ง€๋งŒ ๋ฐฐ์—ด ๋ฉ”์†Œ๋“œ๋Š” ๋จนํžˆ์ง€ ์•Š๋Š” list์ด๋‹ค.)

rules์˜ 0๋ฒˆ์งธ๋ถ€ํ„ฐ๋Š” rule๋“ค์ด ๋“ค์–ด์žˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ rules[0]์—๋Š” style ๋‚ด์—์„œ ์ •์˜ํ•œ .test ๋‚ด์šฉ์ด ๋“ค์–ด๊ฐ€์žˆ๋‹ค. ๋งŒ์•ฝ ์ •์˜ํ•œ style์ด ์—ฌ๋Ÿฌ๊ฐœ์˜€๋‹ค๋ฉด [0], [1], [2], ...์— ์ฐจ๋ก€๋Œ€๋กœ ๋“ค์–ด์žˆ์„ ๊ฒƒ์ด๋‹ค.

rule์˜ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์†์„ฑ

  • type
  • selectortext (ex. .test)
  • style๊ฐ์ฒด(DOM์—๋„ ๋“ค์–ด์žˆ๋Š” style ๊ฐ์ฒด)
const el = document.querySelector('#s');
const sheet = el.sheet;
const rules = sheet.cssRules;
const rule = rules[0];
console.log(rule);
/**
 * CSSStyleRule
 *  ใ„ดselectorText: ".test"
 *  ใ„ดstyle:
 *      ใ„ดbackground: "rgb(255, 255, 0)"
 *  ใ„ดtype: 1
 *  ...(๋” ๋งŽ์€ ์†์„ฑ๋“ค์ด ์žˆ๋‹ค)
 */

์ด๋ ‡๊ฒŒ html์—์„œ text๋กœ ์ •์˜ํ–ˆ๋˜ css๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์˜ ํ•ด์„๊ณผ์ •์„ ๊ฑฐ์น˜๊ณ  ๋‚˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ์— ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜ํ•˜๋‚˜์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๋ ‡๊ฒŒ html์˜ text๋กœ ์ ์–ด๋†“์€ css๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์ƒ์˜ ๊ตฌ์กฐ๋กœ ๋ฐ”๋€Œ๋Š” ๊ณผ์ •์ด CSSOM์ด๋‹ค.

CSSRule Type

๊ทธ๋ ‡๋‹ค๋ฉด ๊ฐ๊ฐ rule๋“ค์— ๋“ค์–ด์žˆ๋Š” type ์†์„ฑ์€ ๋ฌด์—‡์ผ๊นŒ? ์ด๋Š” CSS ์ •์˜์— ๋Œ€ํ•œ rule์„ ์˜๋ฏธํ•œ๋‹ค. type์—๋Š” ๊ต‰์žฅํžˆ ๋งŽ์€ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค.

  • type:1 | STYLE_RULE | CSSOM (์•ˆ์— ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ CSSOM ๋ผ๋Š” ๋œป)
  • type:2 | CHARSET_RULE | CSSOM -> @charset
  • type:3 | IMPORT_RULE | CSSOM
  • type:4 | FONT_FACE_RULE | CSSOM -> ์™ธ๋ถ€ ํฐํŠธ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” font-face๋ฅผ ์ƒ๊ฐํ•ด๋ณด๊ธฐ
  • type:7 | KEYFRAMES_RULE | css3-animations -> css3-animations๋ผ๋Š” ํŠน๋ณ„ํ•œ ๊ฐ์ฒด๋กœ ๋ฐ”๋€Œ์–ด ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋œ๋‹ค.

๋™์ ์œผ๋กœ CSS ์ถ”๊ฐ€ํ•˜๊ธฐ: Insert Rule

sheet.insertRule('์Šคํƒ€์ผ', ๋„ฃ์„ index ๋ฒˆํ˜ธ)

insertRule์„ ์‚ฌ์šฉํ•ด sheet์— ์ถ”๊ฐ€ํ•˜๋ฉด CSS๋ฅผ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

const el = document.querySelector('#s');
const sheet = el.sheet;
const rules = sheet.cssRules;
const rule = rules[0];
// rules์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ธ๋ฑ์Šค๋ฅผ rules.length๋กœ ์ฃผ์—ˆ๋‹ค.
sheet.insertRule('.red{background:red}', rules.length);
sheet.insertRule('.blue{background:blue}', rules.length);
console.log(sheet);

insertRule์„ ํ•œ ๋’ค, sheet๋ฅผ ์ถœ๋ ฅํ•ด cssRules๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์ง€์ •ํ•œ red, blue ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์‹ค์ œ CSS ์Šคํƒ€์ผ์— ์ถ”๊ฐ€๊ฐ€ ๋˜์—ˆ๋Š”์ง€ ์•Œ์•„๋ณด๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด html์˜ body์—์„œ ํ™•์ธํ•œ๋‹ค.

<!-- ์‹คํ–‰ํ•ด๋ณด๋ฉด CSS๊ฐ€ ์ž˜ ์ ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. -->
<div class="red">red</div>
<div class="blue">blue</div>

cssRules๋Š” ์ˆœ์„œ๊ฐ€ ๊ต‰์žฅํžˆ ์ค‘์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— insertRule์„ ํ•  ๋•Œ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ css๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆœ์„œ๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (์˜ˆ๋ฅผ ๋“ค์–ด CSS์—์„œ .test๋ผ๋Š” css๋ฅผ ๋‘ ๋ฒˆ ์ฃผ๋Š”๋ฐ ๋จผ์ € ์„ ์–ธ๋œ ๊ฒƒ์€ width:100, ๋‘ ๋ฒˆ์งธ๋กœ ์„ ์–ธ๋œ ๊ฒƒ์€ width:200์ด๋ผ๋ฉด ์•„๋ž˜ ์„ ์–ธ๋œ 200์ด ๋จนํžŒ๋‹ค.)

๋งŒ์•ฝ insert๋ฅผ ๋‚˜์ค‘์— ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๋‚˜์ค‘์— insertํ•˜๋”๋ผ๋„ CSS๊ฐ€ ์ ์šฉ๋˜๋Š”์ง€ ์•Œ์•„๋ณด์ž. onclick์„ ์ด์šฉํ•˜์—ฌ red๋ถ€๋ถ„์„ ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค insertRule์ด ์ž‘๋™ํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

const el = document.querySelector('#s');
const sheet = el.sheet;
const rules = sheet.cssRules;
const rule = rules[0];
document.querySelector('.red').onclick = (_) => {
  sheet.insertRule('.red{background:red}', rules.length);
  sheet.insertRule('.blue{background:blue}', rules.length);
};

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด red๋ฅผ ํด๋ฆญํ•˜๋ฉด CSS๊ฐ€ ๋ณ€ํ™”ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. document์— ๋“ฑ๋ก๋œ sheet๊ฐ€ ๋ณ€ํ™”ํ•˜๋ฉด ๋ Œ๋”๋ง์„ ๋‹ค์‹œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.(repaint, reflow๊นŒ์ง€)

document์— ๋“ฑ๋ก๋œ stylesheet๋ผ๋Š” ๊ฑด ์–ด๋–ป๊ฒŒ ์•„๋Š”๊ฑธ๊นŒ? ์ด๋Š” ์šฐ๋ฆฌ๊ฐ€ html์— style ํƒœ๊ทธ๋ฅผ ์ด๋ฏธ ๋“ฑ๋กํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋“ฑ๋ก๋œ stylesheet๋Š” ๋”ฐ๋กœ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์ฐฝ์—์„œ document.styleSheets๋ฅผ ์ž…๋ ฅ. (โ“ ๊ฐ•์˜์—์„  CSSStyleSheet๊ฐ€ 2๊ฐœ ๋‚˜์˜ค๋Š”๋ฐ ๋‚ด ๊ฒฐ๊ณผ์—์„  ํ•˜๋‚˜๋งŒ ๋‚˜์˜จ๋‹ค) CSSStyleSheet ์•ˆ์— cssRules๋ฅผ ๋ณด๋ฉด ์šฐ๋ฆฌ๊ฐ€ insertRule๋กœ ์ถ”๊ฐ€ํ•œ CSS๋“ค์ด ๋ฐ˜์˜๋ผ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ CSSStyleSheet๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ๋ผ๋ฉด ์•„๋ž˜์— ์žˆ๋Š” ์Šคํƒ€์ผ ํƒœ๊ทธ ์ผ์ˆ˜๋ก ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๋‹ค.(์•„๋ž˜์žˆ๋Š” ๊ฒƒ์ด ์œ„์— ์žˆ๋Š” ๊ฒƒ์„ ์ด๊ธด๋‹ค.)

๋˜ํ•œ ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์ฐฝ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์Šคํƒ€์ผ ์†์„ฑ์„ ๋Œ ์ˆ˜ ์žˆ๋‹ค. document.styleSheets[0].disabled = true๋กœ ๋ฐ”๊พธ๋ฉด onclick์œผ๋กœ ์ ์šฉํ–ˆ๋˜ CSS๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (์ ์šฉํ–ˆ๋˜ ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ๊บผ๋ฒ„๋ฆฐ ๊ฒƒ์ž„)

๋™์ ์œผ๋กœ CSS ์‚ญ์ œํ•˜๊ธฐ: Delete Rule

deleteRule ์„ ์ด์šฉํ•ด CSS๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ธ๋ฑ์Šค๋งŒ ์ง€์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. insertRule ์ฝ”๋“œ์— ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด์ž. blue๋ฅผ ํ•œ๋ฒˆ ํด๋ฆญํ•˜๋ฉด ๋งˆ์ง€๋ง‰์œผ๋กœ ์ถ”๊ฐ€ํ–ˆ๋˜ .blue์— ๋Œ€ํ•œ CSS๊ฐ€ ์‚ญ์ œ๋  ๊ฒƒ์ด๋‹ค.

document.querySelector('.blue').onclick = (_) => {
  sheet.deleteRule(rules.length - 1);
};

CSSOM ์˜ ํšจ์œจ์„ฑ

CSSOM์„ ๋‹ค๋ฃจ๋Š” ๊ฒƒ์„ DOM์˜ style ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒƒ๊ณผ ์™„์ „ํžˆ ๋‹ค๋ฅด๋‹ค. CSSOM์„ ์ด์šฉํ•˜๋ฉด stylesheet๋ฅผ ๋™์ ์œผ๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. inline ํƒœ๊ทธ๋ฅผ ๊ฑด๋“œ๋ฆฌ๋Š” ๊ฒƒ๋ณด๋‹ค ์ข‹๋‹ค. css object(stylesheet) ํ•˜๋‚˜๋งŒ ๊ฑด๋“œ๋ฆฌ๋ฉด ์Šคํƒ€์ผ์ด ์ ์šฉ๋˜์žˆ๋Š” ์š”์†Œ๋“ค์— ์ผ๊ด„์ ์œผ๋กœ ์ ์šฉ๋˜๋‹ˆ๊นŒ ์ข‹์€ ๊ฒƒ! ์ด ๊ฒฝ์šฐ์—” ์„ฑ๋Šฅ์ƒ์˜ ์ €ํ•˜๊ฐ€ ์—†์„ ๊ฒƒ์ด๋‹ค. (+ ์œ„ ์˜ˆ์ œ์ฒ˜๋Ÿผ ํƒœ๊ทธ์—๋Š” ๋ฏธ๋ฆฌ class๋ฅผ ์ง€์ •ํ•ด๋†“์•„๋„ ์ƒ๊ด€์—†๋‹ค) dom์€ ๊ทธ๋Œ€๋กœ ๋‘๊ณ  cssom๋ฅผ ์‚ฌ์šฉํ•ด ํด๋ž˜์Šค๋‚˜ dom๊ตฌ์กฐ์— ๋งž๊ฒŒ cssobject๋งŒ ๋ฐ”๊ฟ”์ฃผ๋Š” ๊ฒƒ. ํ•˜๋‚˜ํ•˜๋‚˜ dom์˜ style์„ ์กฐ์ •ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋น ๋ฅด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด red๋ผ๋Š” ์ด๋ฆ„์„ ๊ฐ€์ง„ class๊ฐ€ ๊ต‰์žฅํžˆ ๋งŽ์„ ๋•Œ cssom๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์œ„์—์„œ ๋งํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์ผ๊ด„์ ์œผ๋กœ css ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ๋œ๋‹ค.

<div class="red red1">red</div>
<div class="blue blue1">blue</div>
<div class="red">red</div>
<div class="blue">blue</div>
<div class="red">red</div>
<div class="blue">blue</div>
<div class="red">red</div>
<div class="blue">blue</div>
<div class="red">red</div>
<div class="blue">blue</div>
<div class="red">red</div>
<div class="blue">blue</div>
<div class="red">red</div>
<div class="blue">blue</div>
<div class="red">red</div>
<div class="blue">blue</div>
<div class="red">red</div>
<div class="blue">blue</div>
document.querySelector('.red1').onclick = (_) => {
  sheet.insertRule('.red{background:red}', rules.length);
  sheet.insertRule('.blue{background:blue}', rules.length);
};

document.querySelector('.blue1').onclick = (_) => {
  sheet.deleteRule(rules.length - 1);
};

์‹คํ–‰ํ•ด๋ณด๋ฉด css object๋ฅผ ์กฐ์ •ํ•จ์œผ๋กœ์จ css๋ฅผ ์ผ๊ด„์ ์œผ๋กœ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Œ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

Compatibility Library

์ง€๊ธˆ๊นŒ์ง€ CSS object ๋ชจ๋ธ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์„ ์žก์•˜์œผ๋‹ˆ ์ด๋ฅผ ์ด์šฉํ•ด CSS ์ „์ฒด๋ฅผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ†ตํ•ด ์•ˆ์ •์ ์œผ๋กœ ํ†ต์ œํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ชฉํ‘œ

  • Vendor Prefix ํ•ด๊ฒฐ
  • CSS ๋™์  ์กฐ์ •

ํ•ด๊ฒฐํ•ด์•ผํ•  ๋ฌธ์ œ๋“ค

  1. Vendor Prefix

Vendor Prefix๋ž€?

๊ฐ™์€ CSS๋”๋ผ๋„ ์›น๋ธŒ๋ผ์šฐ์ €๋งˆ๋‹ค ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ง€์›๋  ์ˆ˜ ์žˆ๋‹ค. ๊ท ์ผํ•˜๊ฒŒ ์Šคํƒ€์ผ ์†์„ฑ์„ ํ‘œํ˜„ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ธŒ๋ผ์šฐ์ €๋งˆ๋‹ค prefix(์ ‘๋‘์‚ฌ)๋ฅผ ๋ถ™์—ฌ ์Šคํƒ€์ผ์„ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด๋ฅผ Vendor Prefix๋ผ๊ณ  ํ•œ๋‹ค. ์˜ˆ๋ฅผ๋“ค๋ฉด IE or Edge๋Š” Vendor Prefix๊ฐ€ -ms-์ด๋‹ค.

Vendor Prefix๋Š” ์‹คํ–‰์ค‘์— ์†์„ฑ์„ ํ™•์ธํ•ด๋ณด๋Š” ์ˆ˜๋ฐ–์— ์—†๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. '๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํฌ๋กฌ์ด๋ผ๋ฉด border-radius์— webkit์„ ๋ถ™์ด์ž' ์ด๋Ÿฐ๊ฒŒ ํ†ตํ•˜์ง€ ์•Š๋Š”๋‹ค. ํฌ๋กฌ ๋ฒ„์ „ 54์—์„œ๋Š” webkit์„ ๋ถ™์—ฌ์•ผํ•˜๋Š”๋ฐ ๋ฒ„์ „66์—์„œ๋Š” ๋ถ™์ด๋ฉด ์•ˆ๋ผ ์ด๋Ÿฐ์‹์œผ๋กœ ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ. border-radius๊ฐ€ ์žˆ๋‚˜๋ฅผ ๊ทธ๋•Œ๊ทธ๋•Œ ํ™•์ธํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค. ๋ฏธ๋ฆฌ ๊ณต์‹์„ ๋งŒ๋“ค ์ˆ˜ ์—†๊ณ  ์–ด๋–ค ์†์„ฑ์ด ์žˆ์„์ง€ ์—†์„์ง€๋Š” ์‹คํ–‰๋„์ค‘์— ํ™•์ธํ•ด์•ผํ•œ๋‹ค.

Runtime Fetch ํ•ด์•ผํ•œ๋‹ค.

  1. Unsupported Property

๋ธŒ๋ผ์šฐ์ €๋งˆ๋‹ค ์ง€์›ํ•˜์ง€ ์•Š๋Š” ์†์„ฑ์ด๋‚˜ ๊ฐ’์ด ์กด์žฌํ•œ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ ie7์— rgba๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ฃฝ๋Š”๋‹ค.

Graceful Fail ์‹คํŒจ๋ฅผ ์กฐ์šฉํ•˜๊ฒŒ ์ž˜ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ๊ฒƒ(์—†์—ˆ๋˜ ์ผ์ฒ˜๋Ÿผ)

  1. Hierarchy Optimize

๊ณ„์ธต๊ตฌ์กฐ๋ฅผ ์ตœ์ ํ™”ํ•ด์•ผํ•˜๋Š” ์ผ๋“ค์ด ๋งŽ์ด ์ƒ๊ธด๋‹ค. ์Šคํƒ€์ผ์‹œํŠธ๊ฐ€ ์ˆ˜์‹ญ๊ฐœ ์žˆ์„ ๋•Œ, ์˜ˆ๋ฅผ ๋“ค์–ด .red์— ๋Œ€ํ•ด ๊ณ„์‚ฐํ•˜๋ ค๋ฉด, stylesheet ๊ฐ์ฒด๋ฅผ ๋‹ค ๋Œ๋ฉด์„œ(stylesheet 0๋ฒˆ๋ถ€ํ„ฐ 1,2,.. ์ˆœ์œผ๋กœ ๊ณ„์‚ฐํ•œ๋‹ค) ๊ทธ ์•ˆ์˜ rule list๋ฅผ ๋‹ค ๋Œ๋ฉด์„œ ๊ทธ ์•ˆ์˜ rule๋ฅผ ๋‹ค ๋Œ๋ฉฐ ๊ทธ์•ˆ์˜ ์†์„ฑ๋“ค์„ ๋ชจ๋‘ ํ•ฉ์ณ ๊ณ„์‚ฐ์„ ํ•ด์•ผํ•œ๋‹ค.(์˜ค๋ž˜๊ฑธ๋ฆผ) ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— styleํƒœ๊ทธ๋‚˜ linkํƒœ๊ทธ๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ๋‹ฌ๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ฃฝ์–ด๋‚˜๋Š”๊ฒƒ์ด๋‹ค.(CSS ์ค‘์ฒฉ ๊ณ„์‚ฐ)

css ๊ฐ์ฒด ๋ชจ๋ธ์„ ์ด์šฉํ•˜๋ฉด ์ด๋ฅผ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ํ†ตํ•ฉํ•˜๊ณ  sheet.disabled = true; ๋ฅผ ์ด์šฉํ•ด ๋ช‡๊ฐœ๋Š” ๋„๋ฉด ๋œ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ตฌ์กฐ

Style(CSSStyleDeclare)

  • ๊ฐ€์žฅ ์˜์กด์„ฑ์ด ์—†์Œ
  • dom์—๋„ ์žˆ๊ณ  cssrule์—๋„ ์žˆ๋Š”
  • vendor prefix ์ฒ˜๋ฆฌ

โฌ†๏ธ (์˜์กด ๋ฐฉํ–ฅ, '์•Œ๊ณ  ์žˆ๋‹ค'๋Š” ๊ฒƒ)

Rule(CSSRule)

  • style์„ ์†Œ์œ ํ•  ์ˆ˜ ์žˆ๋Š” rule

โฌ†๏ธ

CSS(StyleSheet)

  • rule์„ ์—ฌ๋Ÿฌ๊ฐœ ์†Œ์œ ํ•  ์ˆ˜ ์žˆ๋Š” sheet ๊ฐ์ฒด

์˜์กด์„ฑ์ด ์—†๋Š” style๋ถ€ํ„ฐ ๋งŒ๋“ค์ž(๊ทธ๊ฒŒ ์‰ฝ๋‹ค)

Rule ๋‚ด๋ถ€์— Style์ด๋ผ๋Š” ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์žˆ๋‹ค(CSSStyleDeclaration) ์ด๊ฑธ ์ถ”์ƒํ™”ํ•ด ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค. ์™œ ์ถ”์ƒํ™”๋ฅผ ํ•˜๋ƒ๋ฉด, Style์— ๋‚ ๋กœ ์†์„ฑ์„ ๋„ฃ์œผ๋ฉด Vendor Prefix๊ฐ€ ํ•ด๊ฒฐ์ด ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด ๋„ฃ์–ด์•ผ Vendor Prefix๊ฐ€ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

1. Style ๋งŒ๋“ค๊ธฐ

Style์ด๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž

const Style = (_ => {
  const prop = new Map, prefix = 'webkt,moz,ms,chrome,o,khtml'.split(',');
  const NONE = Symbol();
  const BASE = document.body.style;
  const getKey = key => {...}; // end of getKey()
  return class{...};
})();
  • prefix: ๊ทธ์ „์— vendor prefix ๋ฌธ์ž์—ด์ด ํ•„์š”ํ•˜๋‹ค(๋ธŒ๋ผ์šฐ์ €์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ๊ฐ€์ง€ vendor prefix๊ฐ€ ์žˆ์Œ) split์œผ๋กœ ๋ฌธ์ž์—ด์„ ์ชผ๊ฐœ prefix๋ผ๋Š” ๋ฐฐ์—ด๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋‹ค.
  • ์ž๋ฃŒํ˜•์ด Map์ธ prop: key๋Š” ์†์„ฑ(ex. background), value๋Š” ํ•ด๋‹น ๋ธŒ๋ผ์šฐ์ €์—์„œ vendor prefix๋ฅผ ํฌํ•จํ•ด ์ง€์›ํ•˜๋Š” ์ง„์งœ ์ด๋ฆ„์ด ๋“ค์–ด๊ฐˆ ๊ฒƒ์ด๋‹ค.
  • None: ์–ด๋–ค ์†์„ฑ์€ ์ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•œ ์žฅ์น˜
  • ์œ„์—์„œ๋„ ์„ค๋ช…ํ–ˆ๋“ฏ ์–ด๋–ค ์†์„ฑ์ด ์žˆ๋Š”์ง€ ์—†๋Š”์ง€๋Š” ์‹คํ–‰๋„์ค‘์— ํ™•์ธํ•ด์•ผํ•œ๋‹ค. (ex. border-radius๋ผ๋Š” ์†์„ฑ์ด ์žˆ๋‚˜?) ์žˆ๋Š”์ง€ ์—†๋Š”์ง€๋ฅผ ๋ˆ„๊ตฌ์—๊ฒŒ ๋ฌผ์–ด๋ณผ ๊ฒƒ์ธ๊ฐ€? ๋ฐ”๋กœ ์–ด๋–ค ๋ธŒ๋ผ์šฐ์ €๋“  ๋ฐ˜๋“œ์‹œ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” document.body.style์— ๋ฌผ์–ด๋ณด๋ฉด ๋œ๋‹ค. body์— ์žˆ๋Š” ์†์„ฑ์ด๋ผ๋ฉด ์žˆ๋Š” ๊ฒƒ์ด ํ™•์ •๋˜๋Š” ๊ฒƒ!

๊ฒฐ๊ตญ, ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ

  • Unsupported Property ์ง€์›ํ•˜์ง€ ์•Š๋Š” ์†์„ฑ์€ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์‹คํŒจํ•˜๊ธฐ ์œ„ํ•ด NONE์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ณ 
  • Vendor Prefix๋ฅผ Runtime์— Fetchํ•˜๊ธฐ ์œ„ํ•ด์„œ BASE, ์ฆ‰ body์— ์žˆ๋Š” style ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค. ๋ผ๋Š” ๊ฒƒ!

์ฝ”๋“œ์—์„œ getKey() ๋ถ€๋ถ„

const Style = (_ => {
  // ...
  const getKey = key => {
    if(prop.has(key)) return prop.get(key);
    if(key in BASE) prop.set(key, key);
    else if(!prefix.some(v =>{
      // prefix๋ฅผ ๋ถ™์ธ ์†์„ฑ์€ ์กด์žฌํ•˜๋Š”๊ฐ€?
      // ...
    })){
      prop.set(key, NONE);
      key = NONE;
    }
    return key;
  }; // end of getKey()

  return class{...};
})();
  • ์ง„์งœ ์ด๋ฆ„์€ ์–ด๋–ป๊ฒŒ ์–ป๋‚˜? ํ‘œ์ค€ ์ด๋ฆ„, ์˜ˆ๋ฅผ ๋“ค์–ด border-radius๋ฅผ ๋ณด๋ƒˆ์„ ๋•Œ ์ด๋ฅผ ์ง€์›ํ•˜๋Š” ์–ด๋–ค ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์žˆ์„ ๋• border-radius๋ผ๋Š” ์ด๋ฆ„์„ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„์•ผ ํ•˜๊ณ , ์ด๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ณ  webkit border-radius๊ฐ€ ์žˆ๋Š” ์–ด๋–ค ๋ธŒ๋ผ์šฐ์ €๋Š” webkit border-radius๋ฅผ ๋ฐ›์•„์•ผ ํ•œ๋‹ค. ์•„์˜ˆ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €๋ผ๋ฉด NONE์„ ๋ฐ˜ํ™˜ํ•ด์ค˜์•ผํ•œ๋‹ค. ์ด๋Ÿฐ ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ด getKey ํ•จ์ˆ˜์ด๋‹ค. ํ‘œ์ค€์ด๋ฆ„์„ ์ฃผ๋ฉด ํ•ด๋‹น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ง€์›ํ•˜๋Š” ์ง„์งœ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ธ ๊ฒƒ์ด๋‹ค.

    ์ด๋ฅผ ๋งค๋ฒˆ ๊ณ„์‚ฐํ•˜๋ฉด ๋น„ํšจ์œจ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•œ๋ฒˆ ์—ฐ์‚ฐํ•ด ์ง„์งœ ์ด๋ฆ„์„ ์•Œ์•„๋ƒˆ์œผ๋ฉด ์ด๋ฅผ ์บ์‹œ์— ์ €์žฅํ•˜๋„๋ก ๊ตฌํ˜„ํ•  ๊ฒƒ์ด๋‹ค. ์ด ์บ์‹œ๊ฐ€ prop์ด๋‹ค. ์บ์‹œ์— ์žˆ๋‹ค๋ฉด ์บ์‹œ์— ์žˆ๋Š” ๊ฐ’์œผ๋กœ ์ค€๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰ ๋ณด๋‚ธ ํ‘œ์ค€ ์ด๋ฆ„(key)์— ํ•ด๋‹นํ•˜๋Š” ๊ฒƒ์ด ์บ์‹œ์•ˆ์— ๋“ค์–ด์žˆ๋‹ค๋ฉด ๊ทธ ์บ์‹œ ์•ˆ์— ์žˆ๋Š” ์ง„์งœ ์ด๋ฆ„์„ ๋ฆฌํ„ดํ•ด์ค€๋‹ค. (๋งค๋ฒˆ ์ด if๋ฌธ ๋ฐ‘์„ ๊ณ„์‚ฐํ•˜๊ธฐ ์‹ซ๊ธฐ ๋•Œ๋ฌธ์—) ํ•œ๋ฒˆ์ด๋ผ๋„ ์ง„์งœ ์ด๋ฆ„์„ ํ™•์ธํ•œ ์ ์ด ์žˆ๋‹ค๋ฉด ์บ์‹œ์— ์ €์žฅํ•ด๋‘”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

  • if(key in BASE) prop.set(key, key);: body style์— border-radius๊ฐ€ ์žˆ๋‹ค๋ฉด ์บ์‹œ์— ์ €์žฅํ•ด๋‘”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

  • else if๋ฌธ: ๋งŒ์•ฝ border-radius๊ฐ€ ์—†๋‹ค๋ฉด? prefix๋ฅผ ๋ถ™์ธ border-radius๋Š” ์žˆ๋Š”๊ฐ€? ์—†์œผ๋ฉด key๋ฅผ NONE์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

Array.prototype.some()

arr.some(callback[, thisArg])

callback์ด ์–ด๋–ค ๋ฐฐ์—ด ์š”์†Œ๋ผ๋„ ์ฐธ์ธ(truthy)๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ์—” true์ด๊ณ  ๊ทธ ์™ธ์—๋Š” false์ด๋‹ค.

else if๋ฌธ์„ ์ž์„ธํžˆ ๋“ค์—ฌ๋‹ค๋ณด์ž(์ฝ”๋“œ ์ฃผ์„ ์ฐธ๊ณ )

else if(!prefix.some(v =>{
  // prefix๋ฅผ ๋ถ™์ธ ์†์„ฑ์€ ์กด์žฌํ•˜๋Š”๊ฐ€?๋ฅผ ์•Œ์•„๋ณผ ์ฐจ๋ก€
  // ๋ฉ”์†Œ๋“œ some์˜ ์ธ์ˆ˜์ธ callback ํ•จ์ˆ˜ ๋ถ€๋ถ„์ด๋‹ค.
  // webkitBackground ์ด๋Ÿฐ์‹์œผ๋กœ ์†์„ฑ๋ช… ์ฒซ๊ธ€์ž๊ฐ€ ๋Œ€๋ฌธ์ž์ด๋ฏ€๋กœ ํ‘œ์ค€ key์ธ background์˜ ์•ž์— vendor prefix๋ฅผ ๋ถ™์ด๊ณ  ๋Œ€๋ฌธ์ž๋กœ ๋ฐ”๊พธ๊ณ  ๋‚˜๋จธ์ง€ ๋’ค์ธ 'ackground'๋ฅผ ๋ถ™์—ฌ์ฃผ๋Š” ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค.
  const newKey = v + key[0].toUpperCase() + key.substr(1);
  if(newKey in BASE){ // prefix๋ถ™์ธ ์†์„ฑ์ด body์— ์žˆ๋‹ค๋ฉด,
    prop.set(key, newKey); // border-radius ๋ถ€๋ฅด๋ฉด prefix๋ฅผ ๋ถ™์ธ ์ง„์งœ ์ด๋ฆ„์„ ์บ์‹œ์— ์ €์žฅ
    key = newKey; // ๋ฆฌํ„ดํ•  key๋Š” ๋”์ด์ƒ ์›๋ž˜ ํ‚ค๊ฐ€ ์•„๋‹ˆ๋ผ newKey
    return true; // ์ง„์งœ ์ด๋ฆ„์„ ์ฐพ์•˜์œผ๋‹ˆ ์—ฌ๊ธฐ์„œ ๋Š์–ด ๋ผ๋Š”๊ฒƒ. some์„ ๋” ๋Œ์ง€ ์•Š์•„๋„ ๋œ๋‹ค๊ณ  ๋Š์–ด๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด๋‹ค.
  } else return false;
})){
  // some์˜ ๊ฒฐ๊ณผ๊ฐ€ false์ผ ๊ฒฝ์šฐ์—๋งŒ ์—ฌ๊ธฐ์— ๋“ค์–ด์˜จ๋‹ค.
  prop.set(key, NONE);
  key = NONE;
}
return key; // ๊ทธ๋ƒฅ key๊ฐ€ ๋ฆฌํ„ด๋˜๋“ ์ง€, newKey๊ฐ€ ๋ฆฌํ„ด๋˜๋“ ์ง€, NONE์ด ๋ฆฌํ„ด๋  ๊ฒƒ์ž„

๋‹ค์Œ๋ถ€ํ„ด if(prop.has(key)) return prop.get(key);์— ๊ฑธ๋ ค์„œ(ํ•œ๋ฒˆ ํ•œ ๊ฑด ์บ์‹œ์— ์ด๋ฏธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊บผ๋‚ด์“ฐ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.) ๊ทธ ์•„๋ž˜์˜ ๊ณ„์‚ฐ๋“ค์„ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ํ•œ ๊ฒƒ์€ Vendor Prefix๋ฅผ ๋Ÿฐํƒ€์ž„์— ์กฐ์‚ฌํ•ด์„œ ์ง„์งœ ์ด๋ฆ„์„ ์–ป๊ฒŒ๋˜๋Š” ์ „๋žต์„ ์ง  ๊ฒƒ์ด๋‹ค. ์œ„์—์„œ ๋งํ–ˆ๋“ฏ ๊ณต์‹์ด ํ†ตํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ชจ์งˆ๋ผ ์ด๋ฉด ๋ชจ๋“  ์†์„ฑ์— moz๋ฅผ ๋ถ™์—ฌ์•ผ์ง€~ ์ด๊ฒŒ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ฐ˜๋“œ์‹œ ๋‹น์‹œ์— ํ™•์ธํ•ด์•ผํ•œ๋‹ค. ํฌ๋กฌ์ด๋ผ๊ณ  ์ผ๊ด„์ ์œผ๋กœ webkit์„ ๋ชจ๋‘ ๋ถ™์—ฌ๋„ ์•ˆ ๋œ๋‹ค. ์†์„ฑ๋งˆ๋‹ค ๋‹ค ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ชจ๋“  ๋ธŒ๋ผ์šฐ์ €์— ๋Œ€์‘ํ•˜๋ ค๋ฉด ์ด ๋ฐฉ๋ฒ•๋ฐ–์—” ์—†๋‹ค.

const Style = ((_) => {
  // ...
  const getKey = (key) => {
    // ...
  }; // end of getKey()
  return class {
    constructor(style) {
      this._style = style;
    } // ์ƒ์„ฑ์ž์— style๊ฐ์ฒด๋ฅผ ์ค€๋‹ค. ์ด ํด๋ž˜์Šค๋Š” style ๊ฐ์ฒด๋ฅผ ์•ˆ๊ณ  ํƒœ์–ด๋‚œ๋‹ค.
    // ํ‚ค๋ฅผ ์–ป๊ธฐ(์Šคํƒ€์ผ ์‹œํŠธ์— ์žˆ๋Š” background๋ผ๋Š” ๊ฐ’์„ ์–ป๊ณ ์‹ถ๋‹ค๋ฉด?)
    get(key) {
      key = getKey(key); // ๋ฐ˜๋“œ์‹œ getKey์— ๋ณด๋‚ด์„œ ์ง„์งœ ์ด๋ฆ„์„ ์–ป์–ด์•ผ ํ•œ๋‹ค.
      if (key === NONE) return null; // ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ null์„ ๋ฆฌํ„ดํ•˜๊ธฐ // Unsupported Property ๋ฌธ์ œ ํ•ด๊ฒฐ!
      return this._style[key]; // ์ด๋ฆ„์ด ์žˆ๋‹ค๋ฉด ์ง„์งœ ์ด๋ฆ„์œผ๋กœ style๊ฐ์ฒด์— ํ•ด๋‹น ์†์„ฑ๊ฐ’์„ ๊ฐ€์ ธ์˜ค์ž
    }
    set(key, val) {
      key = getKey(key);
      // key๊ฐ€ NONE์ด ์•„๋‹ˆ๋ฉด
      if (key !== NONE) this._style[key] = val; // ๊ฐ’์„ ์„ค์ •
      // NONE์ด๋ฉด ์Šคํƒ€์ผ์„ ์•„์˜ˆ ๊ฑด๋“ค์ง€ ์•Š๋Š”๋‹ค(Graceful Fail)
      return this; // set์„ ๊ณ„์† ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„์„œ set์„ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ this๋ฅผ ๋ฆฌํ„ด
    }
  };
})();

class๋ฅผ ๋งŒ๋“œ๋Š” ๋ถ€๋ถ„๋„ ์ค‘์š”ํ•˜์ง€๋งŒ getKey() ํ•จ์ˆ˜๊ฐ€ ์†์„ฑ์„ ์–ป์–ด์˜ค๋Š” ๋ฐฉ์‹์ด ๊ฐ€์žฅ ํ•ต์‹ฌ์ด๋‹ค.

๋งŒ๋“  Style ๊ฐ์ฒด ์‚ฌ์šฉํ•˜๊ธฐ & ์ „์ฒด ์ฝ”๋“œ

const Style = ((_) => {
  const prop = new Map(),
    prefix = 'webkt,moz,ms,chrome,o,khtml'.split(',');
  const NONE = Symbol();
  const BASE = document.body.style;
  const getKey = (key) => {
    if (prop.has(key)) return prop.get(key);
    if (key in BASE) prop.set(key, key);
    else if (
      !prefix.some((v) => {
        const newKey = v + key[0].toUpperCase() + key.substr(1);
        if (newKey in BASE) {
          prop.set(key, newKey);
          key = newKey;
          return true;
        } else return false;
      })
    ) {
      prop.set(key, NONE);
      key = NONE;
    }
    return key;
  }; // end of getKey()
  return class {
    constructor(style) {
      this._style = style;
    }
    get(key) {
      key = getKey(key);
      if (key === NONE) return null;
      return this._style[key];
    }
    set(key, val) {
      key = getKey(key);
      if (key !== NONE) this._style[key] = val;
      return this;
    }
  };
})();

const el = document.querySelector('#s');
const sheet = el.sheet;
const rules = sheet.cssRules;
const rule = rules[0];

const style = new Style(rule.style); // โญ
style.set('borderRadius', '20px').set('boxShadow', '0 0 0 10px red');
console.log(rule); // js์—์„œ ์ง€์ •ํ•œ css ์Šคํƒ€์ผ๋“ค์ด ์ž˜ ๋“ค์–ด๊ฐ€์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
<!DOCTYPE html>
<html>
  <head>
    <style id="s">
      .test {
        background: #ff0;
      }
    </style>
  </head>
  <body>
    <div class="test">abc</div>
    <script src="basicTest.js"></script>
  </body>
</html>
  • vendor prefix๋ฅผ ๊ฐ„์„ญํ•˜๊ฑฐ๋‚˜ ์ด์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  ์Šคํƒ€์ผ ์†์„ฑ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • this๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ํ–ˆ์œผ๋ฏ€๋กœ set ์ฒด์ด๋‹์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

๋ธŒ๋ผ์šฐ์ € ๋‚ด๋ถ€์— ๋ฐ˜์˜๋  ๋•Œ๋Š”

์ด๋ ‡๊ฒŒ ๋ฐ˜์˜๋  ์ˆ˜๋„,

์ด๋ ‡๊ฒŒ ๋ฐ˜์˜๋  ์ˆ˜๋„ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

2. Rule ๋งŒ๋“ค๊ธฐ

rule์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ๋“ค(type, selectortext, style, ...)์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ rule์„ ํ†ต์œผ๋กœ ๊ฐ์‹ธ๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค.

const Style = ((_) => {
  // ... ์œ„์—์„œ ๋งŒ๋“ค์—ˆ๋˜ Style ์ฝ”๋“œ
})();

const Rule = class {
  constructor(rule) {
    this._rule = rule;
    this._style = new Style(rule.style);
  }
  get(key) {
    return this._style.get(key);
  }
  set(key, val) {
    this._style.set(key, val);
    return this;
  }
};

const el = document.querySelector('#s');
const sheet = el.sheet;
const rules = sheet.cssRules;
const rule = new Rule(rules[0]); // ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ํด๋ž˜์Šค์ธ Rule์— rule์„ ์ง€์ •ํ•œ๋‹ค.
rule.set('borderRadius', '20px').set('boxShadow', '0 0 0 10px red'); // ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด rule์•ˆ์˜ style์— ์•Œ์•„์„œ ๋ฐ˜์˜์ด ๋  ๊ฒƒ์ด๋‹ค. (rule์ด style์„ ์†Œ์œ ํ•˜๋Š” ๊ตฌ์กฐ์ด๋‹ค.)
  • Rule์˜ ์ƒ์„ฑ์ž์—์„œ rule๊ณผ ์œ„์—์„œ ๋งŒ๋“ค์—ˆ๋˜ Style ๊ฐ์ฒด๋ฅผ ์ง€์ •ํ•œ๋‹ค.
  • get, set๋„ Style์˜ get, set์„ ์“ด๋‹ค.
  • rule์€ get, set์„ ํ•  ๋•Œ Style ๊ฐ์ฒด์— ์˜์กดํ•˜๊ฒŒ ๋˜๊ณ , Style ๊ฐ์ฒด๋Š” get, set์‹œ getKey๋ผ๋Š” ํ•จ์ˆ˜์— ์˜์กดํ•˜๊ฒŒ ๋ผ ์ง„์งœ ์ด๋ฆ„์ธ์ง€ ํ™•์ธํ•˜๋Š” ์ ˆ์ฐจ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค. ์ด๋กœ์จ ๋ณด๋‹ค ๋” ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ css๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

3. Sheet ๋งŒ๋“ค๊ธฐ

rule์„ add/remove ํ•˜๋Š” ๊ฒƒ์ด Sheet ๊ฐ์ฒด์˜ ์ฃผ ๊ธฐ๋Šฅ์ด๋‹ค. ๋™์ ์œผ๋กœ CSS ์ถ”๊ฐ€/์‚ญ์ œํ•˜๊ธฐ ์—์„œ ๋ฐฐ์› ๋˜ ์ฝ”๋“œ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผํ• ์ง€ ์ƒ๊ฐํ•ด๋ณด์ž.

const sheet = el.sheet;
const rules = sheet.cssRules;

// ์ถ”๊ฐ€ // rules์˜ length๊ฐ€ ํ•„์š”ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
sheet.insertRule('.red{background:red}', rules.length);

// ์‚ญ์ œ
sheet.deleteRule(rules.length - 1);
const Style = ((_) => {
  // ...
})();

const Rule = class {
  constructor(rule) {
    this._rule = rule;
    this._style = new Style(rule.style);
  }
  // ...
};

// โญ
const Sheet = class {
  constructor(sheet) {
    this._sheet = sheet;
    this._rules = new Map();
  }
  add(selector) {
    const index = this._sheet.cssRules.length;
    this._sheet.insertRule(`${selector}{}`, index); // selector๋ฅผ ์ง€์ •ํ•˜์—ฌ ๋นˆ rule์„ ๋„ฃ๋Š”๋‹ค.
    const cssRule = this._sheet.cssRules[index]; // ์ง„์งœ cssRule์ด ๋‹ด๊ธด๋‹ค.
    const rule = new Rule(cssRule); // ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  Rule ๊ฐ์ฒด์— cssRule์„ ๋„ฃ๋Š”๋‹ค.
    this._rules.set(selector, rule); // key๋ฅผ selector๋กœ ํ•ด์„œ rule์„ rules์— ์ €์žฅํ•ด๋†“๋Š”๋‹ค. -> ๋‚˜์ค‘์— selector๋กœ ์กฐํšŒํ•  ์ˆ˜๋„  ์žˆ์Œ
    return rule; // add๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง„ rule์ด ๋ฆฌํ„ด๋œ๋‹ค.
  }
  remove(selector) {
    // ์ด์ „์— deleteRule์€ index๋ฅผ ์ง€์ •ํ•ด์•ผ๋งŒ delete๊ฐ€ ๊ฐ€๋Šฅํ–ˆ๋‹ค.
    // ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฑด selector๋กœ Rule์„ ์ง€์šฐ๋Š” ๊ฒƒ์ด๋‹ค.(.red, .blue๋ฅผ ํŠน์ •ํ•˜์—ฌ ์ง€์šฐ๊ณ  ์‹ถ์€ ๊ฒƒ์ด๋‹ค.)
    if (!this._rules.contains(selector)) return; // rules์— ํ•ด๋‹น selector๋กœ๋œ rule์ด ์žˆ๋‹ค๋ฉด ๊ทธ๋ƒฅ ๋ฆฌํ„ด
    const rule = this._rules.get(selector)._rule; // Rule ๊ฐ์ฒด์—๋Š” _rule์ด ์žˆ๋‹ค.(์œ„์—์„œ ์ง  Rule ๊ฐ์ฒด ๊ด€๋ จ ์ฝ”๋“œ ์ฐธ๊ณ ํ•˜๊ธฐ)
    Array.from(this._sheet.cssRules).some((cssRule, index) => {
      // cssRules๋ฅผ ๋Œ๋ฉด์„œ rule๊ณผ ๊ฐ™๋‹ค๋ฉด ํ•ด๋‹น rule์„ ์‚ญ์ œ
      if (cssRule === rule._rule) {
        this._sheet.deleteRule(index);
        return true; // true๋ฅผ ๋ฆฌํ„ดํ•ด some ํ•จ์ˆ˜๋ฅผ ๋ฉˆ์ถ˜๋‹ค.
      }
    });
  }
  get(selector) {
    return this._rule.get(selector);
  }
};

// Sheet ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•ด๋ณด์ž
const sheet = new Sheet(document.styleSheets[0]);
sheet.add('body').set('background', '#f00');
sheet.add('.test').set(
  'cssText',
  `
  width:200px;
  border:1px solid #fff;
  color: #000;
  background: #fff
`
);
<!DOCTYPE html>
<html>
  <head>
    <style></style>
  </head>
  <body>
    <div class="test">test</div>
    <script src="test.js"></script>
  </body>
</html>
  • cssText๋ฅผ ์‚ฌ์šฉํ•ด ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์†์„ฑ์„ ํ•œ๋ฒˆ์— ๋ฐ€์–ด๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์†์„ฑ๋ช… ๋Œ€์‹  CSS ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ๋‹ค๋งŒ ์ด ์˜ˆ์ œ์—์„œ๋Š” ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  key-value ์‹œ์Šคํ…œ์ด ๋ฌด์˜๋ฏธํ•ด์ง„๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ๊ตฌํ˜„ํ•œ ๊ฒƒ์€ CSS rule type 1๋ฒˆ์„ ์ปค๋ฒ„ํ•œ ๊ฒƒ์— ๋ถˆ๊ณผํ•˜๋‹ค. import ๋˜๋Š” ๊ฒฝ์šฐ๋Š”? @font-face ๋“ฑ์€ ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ๊ฐ€?

keyframes ๋‹ค๋ฃจ๊ธฐ

keyframes์—๋Š” from, to์™€ ๊ฐ™์€ keyframe animation ์…€๋ ‰ํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€์žˆ๋‹ค.(DOM ์…€๋ ‰ํ„ฐ๊ฐ€ ์•„๋‹˜) ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ๊ฐ์ฒดํ™” ์‹œํ‚ฌ ๊ฒƒ์ธ๊ฐ€?

const Style = ((_) => {
  const prop = new Map(),
    prefix = 'webkt,moz,ms,chrome,o,khtml'.split(',');
  const NONE = Symbol();
  const BASE = document.body.style;
  const getKey = (key) => {
    if (prop.has(key)) return prop.get(key);
    if (key in BASE) prop.set(key, key);
    else if (
      !prefix.some((v) => {
        const newKey = v + key[0].toUpperCase() + key.substr(1);
        if (newKey in BASE) {
          prop.set(key, newKey);
          key = newKey;
          return true;
        } else return false;
      })
    ) {
      prop.set(key, NONE);
      key = NONE;
    }
    return key;
  }; // end of getKey()
  return class {
    constructor(style) {
      this._style = style;
    }
    get(key) {
      key = getKey(key);
      if (key === NONE) return null;
      return this._style[key];
    }
    set(key, val) {
      key = getKey(key);
      if (key !== NONE) this._style[key] = val;
      return this;
    }
  };
})();

const Rule = class {
  constructor(rule) {
    this._rule = rule;
    this._style = new Style(rule.style);
  }
  get(key) {
    return this._style.get(key);
  }
  set(key, val) {
    this._style.set(key, val);
    return this;
  }
};

const Sheet = class {
  constructor(sheet) {
    this._sheet = sheet;
    this._rules = new Map();
  }
  add(selector) {
    const index = this._sheet.cssRules.length;
    this._sheet.insertRule(`${selector}{}`, index);
    const cssRule = this._sheet.cssRules[index];
    // โญ @keyframes์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ถ„๊ธฐ๊ฐ€ ์ƒ๊ฒผ๋‹ค.
    let rule;
    if (selector.startsWith('@keyframes')) {
      rule = new KeyFramesRule(cssRule);
    } else {
      rule = new Rule(cssRule);
    }
    this._rules.set(selector, rule);
    return rule;
  }
  remove(selector) {
    if (!this._rules.contains(selector)) return;
    const rule = this._rules.get(selector)._rule;
    Array.from(this._sheet.cssRules).some((cssRule, index) => {
      if (cssRule === rule._rule) {
        this._sheet.deleteRule(index);
        return true;
      }
    });
  }
  get(selector) {
    return this._rule.get(selector);
  }
};

// โญ
// KeyFramesRule์€ Sheet ๊ฐ์ฒด์™€ ์ƒ๊น€์ƒˆ๊ฐ€ ๋˜‘๊ฐ™๋‹ค.
// keyframes ๋‚ด๋ถ€๊ฐ€ ์Šคํƒ€์ผ ์‹œํŠธ์ฒ˜๋Ÿผ ์ƒ๊ฒผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
// ์œ ์ผํ•œ ์ฐจ์ด์ ์€ rule์„ ๋„ฃ์„ ๋•Œ insertRule ๋Œ€์‹  appendRule์„ ์จ์•ผํ•œ๋‹ค.(w3c ํ‘œ์ค€)

const KeyFramesRule = class {
  constructor(rule) {
    this._keyframe = rule;
    this._rules = new Map();
  }
  add(selector) {
    const index = this._keyframe.cssRules.length;
    this._keyframe.appendRule(`${selector}{}`);
    const cssRule = this._keyframe.cssRules[index];
    const rule = new Rule(cssRule);
    this._rules.set(selector, rule);
    return rule;
  }
  remove(selector) {
    if (!this._rules.contains(selector)) return;
    const rule = this._rules.get(selector)._rule;
    Array.from(this._keyframe.cssRules).some((cssRule, index) => {
      if (cssRule === rule._rule) {
        this._keyframe.deleteRule(index);
        return true;
      }
    });
  }
};

const sheet = new Sheet(document.styleSheets[0]);
const size = sheet.add('@keyframes size'); // keyframes rule ๊ฐ์ฒด๊ฐ€ ๋ฆฌํ„ด๋จ
size.add('from').set('width', '0'); // Rule ๊ฐ์ฒด๊ฐ€ ๋ฆฌํ„ด๋˜๋ฏ€๋กœ set ์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Œ
size.add('to').set('width', '500px');
  • keyframes animation์„ ๋™์ ์œผ๋กœ ์ •์˜ํ•ด ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด ๋Ÿฐํƒ€์ž„์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ •๋„๋ฅผ ์กฐ์ •ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ keyframe์„ ์“ฐ๊ธธ ํฌ๊ธฐํ•˜๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ผ๋‹ค๋ฉด ์ด์   ๊ทธ๋Ÿฌ์ง€ ์•Š์•„๋„ ๋œ๋‹ค!

Typed CSSOM

https://drafts.css-houdini.org/css-typed-om/

  • CSS draft๋ฅผ ๋‚ด๋Š” ๊ทธ๋ฃน
  • Chrome์˜ ๊ฒฝ์šฐ houdini ํ”„๋กœ์ ํŠธ์—์„œ ์ง„ํ–‰ํ•˜๋Š” draft๋“ค์„ ๊ฑฐ์˜ ๋ฐ˜์˜ํ•œ๋‹ค. ์‚ฌ์‹ค ๊ตฌ๊ธ€์—๊ฒ ํ‘œ์ค€์ด ์•„๋‹ˆ์–ด๋„ ์ƒ๊ด€์ด ์—†๋Š” ๊ฒƒ์ด๋‹ค. (w3c๋ฅผ ์˜คํžˆ๋ ค ๊ท€์ฐฎ์•„ํ•จ)
  • ๊ตฌ๊ธ€์ด houdini ํ”„๋กœ์ ํŠธ๋ฅผ ํ†ตํ•ด Chrome์— ๋ฐ˜์˜ํ•œ ์ŠคํŽ™๋“ค์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค. ๊ทธ์ค‘ paint api๋ฅผ ์ด์šฉํ•˜๋ฉด ์š”์†Œ์˜ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— (์ด๋ฏธ์ง€๋ฅผ ๋„ฃ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ) ๋ณ„์„ ๊ทธ๋ฆฌ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ด์ค‘์—์„œ Typed OM(Object Model)์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณผ ๊ฒƒ์ด๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด CSSOM์˜ ์ •์ ์ธ ํ™•์žฅํŒ์ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
$('#someDiv').style.height = getRandomInt() + 'px';
// ์ฃผ๋ ค๋Š” ๊ฑด ์ˆซ์ž์ธ๋ฐ ์œ„ ๊ฒฝ์šฐ์ฒ˜๋Ÿผ ํ•ญ์ƒ ๋ฌธ์ž์—ด๋กœ ๋งŒ๋“ค์–ด์ค˜์•ผ๋˜๋Š” ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ํ…์ŠคํŠธ๋กœ ์ „ํ™˜ํ•ด์ฃผ๋Š” ๊ณผ์ •์—์„œ ์˜ค๋ž˜๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ๊ตฌ๊ธ€๋„ ์ด๊ฒŒ ์‹ซ์—ˆ๋˜ ๊ฒƒ! ์œ„ ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

const h = $('someDiv').styleMap.get('height');
$('#otherDiv').styleMap.set('height', h);
// ์ด๊ฒŒ typed OM์ด๋‹ค. h๊ฐ€ ๋„๋Œ€์ฒด ๋ญ˜๊นŒ?
CSS.number(0.5); //ํฌ๋กฌ์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅ
// ์ˆœ์ˆ˜ํ•œ ์ˆซ์ž๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
// CSS์—์„œ ์ˆœ์ˆ˜ํ•œ ์ˆซ์ž๋ฅผ ์“ฐ๋Š” ๊ฒฝ์šฐ๋Š” opacity, z-index ๋“ฑ์ด ์žˆ๋‹ค.
el.styleMap.set('opacity', CSS.number(0.5));

CSS.px(500); // ์šฐ๋ฆฌ๊ฐ€ ์นœ์ˆ™ํ•œ px!
el.styleMap.set('height', CSS.px(500)); // ์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ๋”์ด์ƒ ๋ฌธ์ž์—ด์„ ์“ฐ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
// ์ •์ ์ธ ํ˜•์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹คํ•˜์—ฌ Typed OM์ด๋ผ๊ณ  ํ•œ๋‹ค.(ํ˜•์— ๋งž๋Š” ๊ฐ’์„ ๋ณด๋ƒ„)

CSS์— ์žˆ๋Š” Type์˜ ์ข…๋ฅ˜

CSSTransformValue
  ใ„ดCSSTransformComponent(์•„๋ž˜ ์š”์†Œ๋“ค์„ ๋ฌถ์–ด์ค€๋‹ค.)
    ใ„ดCSSTranslate, CSSRotate, CSSScale, CSSSkew, ...

margin: 10px 0 0 10px -> trbl ์„ ๋ฌถ์–ด์ฃผ๋Š” CSSPositionValue ํ˜•์ด ํ•„์š”ํ•˜๋‹ค.(number 2๊ฐœ๋‚˜ 4๊ฐœ๋ฅผ ๋ฐ›์•„๋“ค์ผ ์ˆ˜ ์žˆ๋‹ค)

background: url('a.png') -> CSSImageValue ๋ผ๋Š” ํƒ€์ž… ํ•„์š”
CSS๊ฐ’์ค‘ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค - list style(์œ ์—ฐํ•จ), cursor(ํฌ๊ธฐ, ๋ธŒ๋ผ์šฐ์ €์— ์žˆ์–ด ์ œํ•œ์ )

inset, left... -> CSSStyleValue
<!DOCTYPE html>
<html>
  <head>
    <style>
      .test {
        background: #f00;
      }
    </style>
  </head>
  <body>
    <div class="test">test</div>
    <script>
      document
        .querySelector('.test')
        .attributeStyleMap.set('height', CSS.px(300));
    </script>
  </body>
</html>
  • ์ฐธ๊ณ ) attributeStyleMap ์ด ์ด๋ฆ„์€ ๋ธŒ๋ผ์šฐ์ € ๋ฒ„์ „๋งˆ๋‹ค ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค.
  • ํ˜„์‹ค์—” ๋ฒ”์šฉ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ง€์›ํ•˜๋Š” ์›น์‚ฌ์ดํŠธ vs ํฌ๋กฌ๋งŒ ์ง€์›ํ•˜๋Š” ์›น์‚ฌ์ดํŠธ(ex.๊ด€๋ฆฌ์žํŽ˜์ด์ง€)๊ฐ€ ์žˆ๋‹ค. ์จŒ๋“  ํฌ๋กฌ๋งŒ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ ์ด๋Ÿฐ ์ŠคํŽ™ ์จ๋„๋œ๋‹ค๋Š” ๊ฒƒ...

Comment

References

ํŒ€์›๋“ค ๊ฒฐ๊ณผ๋ฌผ

STEP 40

STEP 41