5 min read

당신이 λͺ°λžλ˜ CSS μ„ νƒμžμ™€ 속성듀

이것도 λ‚˜λ§Œ λͺ°λžλ˜ κ±Έ μˆ˜λ„ 있고...

Table of Contents

λ“€μ–΄κ°€λ©°

CSSλŠ” μ›Ή κ°œλ°œμ—μ„œ λ””μžμΈμ„ λ‹΄λ‹Ήν•˜λŠ” μ€‘μš”ν•œ μ–Έμ–΄μž…λ‹ˆλ‹€.
ν•˜μ§€λ§Œ λŒ€λΆ€λΆ„μ˜ 개발자(μ €)λŠ” margin, padding, color, font-size 같은 μ†μ„±λ§Œ μ‚¬μš©ν•©λ‹ˆλ‹€. 그런데 CSSμ—λŠ” 이보닀 훨씬 더 λ‹€μ–‘ν•œ μ„ νƒμžμ™€ 속성듀이 μžˆμŠ΅λ‹ˆλ‹€. λ§Žμ€ μƒν™©μ—μ„œ μœ μš©ν•˜κ²Œ 쓰일 수 μžˆμ§€λ§Œ, μ΅μˆ™ν•˜μ§€ μ•Šμ•„μ„œ μ‚¬μš©ν•˜μ§€ μ•Šκ±°λ‚˜ 개발의 편의λ₯Ό μœ„ν•΄μ„œ JavaScriptλ₯Ό μ‚¬μš©ν•˜λŠ” κ²½μš°κ°€ λ§ŽμŠ΅λ‹ˆλ‹€.

μ˜€λŠ˜μ€ κ·Έ μ€‘μ—μ„œλ„ 특히 ν₯미둜운 λͺ‡ 가지λ₯Ό μ†Œκ°œν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. 그럼 … λ ˆμ“°κ³ 


1. :is()와 :where(): μ„ νƒμž κ·Έλ£Ήν™”

μ—¬λŸ¬ μ„ νƒμžλ₯Ό κ·Έλ£Ήν™”ν•  λ•Œ, 보톡은 각 μ„ νƒμžλ₯Ό λ”°λ‘œ μž‘μ„±ν•˜κ³€ ν•©λ‹ˆλ‹€.
ν•˜μ§€λ§Œ :is()와 :where()λ₯Ό μ‚¬μš©ν•˜λ©΄ 더 κ°„κ²°ν•˜κ²Œ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

/* κΈ°μ‘΄ 방식 */
header h1,
header h2,
header h3 {
  color: blue;
}

/* :is() μ‚¬μš© */
header :is(h1, h2, h3) {
  color: blue;
}

/* :where() μ‚¬μš© */
header :where(h1, h2, h3) {
  color: blue;
}
  • :is(): μ„ νƒμž 그룹을 λ¬Άμ–΄μ„œ μŠ€νƒ€μΌμ„ μ μš©ν•©λ‹ˆλ‹€.
  • :where(): :is()와 λΉ„μŠ·ν•˜μ§€λ§Œ, νŠΉμ΄λ„κ°€ 0μž…λ‹ˆλ‹€.

이 μ„ νƒμžλ“€μ€ λ³΅μž‘ν•œ μ„ νƒμžλ₯Ό κ°„κ²°ν•˜κ²Œ μž‘μ„±ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.


2. :has(): 쑰건뢀 μ„ νƒμž

νŠΉμ • μš”μ†Œλ₯Ό ν¬ν•¨ν•˜λŠ” λΆ€λͺ¨ μš”μ†Œλ₯Ό 선택할 λ•Œ, 보톡은 JavaScriptλ₯Ό μ‚¬μš©ν•˜κ³€ ν•©λ‹ˆλ‹€.
ν•˜μ§€λ§Œ :has()λ₯Ό μ‚¬μš©ν•˜λ©΄ CSSλ§ŒμœΌλ‘œλ„ 쑰건뢀 선택이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

/* 이미지λ₯Ό ν¬ν•¨ν•˜λŠ” div에 μŠ€νƒ€μΌ 적용 */
div:has(img) {
  border: 2px solid blue;
}

/* νŠΉμ • 클래슀λ₯Ό 가진 μžμ‹ μš”μ†Œλ₯Ό ν¬ν•¨ν•˜λŠ” μš”μ†Œ 선택 */
section:has(.highlight) {
  background-color: yellow;
}
  • :has(): νŠΉμ • μš”μ†Œλ₯Ό ν¬ν•¨ν•˜λŠ” λΆ€λͺ¨ μš”μ†Œλ₯Ό μ„ νƒν•©λ‹ˆλ‹€.

