CSS가 요즘 미쳤다 — 예전엔 JS로 하던 걸 이제 CSS로
몇 년 손 놓은 사이 CSS가 딴 세상이 됐다. :has()·container query·color-mix·@layer… 예전엔 JavaScript나 전처리기를 동원하던 걸 이제 순수 CSS가 해낸다. 디자인 시스템을 만들며 실제로 쓴 것들만 골라 소개한다.
퍼블리셔로서 자신 있던 게 CSS였는데, 개발 공부하며 다시 들여다보니 딴 세상이 돼 있었어요.
예전엔 JavaScript나 SCSS를 동원해야 했던 걸 이제 순수 CSS가 해내더라고요.
nacre 디자인 시스템을 빌드 도구 없이 플레인 CSS로 만들 수 있었던 것도 이 변화 덕이에요.
실제로 쓴 것만 골라볼게요.
먼저 :has(). CSS의 오랜 숙원, 부모 선택자예요.
”자식 상태에 따라 부모 스타일을 바꾸고 싶다”는 늘 JS의 몫이었는데, 이제 돼요.
/* 체크된 체크박스를 품은 카드만 강조 */
.card:has(input:checked) { border-color: var(--accent); }
/* 이미지가 있는 아티클과 없는 아티클의 레이아웃을 다르게 */
article:has(img) { grid-template-columns: 1fr 2fr; }
“~을 가진(has)” 요소를 고른다.
이 한 줄이 얼마나 많은 classList.toggle을 없앴는지 몰라요.
컨테이너 쿼리도 있어요.
미디어 쿼리는 늘 화면 전체 폭만 봤어요.
그래서 같은 카드 컴포넌트라도 사이드바에 있을 때와 본문에 있을 때를 구분 못 했죠.
컨테이너 쿼리는 컴포넌트가 놓인 부모의 폭을 기준으로 반응해요.
.card-list { container-type: inline-size; }
@container (min-width: 400px) {
.card { grid-template-columns: auto 1fr; }
}
이 컴포넌트는 자기가 놓인 공간에 맞춰 알아서 변한다.
진짜 재사용 가능한 컴포넌트에 딱 맞는 사고예요.
color-mix()는 색을 계산으로 파생시켜요.
예전엔 hover·active 색을 포토샵에서 하나하나 찍어 hex로 박았는데, 이제 씨앗 색 하나에서 뽑아요.
--brand: #3f6b58;
--brand-hover: color-mix(in oklab, var(--brand), #000 14%);
--brand-subtle: color-mix(in oklab, var(--brand) 16%, white);
oklab 공간에서 섞으면 밝기가 눈에 고르게 움직여요.
nacre의 강조색 스케일 전체가 이 방식이라, 씨앗 색 한 줄만 바꾸면 나머지가 따라오고요.
(자개 빛 인터랙션도 이걸로 요소 자기 색에서 빛을 파생시켰어요.)
@layer는 특정도 전쟁을 끝내줘요.
디자인 시스템을 배포할 때 제일 무서운 게 소비하는 앱의 CSS와 특정도 싸움이 나는 거였는데, @layer로 규칙을 감싸면 레이어에 든 규칙은 레이어 없는 규칙에 특정도와 무관하게 순서로 져요.
!important 지옥이 사라지는 거죠.
@layer nacre, nacre-accent;
@layer nacre { /* 시스템 규칙 전부 여기 — 소비자가 항상 이긴다 */ }
여기까지가 nacre를 만들며 실제로 쓴 넷인데, 넷 다 이미 주요 브라우저에 널리 깔려 있어 안심하고 써요.
이 외에도 요즘 자주 보는 게 많아요.
aspect-ratio는 이미지 자리를 미리 확보해서 레이아웃 밀림(CLS)을 예방하고 — 퍼블리셔의 오랜 습관이 이제 한 줄이죠.
text-wrap: balance / pretty는 제목 줄바꿈을 예쁘게 잡아줘서 한글에서 특히 체감돼요.
:user-invalid는 사용자가 건드린 뒤에만 검증 스타일을 걸어 성급한 빨간 테두리를 막고, field-sizing: content는 textarea가 내용에 맞춰 자동으로 늘어나서 JS 높이 계산과 작별하게 해줘요.
그래서 요즘은 “이거 JS로 해야겠다” 싶은 순간에 CSS부터 의심하게 됐어요.
부모 선택, 컴포넌트 단위 반응형, 색 파생, 레이어 격리 — 다 CSS 안으로 들어왔거든요.
퍼블리셔에겐 반가운 소식이죠.
우리가 제일 잘 아는 언어의 힘이 세지고 있다는 뜻이니까.
댓글