--- id: frontend-css-modern-features title: Modern CSS — :has() / Subgrid / Color spaces / @scope category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [frontend, css, vibe-coding] tech_stack: { language: "CSS", applicable_to: ["Frontend"] } applied_in: [] aliases: [:has, subgrid, OKLCH, color-mix, @scope, anchor positioning, popover] --- # Modern CSS > 2024-2026 = CSS 황금기. **:has() (parent selector), subgrid, OKLCH, @scope, anchor positioning, popover, container queries**. JS 없이 가능한 게 늘어남. ## 📖 핵심 개념 - :has(): parent selector (드디어). - Subgrid: nested grid 가 parent grid 따름. - OKLCH: perceptually uniform color. - @scope: CSS scope (CSS-in-JS 의 native). - Anchor positioning: tooltip / popover 자동 align. ## 💻 코드 패턴 ### :has() — parent selector ```css /* Card 안 image 가 있으면 padding 변경 */ .card:has(img) { padding: 0; } /* Form 안 :invalid input 가 있으면 button disable */ form:has(input:invalid) button { opacity: 0.5; pointer-events: none; } /* Sibling */ .card + .card:has(.featured) { border-color: gold; } /* :has + :not */ .list:has(:not(.read)) { background: yellow; } ``` → JS 없이 parent / sibling 반응. Chrome 105+ / Safari 15.4+ / FF 121+. ### Subgrid ```css .parent { display: grid; grid-template-columns: 1fr 2fr 1fr; gap: 16px; } .parent > .nested { display: grid; grid-template-columns: subgrid; /* parent 의 column 따름 */ grid-column: 1 / -1; /* 모든 column */ } ``` → Nested grid 가 parent column align. ### OKLCH (modern color) ```css :root { --primary: oklch(60% 0.2 250); /* L=60% C=0.2 H=250 */ --primary-hover: oklch(55% 0.2 250); /* darker */ --primary-bg: oklch(95% 0.05 250); /* lighter */ } .button { background: var(--primary); } .button:hover { background: oklch(from var(--primary) calc(l - 5%) c h); } ``` → HSL 보다 perceptually uniform. Tailwind 4 가 default. ### color-mix ```css .card { background: color-mix(in oklch, var(--brand) 80%, white); border-color: color-mix(in srgb, var(--brand) 50%, transparent); } ``` → 동적 color 변형. ### @scope ```css @scope (.card) to (.card-content) { /* .card ~ .card-content 사이만 */ h2 { color: red; } p { font-size: 14px; } } ``` ```html

...

...

``` → CSS module / CSS-in-JS 의 native 대안. ### Anchor positioning ```css .tooltip { position-anchor: --anchor-1; /* anchor name */ position: absolute; top: anchor(bottom); left: anchor(center); translate: -50% 0; } .button { anchor-name: --anchor-1; } ``` ```html
Tooltip text
``` → JS positioning 없이 자동 align. Chrome 125+. ### Popover API ```html

Popover content

``` ```css [popover] { border: none; border-radius: 8px; padding: 1rem; } [popover]::backdrop { background: rgba(0, 0, 0, 0.5); } ``` → Native modal / dropdown. 모든 modern browser. ### CSS nesting ```css /* Modern — Sass-like */ .card { padding: 16px; & .title { font-size: 24px; &:hover { color: blue; } } &:has(img) { padding: 0; } } ``` → Sass / PostCSS 없이. ### Logical properties (RTL friendly) ```css .card { /* 옛 */ margin-left: 16px; padding-right: 8px; /* 새 — RTL 자동 */ margin-inline-start: 16px; padding-inline-end: 8px; } ``` ### Cascade layers (@layer) ```css @layer reset, base, components, utilities; @layer reset { * { margin: 0; } } @layer components { .button { ... } } @layer utilities { .mt-4 { margin-top: 1rem; } } ``` → Specificity 충돌 해결 — layer 가 우선순위. ### Container queries (위 별 문서) ```css .container { container-type: inline-size; } @container (min-width: 400px) { ... } ``` ### Aspect ratio ```css .video { aspect-ratio: 16 / 9; width: 100%; } .avatar { aspect-ratio: 1; height: 50px; } ``` ### clamp / min / max ```css .responsive-font { font-size: clamp(1rem, 2vw, 2rem); /* min 1rem, max 2rem, 2vw 사이 */ } .container { width: min(90%, 1200px); } ``` ### CSS variables + dynamic ```css .button { --hue: 220; background: oklch(60% 0.2 var(--hue)); } .button.warning { --hue: 30; } .button.danger { --hue: 0; } ``` ### Scrollbar gutter ```css html { scrollbar-gutter: stable; } ``` → Scrollbar 가 layout 안 흔들림. ### text-wrap: balance / pretty ```css h1 { text-wrap: balance; } /* 균등 line break */ p { text-wrap: pretty; } /* 마지막 줄 홀로 안 됨 */ ``` ### accent-color ```css :root { accent-color: oklch(60% 0.2 250); } /* Form element (checkbox, radio) 자동 brand */ ``` ### color-scheme ```css :root { color-scheme: light dark; } ``` → Browser 가 system 따라 자동 dark mode (form element, scrollbar). ### Container query units (위 문서) ```css .text { font-size: 5cqi; } ``` ### print stylesheet ```css @media print { .no-print { display: none; } body { font-size: 12pt; } a::after { content: " (" attr(href) ")"; } /* URL 표시 */ .page-break { page-break-after: always; } } ``` ### Browser support 검사 ``` caniuse.com mdn.dev/learn 새 기능 = polyfill / fallback 디자인. ``` ```css @supports (color: oklch(60% 0.2 250)) { .button { background: oklch(...); } } @supports not (color: oklch(60% 0.2 250)) { .button { background: hsl(...); } /* fallback */ } ``` ### Tailwind 4 ``` - OKLCH default - Container query @container - :has() variants - @scope - 모든 modern feature 친화 ``` ## 🤔 의사결정 기준 | 기능 | 사용 | |---|---| | Parent selector | :has() | | Nested grid align | Subgrid | | 색 계산 | OKLCH + color-mix | | Component scope | @scope | | Tooltip / popover | Anchor + Popover API | | CSS-in-JS 대안 | @scope + cascade layers | ## ❌ 안티패턴 - **JS 가 모든 거 — CSS 가능한데**: :has + container 가 더 빠름. - **CSS-in-JS 무 reason**: @scope 가 native. - **HSL 만 + brand 변형**: OKLCH 가 perceptual. - **!important 남발**: cascade layers. - **Browser support 무 fallback**: @supports. - **Tooltip JS positioning + 옛 ancho-positioning 가능**: native. ## 🤖 LLM 활용 힌트 - :has() / Subgrid / Container query / @scope = 새 standards. - OKLCH > HSL. - Native popover + anchor = JS 줄임. - Tailwind 4 가 modern features 친화. ## 🔗 관련 문서 - [[Frontend_Container_Queries]] - [[Frontend_Tailwind_Architecture]] - [[Frontend_Animation_Motion]]