
한동안 웹사이트를 만들어 왔다면, CSS에 대해 어느 정도 확고한 의견이 있을 겁니다. 디자인과 레이아웃에는 당연한 선택이지만, 기본 애니메이션을 넘어 더 인터랙티브한 기능이 필요해지면 대부분의 개발자는 본능적으로 자바스크립트에 손을 뻗습니다. 하지만 끊임없이 발전하는 플랫폼 덕분에 웹 기능을 구현할 때 "CSS는 디자인, 자바스크립트는 인터랙션"이 더 이상 기본값일 필요가 없어졌습니다.
모던 CSS는 이제 커스텀 스크립트가 필요했던 복잡한 애니메이션과 사용자 인터렉션을 처리할 만큼 강력합니다. 이 글에서는 CSS에 새로 도입되는 최신 기능들을 살펴보고, 자바스크립트로 익숙하게 구현하던 수준의 인터랙티비티를 유지하면서도 개발 워크플로를 어떻게 단순화할 수 있는지 알아보겠습니다.
자바스크립트를 한 줄도 작성하지 않고 완전히 커스터마이징 가능한 <select> 요소를 만들거나, scrollLeft를 계산하거나 여러 이벤트 리스너를 연결하지 않고도 인터랙티브 마커가 달린 스크롤 가능한 캐러셀을 만드는 세상을 상상해 보세요. 바로 이런 것들이 새로운 CSS 기능으로 가능해지고 있으며, 분명 기대할 만한 일입니다.
2026년 CSS의 새로운 기능
이러한 최신 기능들과 코드베이스에서 어떻게 구현할 수 있는지 살펴보겠습니다.
참고. 이 기능들은 대부분 매우 새롭고 아직 브라우저에 배포되는 중이므로, 프로덕션에서 사용하기에는 아직 이릅니다. 이 기능들이 어떻게 동작하는지 더 깊이 알고 싶다면 Chrome DevRel 팀의 CSS Wrapped 2025 글을 확인해 보세요.
| 기능 | 하는 일 |
|---|---|
appearance: base-select |
<select>를 새로운 커스터마이징 모드로 전환하여, 네이티브 동작을 잃지 않으면서 스타일을 적용하고 피커를 꾸밀 수 있게 합니다. |
select::picker(select) |
커스터마이징 가능한 <select>의 드롭다운 표면을 나타내는 의사 요소(pseudo-element)로, 그림자, 테두리, 간격 등을 스타일링할 수 있습니다. |
selectedcontent |
select 필드에 표시되는 선택된 옵션의 스타일을 지정합니다. |
::scroll-button() |
스크롤 가능한 컨테이너에 생성되는 버튼으로, 클릭하면 좌우로 스크롤합니다. |
::scroll-marker |
각 스크롤 항목과 쌍을 이루는 생성 요소로, 브라우저가 페이지네이션 점이나 시각적 인디케이터로 사용할 수 있습니다. |
::scroll-marker-group |
생성된 스크롤 마커들의 컨테이너로, 스타일링하거나 배치(예: 하단 중앙)할 수 있습니다. |
scroll-target-group |
링크 컨테이너에 적용할 수 있는 속성으로, CSS가 현재 뷰에 있는 타깃과 일치하는 링크를 매칭(:target-current)할 수 있게 합니다. |
:target-current |
타깃(ID 앵커)이 현재 스크롤 활성 요소인 링크(또는 다른 타깃 가능 요소)와 매칭하는 선택자입니다. |
container-type: scroll-state |
요소에 스크롤 상태 쿼리를 활성화하여, 스크롤 컨테이너가 특정 스냅 또는 고정 상태인지 CSS가 반응할 수 있게 합니다. |
@container scroll-state(snapped: x) |
컨테이너가 x축에서 "스냅된" 스크롤 위치일 때 스타일을 적용하는 컨테이너 쿼리입니다. |
sibling-index() |
형제 요소 중 1부터 시작하는 위치를 반환하며, 동적 딜레이와 레이아웃 규칙에 유용합니다. |
sibling-count() |
형제 요소의 총 개수를 반환하며, 개수 기반 레이아웃이나 비례 스타일링에 유용합니다. |
attr() |
속성을 색상으로 읽어 background-color 같은 프로퍼티에 사용할 수 있는 타입 지정 attr() 함수 호출입니다. |
@starting-style |
트랜지션이나 애니메이션 시퀀스의 시작 시점에 스타일을 정의할 때 사용하는 컨테이너 쿼리 유사 블록입니다(실험적 구문). |
이제 이 새로운 기능들의 실제 사용 사례를 살펴보겠습니다.
데모: 네이티브 HTML select 커스터마이징
솔직히 몇 년간 기다려 온 기능이니, 실제로 어떻게 동작하는지 살펴보겠습니다. <select> 요소는 접근 가능한 드롭다운을 위한 브라우저 내장 솔루션이지만, 스타일링에는 항상 제약이 있었습니다. 패딩을 조정하거나 색상을 바꾸는 것 이상의 작업을 하려면 보통 추가 마크업, 자바스크립트 핸들러, 그리고 네이티브 동작을 모방하기 위한 온갖 복잡함을 동원해 완전히 커스텀 드롭다운을 만들어야 했습니다.
커스터마이징 가능한 select를 사용하면 두 세계의 장점을 결합할 수 있습니다. 실제 <select>의 네이티브 접근성과 시맨틱을 유지하면서, 이전에는 자바스크립트 기반 컴포넌트에서만 가능했던 수준의 스타일링 유연성을 갖출 수 있습니다.
아래 데모에서는 세 가지 최신 CSS 기능을 사용하여 포켓몬 선택기를 만들겠습니다.
- 시맨틱과 접근성을 위해 네이티브
<select>를 사용 - 각 옵션에 아이콘과 배경색을 표시
- 옵션이 엇갈린 타이밍으로 슬라이드하며 나타나는 애니메이션 적용

