๐ 14. ํ๋์ ์ธ CSS: 'Nesting, Layers, ๊ทธ๋ฆฌ๊ณ Scope์ ํ๋ช '
๐ ๊ฐ์
SASS ์์ด๋ ๊ฐ๋ฅํ ์ ๊ท Nesting๋ถํฐ ์คํ์ผ ์ฐ์ ์์์ ๊ตฌ์ํฌ์์ธ Cascade Layers๊น์ง, CSS์ ํ๋๋ฅผ ๋ฐ๊พธ๊ณ ์๋ ์ต์ ๋๊ตฌ๋ค์ ์์ฒ ์ด์ ํจ๊ป ๋ง์คํฐํฉ๋๋ค.
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 8๋ถ(์ ์ฒด) / ํต์ฌ ํํธ๋ง: 4๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
[๋ค์ดํฐ๋ธ Nesting์ ๋ฑ์ฅ] โ [Cascade Layers(@layer)] โ [Scoped CSS(@scope)]
๐ฏ ์ด ๋ฌธ์๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- ์ ์ฒ๋ฆฌ๊ธฐ(SASS) ์์ด ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ ๊ธฐ๋ฅ๋ง์ผ๋ก ๊น๋ํ ์ค์ฒฉ ๊ตฌ์กฐ๋ฅผ ์งญ๋๋ค.
-
@layer๋ฅผ ํ์ฉํด ์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ด ์คํ์ผ์ ์ฐ์ ์์๋ฅผ ๋ช ํํ ๋ถ๋ฆฌํฉ๋๋ค. -
@scope๋ฅผ ํตํด ํน์ ์์ญ ์์์๋ง ์๋ํ๋ ์์ ํ ์คํ์ผ๋ง์ ๊ตฌํํฉ๋๋ค.
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ๐ฃ ์์ฒ ( ์ ์
): "์ํธ ๋! ์ ์
๋ ๋ฐฐ์ด CSS๋ ์ง๊ธ CSS๊ฐ ๋๋ฌด ๋ฌ๋ผ์. SASS ์ ์จ๋ ๋๋ค๋ ์ฌ๋๋ ์๊ณ ,
!important์์ด๋ ์ฐ์ ์์๋ฅผ ๋ฐ๊ฟ ์ ์๋ค๋ ์๋ฌธ์ ๋ค์๋๋ฐ... ์ง์ง์ธ๊ฐ์? ๐ฎ" - ๐ฆ ์ํธ ( ๋ฆฌ๋ ): "์์ฒ ๋, CSS๋ ์ง๊ธ ๊ทธ ์ด๋ ๋๋ณด๋ค ๋น ๋ฅด๊ฒ ์งํํ๊ณ ์์ต๋๋ค. ๊ณผ๊ฑฐ์ ๊ผผ์(Hacks)๋ค์ด ์ ์ ์คํ์ผ๋ก ๋ค์ด์ค๊ณ ์์ฃ . ์ด์ ๋ ๋๊ตฌ์ ํ์ด ์๋, ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ ์ ๊ณตํ๋ '์งํ๋ CSS'๋ฅผ ๋ค๋ฃฐ ์ค ์์์ผ ์ง์ง ์๋์ด์ ๋๋ค."
๐ค ์ ์์์ผ ํ๋๊ฐ
์ต๊ทผ 1~2๋
์ฌ์ด CSS๋ ์์ญ ๋
๋์ ํ์ง ๋ชปํ๋ ๋์ ๋ค์ ํด๊ฒฐํ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ๋ค์ ๋ฐํํ์ต๋๋ค. ์ด์ ๋ !important๋ก ์ ์์ ์น๋ฅผ ํ์๋ ์๊ณ , ํด๋์ค ์ด๋ฆ์ ๋ฌด์กฐ๊ฑด ๊ธธ๊ฒ ์ง์ ํ์๋ ์์ต๋๋ค.
์ด ์ต์ ๊ธฐ๋ฅ๋ค์ ๋จ์ํ 'ํธ๋ฆฌํจ'์ ๋์ด **'์ ์ง๋ณด์ ํจ์จ'**์ ๊ทน๋์ ์ผ๋ก ๋์ฌ์ค๋๋ค. 5๋ ์ฐจ ์ด์์ ์๋์ด๋ ๊ณผ๊ฑฐ์ ๋ฐฉ์์ ์์ฃผํ์ง ์๊ณ , ์ต์ ์คํ์ ์ฌ์ฉํด ๋ ๊ฐ๊ฒฐํ๊ณ ๊ฐ๋ ฅํ ์ํคํ ์ฒ๋ฅผ ์ค๊ณํฉ๋๋ค.
๐๏ธ 1. Native Nesting: SASS๋ ์๋ ?
์ด์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ Nesting์ ์ง์ํฉ๋๋ค. ๋น๋ ๊ณผ์ ์์ด๋ ๊ฐ๋ ์ฑ ์ข์ ์ฝ๋๋ฅผ ์งค ์ ์์ต๋๋ค.
/* ๐ฆ ์ํธ: ์ด์ ์ฐํผ์๋(&) ํ๋๋ฉด ์ถฉ๋ถํฉ๋๋ค. */
.card {
background: white;
& .title {
font-weight: bold;
}
&:hover {
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
}
}๐ก๏ธ 2. Cascade Layers (@layer): ์ฐ์ ์์ ์ ์ด๊ถ ํํ
์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ด '๋ช ์๋(Specificity)'๋ฅผ ๋ค์์ ์ ์๋ ์ ์ผํ ๋๊ตฌ์ ๋๋ค. ์ฝ๋์ ์์๋ ์ ํ์์ ์ ์์ ์๊ด์์ด, ์คํ์ผ์ '๊ณ๊ธ'์ ๋ฏธ๋ฆฌ ์ ํด๋ก๋๋ค.
/* ๐ฆ ์ํธ: ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ฌด๋ฆฌ ์ ์๊ฐ ๋์๋, ๋ด ํ
๋ง(theme) ์ธต์ด ๋ฌด์กฐ๊ฑด ์ด๊น๋๋ค. */
@layer reset, base, components, theme;
@layer theme {
.btn { color: red !important; } /* ํน์ ๊ณ์ธต์ ๋ชจ๋ ๊ถํ ๋ถ์ฌ */
}๐ฏ 3. Scoped CSS (@scope): ์์ ํ ์คํ์ผ ์ธํ๋ฆฌ
ํน์ ์์ ์์์๋ง ์คํ์ผ์ด ํ๋ฅด๊ฒ ๊ฐ๋ก๋๋ค. ํด๋์ค ์ด๋ฆ ์ถฉ๋ ๊ฑฑ์ ์ ํ๊ธฐ์ ์ผ๋ก ์ค์ฌ์ค๋๋ค.
@scope (.card) {
img {
border-radius: 50%; /* ์ด .card ์์ img ์๋ง ์ ์ฉ! */
}
}๐ฃ ์์ฒ : "์... ๊ทธ๋ผ ์ด์ ์ปดํฌ๋ํธ๋ง๋ค ํด๋์ค ์ด๋ฆ์ __๋ก ์ ์ด์ด๋ @scope๋ก ๊ฐ์ธ๋ฉด ๋๊ฒ ๋ค์? ์ฝ๋๊ฐ ํจ์ฌ ๊น๋ํด์ง๊ฒ ์ด์!"
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ๋ค์ดํฐ๋ธ CSS Nesting์์ ๋ถ๋ชจ ์ ํ์๋ฅผ ์ฐธ์กฐํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ๊ธฐํธ๋ ๋ฌด์์ธ๊ฐ์?
โ
์ ๋ต: & (์ฐํผ์๋)
๐ก ์์ธ ํด์ค:
- ์๋ฆฌ: CSS Nesting ๋ช
์ธ์ ๋ฐ๋ฅด๋ฉด
&๊ธฐํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ถ๋ชจ ์์๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค. SASS์ ๋ฌธ๋ฒ์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์์ผ๋ก ์์ฉํ ํํ์ ๋๋ค. - ์ค๋ต ํผ๋๋ฐฑ: "์์ฒ ๋, ์ด์ ์ ์ฒ๋ฆฌ๊ธฐ ์์ด๋
&ํ๋๋ฉด ๋ถ๋ชจ ์คํ์ผ์ ์ฅ ๊ฐ์ ธ์ฌ ์ ์์ด์. ๊ฐ๋ ์ฑ์ด ํจ์ฌ ์ข์์ง๊ฒ ์ฃ ?"
Q2. @layer๋ฅผ ์ฌ์ฉํ๋ ๊ฐ์ฅ ํฐ ๋ชฉ์ ์ ๋ฌด์์ผ๊น์?
- ์ ๋๋ฉ์ด์ ์๋๋ฅผ ๋น ๋ฅด๊ฒ ํ๊ธฐ ์ํด
- ์คํ์ผ์ ์ฐ์ ์์(Specificity)๋ฅผ ๋ช ์์ ์ผ๋ก ๊ณ์ธตํํ์ฌ ๊ด๋ฆฌํ๊ธฐ ์ํด
- ๋คํฌ ๋ชจ๋๋ฅผ ์ฝ๊ฒ ๊ตฌํํ๊ธฐ ์ํด
- CSS ํ์ผ์ ๋ก๋ฉ ์๋๋ฅผ ๋์ด๊ธฐ ์ํด
โ
์ ๋ต: 2. ์คํ์ผ์ ์ฐ์ ์์(Specificity)๋ฅผ ๋ช
์์ ์ผ๋ก ๊ณ์ธตํํ์ฌ ๊ด๋ฆฌํ๊ธฐ ์ํด
๐ก ์์ธ ํด์ค:
- ์๋ฆฌ:
@layer๋ ์ ํ์์ ์ ์์ ๊ด๊ณ์์ด ์คํ์ผ์ ๋ฐ์ ์์๋ฅผ ์ ์ดํฉ๋๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์คํ์ผ๊ณผ ๋ด ์คํ์ผ์ด ์ถฉ๋ํ ๋, ๋ ์ด์ด ์์๋ง์ผ๋ก ์ฐ์ํ๊ฒ ์น์๋ฅผ ๊ฒฐ์ ํ ์ ์์ต๋๋ค. - ์ค๋ต ํผ๋๋ฐฑ: "์์ฒ ๋, ์ ์ ๊ณ์ฐํ๋๋ผ ๋จธ๋ฆฌ ์ธ๋งค์ง ๋ง๊ณ
@layer๋ก ๊ณ๊ธ์ฅ์ ํ์คํ ๋ฌ์์ฃผ์ธ์!"
Q3. [์์ฒ ์ด์ ํ
์คํธ ํ์: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ๋ ์ด๋์คํ]
์์ฒ ์ด๊ฐ ์ธ๋ถ UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ์ ธ์๋๋ฐ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์คํ์ผ์ด ๋๋ฌด ๊ฐ๋ ฅํด์ ์์ฒ ์ด๊ฐ ์ง ์ปค์คํ
์คํ์ผ์ด ์๊พธ ์นํ๋๋ค. !important๋ฅผ ๋๋ฐฐํ๊ธฐ๋ ์ซ์๋ฐ, ์์ฒ ์ด๊ฐ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ 'ํ'์ ์ ์คํ๊ฒ ๋ฎ์ถ๊ณ ๋ด ์คํ์ผ ๋ ์ด์ด๋ฅผ ๊ทธ ์๋ก ์ฌ๋ฆด ์ ์๋ ์ต์ CSS ๊ธฐ์ ์?
โ
์ ๋ต: Cascade Layers (@layer)๋ฅผ ์ฌ์ฉํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์คํ์ผ๊ณผ ์ปค์คํ
์คํ์ผ์ ๊ณ์ธต ์์๋ฅผ ์ ์ํ๋ค.
๐ก ์์ธ ํด์ค:
- ์๋ฆฌ ์ค๋ช
:
@layer์์์ ์ ์๋ ์คํ์ผ์ ์ ์๊ฐ ๋ฎ๋๋ผ๋ ์ ์ธ๋ ๊ณ์ธต ์์๊ฐ ๋์ผ๋ฉด ์น๋ฆฌํฉ๋๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ ๋ ์ด์ด๋ก, ๋ด ์ฝ๋๋ฅผ ์์ ๋ ์ด์ด๋ก ๋๋ฉด ํํ๋ก์ด ๊ณต์กด์ด ๊ฐ๋ฅํฉ๋๋ค. - ์ค๋ต ํผ๋๋ฐฑ: "์์ฒ ๋, ์ ์ญ์ ์ค์ผ์ํค๋
!important๋์ '๋ ์ด์ด ์ ๋ ฌ'์ด๋ผ๋ ํ๋์ ์ธ ์ธ๊ต์ ์ ์ฐ์ธ์." - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "์ ์(Specificity)๋ณด๋ค ๊ณ๊ธ(@layer)์ด ๋๋ค!"
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ค๋ CSS์ ๋ฏธ๋๋ฅผ ๋ณธ ๊ฒ ๊ฐ๋ค.
๊ทธ๋์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ธ์ฐ๋๋ผ ์ต์ง๋ก ํด๋์ค ์ด๋ฆ์ ๊ธธ๊ฒ ๋์ด๊ณ !important๋ฅผ ์ฐ๋ ๋ด๊ฐ ์ผ๋ง๋ ๊ณ ์ํ๋์ง... @layer ํ๋๋ฉด ํด๊ฒฐ๋ ์ผ์ด์๋ค๋!
๐ก "CSS์ ์ต์ ๊ธฐ๋ฅ์ ๊ณผ๊ฑฐ์ ๊ณ ํต์ ํด๊ฒฐํ๊ธฐ ์ํ ์ ๋ต์ง๋ค. ์ ๋ต์ ์๋ฉด ์ฝ๋ฉ์ด ์ฆ๊ฑฐ์์ง๋ค."
์ํธ ๋์ด "์คํ์ ๊ณ์ ๋ณด์ํด์ผ ํ์ง๋ง, ์์ผ๋ ํญ์ ์ด์ด๋ฌ์ผ ํ๋ค"๋ผ๊ณ ํ์
จ๋ค.
๋ธ๋ผ์ฐ์ ์ง์ ๋ฒ์(Caniuse)๋ฅผ ์ฒดํฌํด๋ณด๋ ์ด๋ฏธ ์ค๋ฌด์์ ์ธ๋งํ ์์ค๊น์ง ์ฌ๋ผ์๋๋ผ. ๋น์ฅ ๋ด์ผ๋ถํฐ ๋ด ์ฌ์ด๋ ํ๋ก์ ํธ์ @layer๋ฅผ ๋ฐ๋ผ๋ด์ผ์ง. ๐