이 μ„ νƒμžλŠ” 아직 일뢀 λΈŒλΌμš°μ €μ—μ„œλ§Œ μ§€μ›λ˜μ§€λ§Œ, 맀우 κ°•λ ₯ν•œ κΈ°λŠ₯μž…λ‹ˆλ‹€.


3. @supports: κΈ°λŠ₯ 지원 μ—¬λΆ€ 확인

νŠΉμ • CSS κΈ°λŠ₯이 λΈŒλΌμš°μ €μ—μ„œ μ§€μ›λ˜λŠ”μ§€ 확인할 λ•Œ, 보톡은 JavaScriptλ₯Ό μ‚¬μš©ν•˜κ³€ ν•©λ‹ˆλ‹€.
ν•˜μ§€λ§Œ @supportsλ₯Ό μ‚¬μš©ν•˜λ©΄ CSSλ§ŒμœΌλ‘œλ„ κΈ°λŠ₯ 지원 μ—¬λΆ€λ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

/* κ·Έλ¦¬λ“œ λ ˆμ΄μ•„μ›ƒ 지원 μ—¬λΆ€ 확인 */
@supports (display: grid) {
  .container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
  }
}

/* μ‚¬μš©μž μ •μ˜ 속성 지원 μ—¬λΆ€ 확인 */
@supports (--custom-property: value) {
  .element {
    background-color: var(--custom-property);
  }
}
  • @supports: νŠΉμ • CSS κΈ°λŠ₯이 μ§€μ›λ˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.

이 κΈ°λŠ₯은 점진적 ν–₯상(Progressive Enhancement)을 κ΅¬ν˜„ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.


4. clip-path: μš”μ†Œμ˜ ν˜•νƒœ λ³€ν˜•

μš”μ†Œμ˜ ν˜•νƒœλ₯Ό λ³€ν˜•ν•  λ•Œ, 보톡은 border-radiusλ₯Ό μ‚¬μš©ν•˜κ³€ ν•©λ‹ˆλ‹€.
ν•˜μ§€λ§Œ clip-pathλ₯Ό μ‚¬μš©ν•˜λ©΄ 더 λ³΅μž‘ν•œ ν˜•νƒœλ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

/* μ›ν˜•μœΌλ‘œ 자λ₯΄κΈ° */
.circle {
  clip-path: circle(50%);
}

/* λ‹€κ°ν˜•μœΌλ‘œ 자λ₯΄κΈ° */
.polygon {
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}

/* SVGλ₯Ό μ‚¬μš©ν•œ λ³΅μž‘ν•œ ν˜•νƒœ */
.custom-shape {
  clip-path: url(#custom-shape);
}
  • clip-path: μš”μ†Œμ˜ ν˜•νƒœλ₯Ό λ³€ν˜•ν•©λ‹ˆλ‹€.

이 속성은 창의적인 λ””μžμΈμ„ κ΅¬ν˜„ν•  λ•Œ 맀우 μœ μš©ν•©λ‹ˆλ‹€.


5. aspect-ratio: μš”μ†Œμ˜ μ’…νš‘λΉ„ μ„€μ •

μš”μ†Œμ˜ μ’…νš‘λΉ„λ₯Ό μ„€μ •ν•  λ•Œ, 보톡은 padding-top을 μ‚¬μš©ν•˜κ³€ ν•©λ‹ˆλ‹€.
ν•˜μ§€λ§Œ aspect-ratioλ₯Ό μ‚¬μš©ν•˜λ©΄ 더 κ°„λ‹¨ν•˜κ²Œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

/* 16:9 λΉ„μœ¨ μ„€μ • */
.video {
  aspect-ratio: 16 / 9;
}

/* μ •μ‚¬κ°ν˜• μ„€μ • */
.square {
  aspect-ratio: 1 / 1;
}
  • aspect-ratio: μš”μ†Œμ˜ μ’…νš‘λΉ„λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

이 속성은 λ°˜μ‘ν˜• λ””μžμΈμ„ κ΅¬ν˜„ν•  λ•Œ 맀우 μœ μš©ν•©λ‹ˆλ‹€.


6. scroll-snap: 슀크둀 μŠ€λƒ… κΈ°λŠ₯

슀크둀 μ‹œ μš”μ†Œκ°€ νŠΉμ • μœ„μΉ˜μ— μŠ€λƒ…λ˜λ„λ‘ ν•  λ•Œ, 보톡은 JavaScriptλ₯Ό μ‚¬μš©ν•˜κ³€ ν•©λ‹ˆλ‹€.
ν•˜μ§€λ§Œ scroll-snap을 μ‚¬μš©ν•˜λ©΄ CSSλ§ŒμœΌλ‘œλ„ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

.container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  height: 300px;
}

