Pure CSS는 위젯 런타임 없이 그리드, 양식, 버튼, 메뉴 및 표를 구성하는 모듈형 스타일시트입니다. 이 가이드에서는 선택적으로 사용하는 반응형 그리드 모듈과 기본 제공 시맨틱 요소를 필터링 가능한 장비 카탈로그에 적용하고, 정렬 및 선택 기능은 명시적으로 구현하는 방법을 보여줍니다.
공식 Pure CSS 3.1.0 및 반응형 그리드 모듈, 순수 JavaScript로 직접 구현. · 구현 레퍼런스
02
Pure CSS 디자인 시스템 디자인 참고 자료
Pure CSS 3.1.0 컴파일 패키지 모듈. 이는 실제 선택자 값이며, 이름이 지정된 디자인 토큰 API은 아닙니다. Pure는 Chakra나 Pico처럼 의미 기반 CSS 변수 테마를 제공하지 않습니다. 애플리케이션에서 타이포그래피, 레이아웃 간격, 더 뚜렷한 포커스 윤곽선을 추가합니다.
Pure는 기본 정규화, 그리드, 버튼, 폼, 메뉴, 표를 제공합니다. 이 카탈로그는 패키지의 컴파일된 롤업과 별도의 반응형 그리드 파일을 사용합니다. JavaScript 프레임워크, 프로바이더 또는 위젯 런타임은 가져오지 않습니다. 필터링, 정렬, 선택 기능은 위에 전체 코드가 표시된 애플리케이션 코드로 구현합니다.
Pure를 완전한 컴포넌트 플랫폼과 비교할 때는 이 차이가 중요합니다. pure-table 클래스는 셀 스타일을 제공할 뿐, 정렬, 페이지 나누기, 가상화 또는 선택 동작의 의미를 제공하지 않습니다. pure-button은 네이티브 버튼에 적용할 수 있는 시각적 클래스입니다. 이 예시는 클래스 이름만으로 동작이 구현될 것으로 기대하지 않고, 의미에 맞는 기본 요소를 그대로 사용합니다.
Pure의 컴파일된 버튼 스타일은 중립적인 #E6E6E6 배경색, 2px 모서리 반경, em 단위 안쪽 여백을 사용합니다. 선택 사항인 기본 버튼은 rgb(0,120,231) 배경에 흰색 텍스트를 사용합니다. 폼 입력 필드에는 4px 모서리 반경과 별도의 안쪽 여백이 적용됩니다. 이 디자인 시스템 참고 자료는 이러한 실제 차이를 보여 주며, 이를 존재하지 않는 공통 모서리 반경 단계로 통일하지 않습니다.
이 카탈로그는 어두운 청회색 텍스트, 중립적인 구분선, 옅은 선택 요약 영역으로 절제된 애플리케이션 팔레트를 구성합니다. 이 색상은 공식 Pure 브랜드 색상이 아닙니다. 이 예시는 완전한 대체 애플리케이션 팔레트를 구현하지 않으므로 다크 모드 전환 기능도 없습니다. 테마를 전환하려면 폼, 표 머리글, 테두리, 텍스트, 포커스 상태를 모두 함께 바꿔야 합니다.
원본 페이지 레이어는 16px 크기의 Arial/Helvetica와 줄 높이 1.5를 사용하고, 제목은 34px, 섹션 제목은 18px로 설정합니다. 좁은 화면에서는 제목이 28px로 바뀝니다. 이는 Pure가 편집용 글자 크기 체계를 규정한다는 뜻이 아니라, 애플리케이션에서 명시적으로 선택한 값입니다. 이 CSS 예시에는 구성을 재현하는 데 필요한 모든 값이 포함되어 있습니다.
Pure 그리드는 인라인 단위의 표시를 처리하기 위해 그리드 컨테이너의 텍스트 렌더링과 자간을 조정합니다. 단위 규칙은 텍스트 표시를 기본 상태로 되돌립니다. 이 카탈로그에서는 사이드바와 결과 영역에서 글꼴이 예기치 않게 바뀌지 않도록 그리드 단위에도 글꼴을 지정합니다. 애플리케이션의 안쪽 여백은 테두리 상자 크기 계산을 적용한 단위 내부에 배치하므로 분수 너비가 유지됩니다.
사이드바에는 pure-u-1과 pure-u-md-1-4를 함께 적용하고, 결과 영역에는 pure-u-1과 pure-u-md-3-4를 함께 적용합니다. 두 영역 모두 처음에는 전체 너비를 차지합니다. md 미디어 경계인 48em부터 각각 너비의 4분의 1과 4분의 3을 차지합니다. 별도의 JavaScript 레이아웃 계산 없이도 필터 영역에 읽기 편한 고정 비율을 적용할 수 있습니다.
기본 pure-min.css 번들에는 반응형 그리드 미디어 쿼리 클래스가 포함되어 있지 않습니다. grids-responsive-min.css를 빠뜨리면 md 수정자가 작동하지 않습니다. 설정에서는 두 파일을 모두 명시적으로 불러옵니다. 모바일 화면에서는 사이드바가 표 앞에 오고 결과 테두리가 제거되어 읽는 흐름이 하나로 이어집니다.
세로로 배치된 폼에는 레이블이 있는 검색 입력란, 카테고리 선택 메뉴, 이용 가능 여부 체크박스가 있습니다. 입력 내용이 바뀔 때마다 세 가지 조건을 모두 적용해 표시할 행을 다시 렌더링합니다. 폼 제출은 막아 두어 검색란에서 Enter를 눌러도 페이지를 벗어나지 않습니다. 필터 지우기는 기본 reset을 호출하고 브라우저가 기본값을 복원한 뒤 다시 렌더링합니다.
선택 항목은 안정적인 키트 ID를 담은 Set에 저장됩니다. 필터로 선택한 항목을 숨겨도 Set에서는 제거되지 않습니다. 따라서 항상 표시되는 검토 목록이 선택 항목을 확인하는 기준이 됩니다. 선택 개수 옆에서 이 동작을 설명하지 않으면, 사용자는 필터링으로 숨겨진 행을 선택 해제로 착각할 수 있습니다.
표에는 caption, thead, tbody와 열 머리글을 지정하는 scope 속성이 사용됩니다. Equipment 머리글에는 이름순 정렬을 반전하는 네이티브 버튼이 있습니다. 부모 th에는 aria-sort="ascending" 또는 "descending"이 설정되어 화면에 표시되는 화살표와 일치합니다. 정렬할 때도 모든 행의 열 구조는 그대로 유지됩니다.
최소 너비 540px를 설정해 Select, Equipment, Category, Availability의 의미가 유지되도록 합니다. 화면이 좁아지면 레이블이 지정된 표 영역만 가로로 스크롤됩니다. 이 영역은 키보드로 포커스할 수 있고 포커스 윤곽선도 표시됩니다. 페이지 전체 너비는 늘어나지 않습니다. 각 행을 시각적으로 무관한 카드로 바꾸는 대신, 데이터 표에 적합한 방식을 의도적으로 적용했습니다.
Pure CSS 디자인 시스템에서 비활성화, 빈 상태, 포커스 상태에 실제 동작을 적용해야 합니다
비활성화, 빈 상태, 포커스 상태에 실제 동작을 적용해야 합니다
대여 중인 항목은 이용 가능 여부를 설명하기 위해 목록에 남겨 두지만 선택할 수는 없습니다. 네이티브 체크박스를 비활성화하기 때문입니다. Set이 비어 있으면 선택 지우기도 비활성화됩니다. Pure의 불투명도 규칙은 비활성화된 모양을 표현하는 데 도움이 되지만, 활성화를 막는 것은 HTML 속성입니다.
필터 결과가 없으면 구체적인 빈 상태 메시지를 표시하고 머리글은 그대로 유지합니다. 결과 개수는 공손한 상태 알림 영역에 표시됩니다. 원본 스타일시트는 기본 Pure 버튼의 포커스 표시가 그라디언트이고 윤곽선이 초기화되어 있으므로, 이를 보완하기 위해 focus-visible에 뚜렷한 윤곽선을 추가합니다. 이 도구에서는 키보드 사용자를 위해 더 명확한 표시가 유용합니다.
[email protected]을 설치하고 pure-min.css와 grids-responsive-min.css를 로컬 assets 디렉터리에 복사한 다음, style.css보다 먼저 순서대로 불러오세요. 전체 본문, 애플리케이션 스크립트, CSS는 위에 제공되어 있습니다. 생성된 파일은 정적 서버에서 제공하면 되며, 카탈로그 자체에는 빌드 런타임이 필요하지 않습니다.
번들 크기를 줄여야 한다면 패키지 모듈을 개별적으로 사용할 수도 있습니다. CSS를 줄일 때는 기본 스타일과 그리드 의존성이 서로 맞도록 유지하세요. 표 스타일시트만 복사한 뒤 폼이나 버튼 클래스에도 스타일이 적용될 것이라고 가정하지 마세요. 현재 예제는 설명 없이 일부만 번들링하는 방식보다 전체 설정을 재현할 수 있도록 구성했습니다.
컴파일된 번들에는 카탈로그의 버튼, 폼, 표 스타일이 포함되고, grids-responsive-min.css는 중단점에 따라 적용되는 분수형 그리드 클래스를 제공합니다. 반응형 파일을 제거해도 오류는 발생하지 않지만 md 클래스의 레이아웃 변경 기능이 사라집니다. 불러오는 모듈을 줄일 때는 화면 폭을 좁혀 열 동작이 적절한지 확인하세요.
그리드 단위에는 인라인 레이아웃에 맞게 그리드 컨테이너가 조정하는 텍스트 동작도 적용됩니다. 단위 요소에 애플리케이션 글꼴을 지정하고, border-box 크기 계산을 적용해 요소 내부에 패딩을 추가하세요. 이후 카탈로그에 페이지네이션이 추가되면 애플리케이션 상태에서 안정적인 ID를 기준으로 선택 상태를 유지하세요. 표의 CSS나 그리드 분수 클래스는 이 동작을 구현하지 않습니다.
원래 동작에서는 고정된 샘플 레코드 6개를 렌더링하고 안정적인 ID로 선택 상태를 유지합니다.
자바스크립트
const data=[{id:'c1',name:'Compact camera kit',kind:'Camera',available:true},{id:'c2',name:'Cinema camera kit',kind:'Camera',available:false},{id:'a1',name:'Field recorder',kind:'Audio',available:true},{id:'a2',name:'Wireless microphone pair',kind:'Audio',available:true},{id:'l1',name:'Portable LED panel',kind:'Lighting',available:false},{id:'l2',name:'Softbox lighting kit',kind:'Lighting',available:true}];const selected=new Set();let ascending=true;const $=id=>document.getElementById(id);
function selection(){ $('selected-count').textContent=selected.size+(selected.size===1?' item selected':' items selected');$('clear-selection').disabled=!selected.size;const list=$('selection-list');list.replaceChildren();for(const x of data.filter(x=>selected.has(x.id))){const li=document.createElement('li');li.textContent=x.name;list.append(li);}if(!selected.size){const li=document.createElement('li');li.textContent='No equipment selected.';list.append(li);}}
function render(){const query=$('query').value.toLowerCase().trim();const visible=data.filter(x=>x.name.toLowerCase().includes(query)&&($('kind').value==='all'||x.kind===$('kind').value)&&(!$('available').checked||x.available)).sort((a,b)=>(ascending?1:-1)*a.name.localeCompare(b.name));$('count').textContent=visible.length+' of '+data.length+' kits shown';$('empty').hidden=visible.length!==0;$('rows').replaceChildren();for(const x of visible){const tr=document.createElement('tr');const choice=document.createElement('td');const input=document.createElement('input');input.type='checkbox';input.disabled=!x.available;input.checked=selected.has(x.id);input.setAttribute('aria-label','Select '+x.name);input.addEventListener('change',()=>{input.checked?selected.add(x.id):selected.delete(x.id);selection()});choice.append(input);tr.append(choice);for(const value of [x.name,x.kind,x.available?'Available':'On loan']){const td=document.createElement('td');td.textContent=value;tr.append(td);}$('rows').append(tr);}selection();}
$('filters').addEventListener('input',render);$('filters').addEventListener('submit',e=>e.preventDefault());$('filters').addEventListener('reset',()=>setTimeout(render,0));$('sort').addEventListener('click',()=>{ascending=!ascending;$('sort').textContent='Equipment '+(ascending?'↑':'↓');$('sort').parentElement.setAttribute('aria-sort',ascending?'ascending':'descending');render()});$('clear-selection').addEventListener('click',()=>{selected.clear();render()});render();
CSS와 JavaScript 예제를 style.css와 app.js로 저장하세요. 반응형 그리드 미디어 클래스는 별도 파일에 있습니다. 오프라인 미리보기에는 공식 스타일시트 두 개와 원본 애플리케이션 코드가 모두 인라인으로 포함됩니다. HTML 래퍼에는 전체 본문 마크업이 들어 있습니다. 제공된 상호작용 및 CSS 예제는 여기에서 참조하는 파일 이름으로 저장하세요.
html
<!-- npm install [email protected]
mkdir -p assets
cp node_modules/purecss/build/pure-min.css assets/
cp node_modules/purecss/build/grids-responsive-min.css assets/ -->
<!doctype html><html lang="en"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Equipment catalog</title>
<link rel="stylesheet" href="assets/pure-min.css">
<link rel="stylesheet" href="assets/grids-responsive-min.css">
<link rel="stylesheet" href="style.css">
<script src="app.js" defer></script></head>
<body><main class="catalog"><header><p class="eyebrow">PURE CSS / LENDING DESK</p><h1>A small equipment catalog.</h1><p>Find a kit, select available items, and review the local selection.</p></header><div class="pure-g"><aside class="pure-u-1 pure-u-md-1-4"><div class="sidebar"><h2>Refine the list</h2><form class="pure-form pure-form-stacked" id="filters"><label for="query">Equipment name</label><input id="query" type="search" placeholder="Camera, recorder…"><label for="kind">Category</label><select id="kind"><option value="all">All categories</option><option>Camera</option><option>Audio</option><option>Lighting</option></select><label class="pure-checkbox"><input id="available" type="checkbox"> Available only</label><button class="pure-button" type="reset">Clear filters</button></form><div class="selection"><strong id="selected-count">0 items selected</strong><p>Selection is kept when a filter hides a row.</p><button id="clear-selection" class="pure-button" disabled>Clear selection</button></div></div></aside><section class="pure-u-1 pure-u-md-3-4"><div class="results"><p id="count" role="status"></p><div class="table-scroll" tabindex="0" role="region" aria-label="Equipment table, scroll horizontally on narrow screens"><table class="pure-table pure-table-horizontal"><caption>Studio lending kits — local sample records</caption><thead><tr><th scope="col">Select</th><th scope="col" aria-sort="ascending"><button id="sort" class="sort">Equipment ↑</button></th><th scope="col">Category</th><th scope="col">Availability</th></tr></thead><tbody id="rows"></tbody></table></div><p id="empty" hidden>No matching equipment. Clear the filters to see all six kits.</p><section class="summary" aria-labelledby="selection-title"><h2 id="selection-title">Selected for review</h2><ul id="selection-list"><li>No equipment selected.</li></ul><p>This is a browsing example. Selecting a kit does not reserve it.</p></section></div></section></div></main>
</body></html>
프로젝트를 위한 프롬프트
에이전트 프롬프트
제공된 Pure CSS 3.1.0 장비 카탈로그를 기반으로 구현하고 pure-min.css와 grids-responsive-min.css를 모두 불러옵니다. 반응형 그리드의 1/4·3/4 단위, 레이블이 있는 필터, 의미 구조를 갖춘 정렬 가능한 표와 표 안에 포함된 가로 스크롤 영역을 유지합니다. 검색, 카테고리 및 대여 가능 여부 필터를 조합해도 선택된 ID는 지우지 않습니다. 대여 중 체크박스는 비활성화하고, 장비 열의 정렬 순서를 바꿀 때 aria-sort를 업데이트하며, 필터로 숨겨진 항목도 검토 목록에 계속 표시합니다. 선택은 로컬에서만 이루어지며 예약으로 처리되지 않습니다.
05
Pure CSS 디자인 시스템 출처 및 범위
Pure CSS 3.1.0. 선택기 값은 공식 패키지 값이며, 카탈로그의 타이포그래피, 색상, 간격 및 애플리케이션 동작은 독자적으로 구성했습니다. 예약은 이루어지지 않습니다.