FEInterview Prep

Velog

Tailwind CSS에서 자식 요소 타겟팅하기

CMS HTML 처럼 클래스를 붙일 수 없는 자식 요소 를 Tailwind 로 스타일하는 법. [&_a]:..., [&>div]:... 임의 변형(arbitrary variant) 문법의 원리와 한계.

2025-12-22·5분 읽기
CSS빌드/도구
원문 보기 ↗

핵심 요약

세 가지 패턴을 기억하면 대부분의 케이스를 커버한다.

패턴문법CSS 결과
직접 자식[&>div]:p-4.class > div { padding: 1rem }
후손[&_a]:underline.class a { text-decoration: underline }
자식 + 가상 상태[&>button:hover]:bg-blue-600.class > button:hover { background: ... }

핵심 규칙 두 가지:

  • & = 현재 생성되는 클래스 선택자
  • 공백은 언더스코어(_) 로 작성 (Tailwind 파서 제약)
// CMS 콘텐츠 전용 래퍼 컴포넌트
<article
  className="p-4
    [&_a]:font-semibold [&_a:hover]:underline
    [&_img]:rounded-lg [&_img]:max-w-full
    [&_li]:list-disc [&_li]:ml-6"
>
  {cmsHtml}
</article>

Tailwind 의 철학은 '모든 요소에 직접 유틸리티 클래스'. 그러나 CMS / 3rd-party / 동적 HTML 은 이 전제가 깨진다. 임의 변형 [&...]SCSS/CSS nesting 의 & 와 동일 의미 로, 현재 요소의 생성된 클래스 셀렉터가 그 자리에 치환된다. 자식/후손/가상 상태 모두 표현 가능하다.

이 문법을 모르면 CMS 콘텐츠를 스타일할 때 @tailwindcss/typography (prose) 에 매달리거나 전용 CSS 파일을 따로 만들어야 한다. 문제는 전용 CSS 가 Tailwind JIT 와 퍼지(purge) 규칙 밖 이라는 점 — 번들 크기 예측이 깨진다. [&_a]:underline 은 그대로 JIT 스캔 대상이라 사용한 것만 최종 CSS 로 남는다.

학습 포인트

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

`&` 의 의미는 SCSS 와 똑같다 — 치환이 생성된 클래스 이름

<div class="[&_a]:font-semibold"> 이 만드는 CSS 는:

.\[\&_a\]\:font-semibold a {
  font-weight: 600;
}

& 자리에 이스케이프된 클래스 이름 이 들어가고, 그 뒤에 a 후손 셀렉터가 이어진다. SCSS 의 .parent { & a { ... } } 과 같은 논리.

arbitrary variant&descendant selector
자주 하는 오해

[&.foo] 처럼 같은 요소의 추가 클래스를 노리는 것. 가능은 하지만 복수 클래스 조합은 가독성이 급격히 떨어진다 — 이 경우는 그냥 별도 유틸 클래스로 분리하는 게 낫다.

공백은 `_`, 진짜 `_` 는 `\_` — Tailwind 파서의 현실 제약

클래스 이름에 공백이 올 수 없어 CSS 결합자(combinator) 간 공백을 _ 로 쓴다.

<!-- 후손 a 요소 -->
<div class="[&_a]:underline">...</div>

<!-- 직접 자식 div -->
<div class="[&>div]:p-4">...</div>

<!-- 속성 셀렉터 값에 _ 가 들어가야 하면 이스케이프 -->
<div class="[&[data-state=\_active]]:bg-blue-500">...</div>
underscorecombinatorarbitrary value
자주 하는 오해

[& a] 처럼 실제 공백을 쓰는 것. JIT 스캔에서 클래스가 인식되지 않아 CSS 가 생성되지 않는다.

이 문법이 정답이 아닐 때가 많다

저자도 반복해서 말한다 — 대부분의 경우 전용 .cms-content a { ... } 스타일시트가 더 낫다.

상황권장 접근
규칙 1~2개, 컴포넌트와 같은 위치 유지임의 변형
규칙 10개+, 유지보수가 중심전용 CSS 또는 @tailwindcss/typography
prose 로 커버되는 일반 글className="prose"
CMS 마크업 + 커스텀 디자인prose 확장 또는 전용 CSS

'테일윈드를 쓰니까 모든 걸 테일윈드로' 가 아니다.

@tailwindcss/typographyprose
자주 하는 오해

컨테이너에 임의 변형을 20개 이상 붙이는 것. 코드 리뷰어가 읽을 수 없어 PR 이 막힌다.

읽는 순서

  1. 1이론

    Tailwind 공식 Handling arbitrary variants 문서에서 &, _, >, ~, + 결합자 표기를 정리.

  2. 2구현

    Tailwind Play 에서 [&_a]:underline [&_a:hover]:text-blue-500 을 적용한 div 에 <a> 를 넣어 JIT 결과 CSS 를 확인.

  3. 3실무

    현재 프로젝트에서 dangerouslySetInnerHTML 이나 Markdown 렌더러 사용처를 찾아, 임의 변형으로 커버 가능한지 / prose 로 충분한지 / 전용 CSS 가 나은지 판단.

  4. 4설명

    'CMS HTML 스타일 3가지 방법' 을 정리해 팀에 공유. 각각이 맞는 상황을 한 줄씩 예시로.

면접 연결 질문

medium서버에서 받아온 CMS HTML 을 Tailwind 프로젝트에서 스타일해야 한다. 선택지와 각 선택의 트레이드오프는?
힌트

[감점 답변] 'prose 쓰면 된다' 만. [좋은 답변] 세 가지 옵션을 비교: (1) @tailwindcss/typographyprose — 기본 스타일 좋지만 디자인 커스터마이징 복잡, (2) [&_a]:... 임의 변형 — 컴포넌트와 스타일이 같은 위치, 하지만 규칙이 많으면 불가독, (3) 전용 .cms-content CSS 파일 — 가장 가독성 높음, 단 번들 퍼지 대상 외. 규칙 수와 디자인 복잡도로 결정.

easy`[&_a]:underline` 과 `[&>a]:underline` 의 차이는?
힌트

[감점 답변] '비슷하다'. [좋은 답변] _ = 모든 후손(descendant), > = 직접 자식. CMS 콘텐츠처럼 <p><a>...</a></p> 구조에서는 전자만 매칭된다. CSS 의 ' ' vs ' > ' 결합자 차이와 정확히 같다.

자기 점검

임의 변형 `[&...]` 에서 `&` 가 치환되는 값은 정확히 무엇인가?
현재 요소생성된 클래스 선택자이스케이프
자주 하는 오해

& 가 HTML 의 부모 요소라고 오해. 실제로는 이 클래스가 만들어내는 CSS 셀렉터 자신.