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