FEInterview Prep

Velog

2026년 프런트엔드 개발자라면 알아야 할 4가지 CSS 기능

sibling-index(), text-box, attr() 타입 인자, scroll-state() 컨테이너 쿼리 네 가지로 JS 가 하던 일이 CSS 로 내려온다. 핵심은 '어떤 JS 가 사라지는가'.

2026-02-10·5분 읽기
CSS
원문 보기 ↗

핵심 요약

Chrome/Safari 최신 버전이 네 개의 CSS 기능을 안정화했다. (1) sibling-index() / sibling-count() 함수: :nth-child 와 달리 계산식 안에서 인덱스를 값으로 쓸 수 있어 스태거드 애니메이션을 CSS 만으로 만든다. (2) text-box 계열: 폰트의 em-box 상하 공백을 잘라 실제 글자 높이 를 기준으로 정렬, 디자인 시스템의 'vertical rhythm' 을 JS 없이 정확히 맞춘다. (3) attr() 타입 확장: 이제 attr(data-progress type(<number>), 0) 로 HTML 속성을 숫자/길이/색상 타입으로 CSS 에 주입 가능. (4) scroll-state() 컨테이너 쿼리: container-type: scroll-state 와 함께 @container scroll-state(stuck: top) 으로 sticky 고정 여부를 스타일 조건으로 쓸 수 있다. 네 기능 모두 DOM 접근 없이 상태를 CSS 에 노출 하는 방향이다.

최신 CSS 기능을 '새 문법' 이 아니라 'JS 로 하던 일을 CSS 엔진이 가져가는 이관' 으로 본다. 각 기능이 제거하는 JS 코드 조각을 한 줄 예시로 떠올려야 실제 쓸모가 체감된다.

'신문법 왜 씀?' 질문에 '예뻐서' 라고 답하면 감점. 네 기능의 실용 가치는 각각 다음 JS 를 지우는 데 있다.

  • sibling-index() → DOM 순회로 :nth-child 인덱스 계산
  • text-box / text-box-trim → 폰트 상/하 여백 수동 마진 조정
  • attr(data-x type(<number>)) → dataset 을 읽어 style.setProperty
  • scroll-state()IntersectionObserver + 상태 플래그

학습 포인트

면접 답변으로 연결할 학습 포인트입니다.

sibling-index() — 스태거를 CSS 로

:nth-child(n) 는 선택자일 뿐 값이 아니었다. sibling-index() 이라 calc() 안에서 쓸 수 있다.

li {
  /* 각 항목이 50ms 씩 지연되어 등장 */
  animation-delay: calc(sibling-index() * 50ms);
}

같은 효과를 과거엔 li:nth-child(1) { delay: 50ms } li:nth-child(2) { delay: 100ms } ... 로 20줄 쓰거나, JS 로 style.setProperty('--i', i) 를 뿌렸다.

sibling-indexsibling-countstagger animationcalc
자주 하는 오해

:nth-child(n)n 을 수식에서 참조할 수 있다고 오해하는 것. 그건 선택자 매칭용 변수일 뿐 계산 값이 아니다.

text-box — 폰트 여백의 제거

대부분의 폰트는 글자 실제 높이보다 상/하 여백(leading) 이 크다. 아이콘과 수직 정렬하면 항상 어긋나는 원인. text-box-edge / text-box-trim 이 이 여백을 잘라낸다.

.label {
  text-box: trim-both cap alphabetic;
  /* cap(대문자 위) 에서 alphabetic(기준선) 까지만 상자 */
}

결과: 디자이너가 Figma 에서 잡은 픽셀 단위 수직 정렬 이 그대로 재현된다. 과거엔 margin-top: -4px 같은 매직 넘버로 맞추던 문제.

text-boxtext-box-trimleadingcap-height
자주 하는 오해

line-height: 1 로 해결됐다고 여기는 것. 실제로는 폰트마다 em-box 비율이 달라 수치 기준 정렬 을 보장하지 못한다.

attr() 타입 확장 — 데이터 브리지

오래된 attr() 은 문자열만 반환해 content: 밖에서 쓸 수 없었다. 이제 타입 인자를 받아 숫자/길이/퍼센트/색상 을 반환한다.

<div class="progress" data-progress="42"></div>
.progress {
  /* 과거: JS 로 element.style.setProperty('--p', 42) */
  --p: attr(data-progress type(<number>), 0);
  width: calc(var(--p) * 1%);
}

서버 렌더 시점에 HTML 에 값이 박혀 있으면, JS 없이 CSS 가 읽어 쓴다.

attr() typeCSS custom propertydata attributeserver-rendered
자주 하는 오해

content: attr(...) 외에는 안 된다고 믿는 것. 최신 스펙에서 type(<length>) 등을 지정하면 어디서든 사용 가능.

읽는 순서

  1. 1이론

    MDN 에서 sibling-index, text-box, attr()type() 문법, scroll-state() 컨테이너 쿼리를 각각 한 문장으로 요약하세요.

  2. 2구현

    메뉴 리스트의 스태거 애니메이션을 기존 JS 구현에서 sibling-index() + calc() 로 교체하고 코드 라인 수 비교.

  3. 3실무

    디자인 시스템의 Typography 컴포넌트에 text-box-trim 을 적용해 토큰 기반 수직 리듬 을 맞춘 뒤 스크린샷 diff 로 검증.

  4. 4설명

    팀에 '2026 CSS 4종 = JS 얼마나 사라졌나' 데모를 만들고, 브라우저 지원표와 @supports fallback 패턴을 정리해 공유.

면접 연결 질문

medium`:nth-child(n)` 와 `sibling-index()` 의 차이를 설명하고, 언제 각각을 선택하시겠어요?
힌트

[좋은 답변] :nth-child선택자 매칭 이고, sibling-index()계산에 쓰는 값. 스태거 delay, grid-row 계산, per-item custom property 주입처럼 인덱스를 숫자로 써야 할 때 후자를 쓴다.

medium디자인 팀이 '버튼 라벨이 아이콘보다 2px 위에 있다' 고 할 때, `margin` 대신 `text-box` 로 해결하는 이유를 말해보세요.
힌트

[좋은 답변] margin매직 넘버 라 폰트 바뀌면 다시 틀어짐. text-box-trim: trim-both폰트 메트릭 기반이라 굵기/패밀리가 바뀌어도 그대로. 디자인 토큰 단위로 관리하려면 후자가 정답.

hard`attr() type()` 이 **안정 지원** 되기 전까지 같은 효과를 낼 대안을 두 가지 말해보세요.
힌트

[좋은 답변] (1) 서버 템플릿에서 style="--p: 42" 를 직접 렌더. (2) 클라이언트 마운트 후 element.style.setProperty('--p', dataset.progress). 각각 SSR/Hydration 비용이 다름.

자기 점검

네 기능을 **각각 어떤 JS 코드를 제거하는가** 한 줄씩 설명해보세요.
sibling-indextext-boxattr() typescroll-state
자주 하는 오해

'그냥 CSS 가 풍부해졌다' 식 추상 답.

`sibling-index()` 가 Safari 16 에서 동작하지 않을 때 **점진적 개선(progressive enhancement)** 전략을 설명해보세요.
@supportsfallbackcustom propertyJS fallback
자주 하는 오해

기능을 쓰려면 브라우저 일괄 업그레이드가 필요하다는 오해. @supports분기 처리 가 정답.