.item {
  scroll-snap-align: start;
  height: 100px;
}
  • scroll-snap-type: 슀크둀 μŠ€λƒ… νƒ€μž…μ„ μ„€μ •ν•©λ‹ˆλ‹€.
  • scroll-snap-align: μŠ€λƒ… μœ„μΉ˜λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

이 속성은 μΊλŸ¬μ…€(Carousel)μ΄λ‚˜ νŽ˜μ΄μ§€ μŠ€ν¬λ‘€μ„ κ΅¬ν˜„ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.


7. :empty: 빈 μš”μ†Œ 선택

λ™μ μœΌλ‘œ μ½˜ν…μΈ κ°€ λ‘œλ“œλ˜λŠ” μƒν™©μ—μ„œ 빈 μš”μ†Œλ₯Ό μ²˜λ¦¬ν•  λ•Œ, 보톡은 JavaScriptλ₯Ό μ‚¬μš©ν•˜κ³€ ν•©λ‹ˆλ‹€.
ν•˜μ§€λ§Œ :empty μ„ νƒμžλ₯Ό μ‚¬μš©ν•˜λ©΄ CSSλ§ŒμœΌλ‘œλ„ 빈 μš”μ†Œλ₯Ό 선택할 수 μžˆμŠ΅λ‹ˆλ‹€.

/* 빈 μš”μ†Œ 숨기기 */
.container:empty {
  display: none;
}

/* 빈 μš”μ†Œμ— ν”Œλ ˆμ΄μŠ€ν™€λ” ν‘œμ‹œ */
.content:empty::before {
  content: "데이터 λ‘œλ”© 쀑...";
  color: #999;
}
  • :empty: μžμ‹ μš”μ†Œλ‚˜ ν…μŠ€νŠΈκ°€ μ—†λŠ” μš”μ†Œλ₯Ό μ„ νƒν•©λ‹ˆλ‹€.

이 μ„ νƒμžλŠ” λ‘œλ”© μƒνƒœλ‚˜ 빈 μƒνƒœλ₯Ό μ²˜λ¦¬ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.


8. writing-mode: ν…μŠ€νŠΈ λ°©ν–₯ μ„€μ •

μ„Έλ‘œ λ°©ν–₯ ν…μŠ€νŠΈλ₯Ό κ΅¬ν˜„ν•  λ•Œ, 보톡은 λ³΅μž‘ν•œ λ ˆμ΄μ•„μ›ƒ 기법을 μ‚¬μš©ν•˜κ³€ ν•©λ‹ˆλ‹€.
ν•˜μ§€λ§Œ writing-modeλ₯Ό μ‚¬μš©ν•˜λ©΄ κ°„λ‹¨ν•˜κ²Œ ν…μŠ€νŠΈ λ°©ν–₯을 λ³€κ²½ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

/* μ„Έλ‘œ λ°©ν–₯ ν…μŠ€νŠΈ (μœ„μ—μ„œ μ•„λž˜λ‘œ) */
.vertical-text {
  writing-mode: vertical-rl;
}

/* κ°€λ‘œ λ°©ν–₯ ν…μŠ€νŠΈ (κΈ°λ³Έκ°’) */
.horizontal-text {
  writing-mode: horizontal-tb;
}
  • writing-mode: ν…μŠ€νŠΈμ˜ μ“°κΈ° λ°©ν–₯을 μ„€μ •ν•©λ‹ˆλ‹€.

이 속성은 λ‹€κ΅­μ–΄ μ§€μ›μ΄λ‚˜ 창의적인 λ ˆμ΄μ•„μ›ƒμ„ κ΅¬ν˜„ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.


마무리

μ˜€λŠ˜μ€ :is(), :where(), :has(), @supports, clip-path, aspect-ratio, scroll-snap, :empty, writing-mode와 같은 νŠΉμ΄ν•œ CSS μ„ νƒμžμ™€ 속성듀을 μ†Œκ°œν–ˆμŠ΅λ‹ˆλ‹€.
CSS둜 ν•΄κ²°ν•  수 μžˆλŠ” λ¬Έμ œλŠ” JS의 도움을 받지 μ•Šμ•„λ„ ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 이런 μ„ νƒμžμ™€ 속성듀을 잘 ν™œμš©ν•˜λ©΄,

  • 더 κ°„κ²°ν•˜κ³  효율적인 CSSλ₯Ό μž‘μ„±ν•  수 있고,
  • JavaScript μ˜μ‘΄λ„λ₯Ό 쀄일 수 있으며,
  • λ§ˆν¬μ—… μ½”λ“œλ₯Ό 더 κΉ”λ”ν•˜κ²Œ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

그럼 λ‹€μŒ 번 ν”„λ‘œμ νŠΈμ—μ„œ ν•œλ²ˆ ν™œμš©ν•΄λ³΄λŠ” 건 μ–΄λ–¨κΉŒμš”?