참고. 이 기능들은 Chrome 135 이상이 필요합니다.
이 모든 것은 하나의 <select> 요소와 몇 개의 data-* 속성으로 이루어집니다. 인터랙티비티는 다음 기능들에서 나옵니다. appearance: base-select(및 select 피커), 트리 카운팅 함수, 그리고 타입 지정 attr().
appearance: base-select과 select 피커
첫 번째 단계는 컨트롤을 커스터마이징 모드로 전환하는 것입니다.
select,
select::picker(select) {
appearance: base-select;
}
appearance: base-select는 <select>를 새로운 커스터마이징 렌더링 모델로 전환하며, 점진적 향상(progressive enhancement) 접근법으로도 훌륭합니다. 지원하지 않는 브라우저는 단순히 프로퍼티를 무시하고 select를 정상적으로 렌더링합니다.
전환이 완료되면 ::picker(select) 의사 요소가 드롭다운 표면 자체를 나타내므로, 다른 UI 패널처럼 스타일을 적용할 수 있습니다.
select::picker(select) {
margin-block-end: 1em;
border-radius: 12px;
border: 1px solid #e0e0e0;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
}
커스터마이징 가능한 select를 사용하면 브라우저가 드롭다운의 많은 복잡한 부분을 대신 처리해 줍니다.
- 자동 오버플로 처리. 드롭다운이 가용 공간보다 크면 브라우저가 오버플로를 처리합니다. 피커 높이를 제한하고 필요할 때 스크롤 가능하게 만들어 주므로, 화면 밖으로 넘치거나 높이를 수동으로 계산할 필요가 없습니다.
- 앵커 포지셔닝 폴백. 피커는 새로운 앵커 포지셔닝 구문을 사용하여 트리거 요소에 고정되므로, 가용 뷰포트 공간을 기반으로 최적의 배치를 자동으로 선택할 수 있습니다.


- 내장 포커스 관리. 포커스 동작이 네이티브로 처리되므로, select가 열리면 포커스가 예측 가능하게 피커로 이동하고, 닫히면 포커스가 적절히 돌아옵니다. 직접 포커스 트래핑이나 "트리거로 포커스 반환" 로직을 구현할 필요가 없습니다.
- 완전한 키보드 내비게이션(화살표 키, Enter, Escape). 사용자가
Arrow키로 옵션을 탐색하고,Enter로 선택을 확정하고,Escape로 피커를 닫을 수 있습니다. 일반<select>와 동일합니다. - 더 풍부한 옵션 콘텐츠 지원. 각
<option>안에 아이콘, 추가 레이블, 구조화된 콘텐츠 등 일반 텍스트 이상을 포함할 수 있습니다.
이런 것들은 커스텀 드롭다운을 만들 때 보통 직접 스크립트로 작성해야 했지만, 여기서는 플랫폼에서 바로 제공됩니다.
또 하나의 큰 장점은 내장된 점진적 향상 모델입니다. 브라우저가 아직 커스터마이징 가능한 select를 지원하지 않으면 사용자는 일반 네이티브 <select> 요소를 받게 됩니다. 아무것도 깨지지 않습니다. 폴리필도 필요 없고, 컴포넌트의 두 가지 버전을 유지할 필요도 없습니다.
sibling-index()로 엇갈린 애니메이션 만들기
다음으로 애니메이션을 추가합니다. 드롭다운이 열리면 각 옵션이 약간의 딜레이를 두고 옆에서 슬라이드합니다. 모든 옵션에 수동으로 인덱스를 지정하는 대신, 트리 카운팅 함수를 사용할 수 있습니다.
option {
transition: opacity 0.25s ease, translate 0.5s ease;
transition-delay: calc(0.2s * (sibling-index() - 1));
@starting-style {
opacity: 0;
translate: 30px 0;
}
}
sibling-index()는 형제 요소 중 1부터 시작하는 위치를 제공합니다. 따라서 첫 번째 보이는 옵션은 0.2s * (1 - 1), 즉 0s의 딜레이를 갖습니다. 다음은 0.2s, 그 다음은 0.4s, 이런 식으로 이어집니다.
나중에 옵션을 추가하거나 제거해도 타이밍이 마크업에 하드코딩된 것이 아니라 동적으로 계산되므로 애니메이션이 여전히 올바르게 보입니다.
트리 카운팅 함수가 없던 시절에는 CSS에서 같은 엇갈린 효과를 내려면 훨씬 번거로웠습니다. :nth-child() 선택자의 긴 목록으로 딜레이를 하드코딩하거나, HTML의 모든 항목에 --index 커스텀 프로퍼티를 수동으로 추가해야 했습니다. 두 방법 모두 동작하긴 했지만 금세 지저분해졌고, 리스트가 바뀔 때 업데이트하는 것을 잊어버리기 쉬웠습니다.
데이터 기반 스타일링을 위한 고급 attr()
마지막으로 이 데모는 시각적 디테일을 data-* 속성에 보관하기 위해 타입 지정 attr() 함수를 사용합니다.
attr() 함수는 꽤 오래전부터 기본적으로 사용 가능했습니다. 하지만 최근까지는 content 프로퍼티에서만 안정적으로 사용할 수 있었습니다.
최신 타입 지정 버전의 attr()을 사용하면, 브라우저에 어떤 타입을 기대하는지 알려주기만 하면 CSS의 더 많은 곳에서 속성 값을 사용할 수 있습니다.
이 데모에서 각 옵션은 호버 배경색을 정의하는 data-bg-color 속성을 포함하며, CSS에서 직접 그 값을 읽습니다.
// HTML
<option data-bg-color="#F8C9A0" value="charmander">
// CSS
option {
background-color: attr(data-bg-color color, transparent);
}
속성을 명시적으로 색상으로 취급하기 때문에 브라우저가 올바르게 파싱하며, 속성이 없을 때를 위한 폴백 값도 안전하게 제공할 수 있습니다. 결과적으로 더 데이터 기반 스타일링 접근법이 됩니다. CSS를 건드리지 않고 HTML에서 테마 색상을 조정할 수 있습니다.
appearance: base-select, select 피커, 트리 카운팅 함수, 타입 지정 attr()을 조합하면 근본적으로 여전히 실제 <select> 요소인 기능이 풍부한 애니메이션 드롭다운을 만들 수 있습니다. 원하는 대로 커스터마이징하면서도 네이티브 동작과 내장 접근성 기능을 유지할 수 있습니다.
비교를 위해, 자바스크립트로 비슷한 드롭다운을 만들면 어떤 모습인지 보겠습니다(스포일러. CSS로 만든 것과 비슷한 수준을 달성하는 데 대략 150줄 이상의 자바스크립트가 필요합니다).
CSS in 2026: 앞으로의 전망
저에게 이 데모는 CSS가 향하는 방향에서 가장 흥미로운 부분을 보여줍니다. 150줄 이상의 자바스크립트를 단 몇 가지 CSS 기능으로 대체하는 것은 정말 놀랍습니다. 예전과 같은 수준의 복잡함을 달성할 수 있지만, 이제 훨씬 적은 노력으로 가능합니다.
플랫폼이 키보드 내비게이션, 포커스 처리, 합리적인 포지셔닝 동작 같은 기본값을 제공하면, 모든 코드베이스에서 같은 인터렉션 패턴을 재구축하거나 매번 새 라이브러리를 설치하는 대신, 기존 컴포넌트를 개선하는 데 더 많은 시간을 쓸 수 있습니다.
AI 시대에 특히 적절하게 느껴지기도 합니다. 이런 기능들이 단순하고 선언적일수록, AI 에이전트가 솔루션을 과도하게 엔지니어링하거나 요청하지 않은 동작을 만들어낼 가능성이 줄어듭니다.
이런 기능들이 도입될 때 바로 활용하고 싶다면, 다음을 추천합니다.
- 자바스크립트가 무거운 UI 컴포넌트 하나를 재검토하세요. 이 새로운 기능들을 사용하기 시작하는 가장 좋은 방법은 코드베이스에서 이미 구현된 기능에 어디서 활용할 수 있는지 찾아보는 것입니다. 캐러셀, 툴팁, 드롭다운이 좋은 후보입니다. 비교적 작은 UI에 많은 코드가 들어가는 경우가 많고, 이를 만드는 데 필요한 네이티브 기능 대부분이 이미 기본 지원되기 때문입니다.
- 접근성을 빠뜨리지 마세요. 네이티브 지원이 보통 더 나은 출발점을 제공하지만, 테스트를 대체하지는 않습니다. 키보드로 데모를 시도해 보고, 가능하면 스크린 리더를 사용하여 모든 사람이 이 기능들을 사용할 수 있는지 확인하세요.
- 호기심을 유지하세요. 이런 새 기능들은 완전히 기본 지원될 때까지는 안 되는 법입니다. 최신 상태를 유지하는 가장 쉬운 방법은 이 기능들의 최신 변경 사항을 주시하는 것입니다(web.dev 블로그를 추천합니다). 그래야 프로덕션에 드디어 도입할 수 있는 시점을 알 수 있습니다. 브라우저 지원을 지켜보고, 내부 도구에서 실험하고, 지원이 안정화될 때까지 프로덕션 배포는 보수적으로 유지하세요.
그리고 개인적으로, CSS가 모든 무거운 작업을 해주는 덕분에 코드를 덜 쓸 수 있다면, 전적으로 찬성입니다.
'Web Frontend Developer' 카테고리의 다른 글
| [번역] 이제 모던 CSS가 SPA를 끝낼 때입니다 (0) | 2026.03.27 |
|---|---|
| [번역] 디자인 엔지니어란 무엇인가? (0) | 2026.03.11 |
| [번역] 토스트 컴포넌트 만들기 (0) | 2026.02.11 |
| 프론트엔드 테스트는 꼭 필요할까? (1) | 2026.01.02 |
| [번역] package.json을 관리하는 방법 (1) | 2025.12.10 |