Bulma은 요소, 컴포넌트, 레이아웃 헬퍼, 수정자로 구성된 시각적 어휘를 제공합니다. 양식 상태 관리자나 JavaScript 위젯 런타임은 아닙니다. 편집 데스크에서는 공식 1.0.4 스타일시트를 불러오고, 검증, 실시간 텍스트 미리보기, 테마 전환을 위한 작은 스크립트를 전체 공개합니다. React 종속성이나 프레임워크 프로바이더는 없습니다.
필드에는 레이블, 컨트롤 래퍼, 도움말 텍스트가 포함됩니다. input 클래스는 실제 입력 요소에 적용하고, select는 네이티브 select 요소를 감싸는 래퍼입니다. 래퍼가 꾸밈과 간격을 담당하므로 이러한 차이는 중요합니다. 스크린샷의 모양만 일반 div에 적용하면 네이티브 편집 및 키보드 동작이 사라집니다.
Bulma 1은 색상 계열을 HSL 구성 요소로 저장하고 관련 값을 파생합니다. 링크 역할은 검토 버튼, 섹션 레이블, 보조 강조 요소에 적용됩니다. 경고 및 성공 태그는 초안과 검토 준비 완료 상태를 나타내지만, 텍스트 레이블은 항상 표시됩니다. 메시지는 오류를 알리는 대신 처리 범위를 설명하므로 is-info를 사용합니다.
데모는 html의 data-theme=light 속성으로 시작합니다. 모양 전환 버튼을 누르면 해당 속성이 light와 dark 사이에서 바뀝니다. 모든 카드, 필드, 도움말 텍스트, 메시지가 함께 적절한 테마를 상속합니다. 상자에 흰색 배경을 직접 설정하면 이 전환을 방해합니다. 브랜드 스타일을 재정의하려면 문서화된 역할 변수를 변경하고 파생 상태를 확인하세요. 최종 버튼 배경만 바꾸지 마세요.
기본 글꼴 스택은 Inter로 시작하며 여러 시스템 대체 글꼴을 포함합니다. Bulma을 불러와도 Inter가 다운로드되지는 않습니다. 이 오프라인 예제에서는 나열된 글꼴 중 설치된 글꼴을 사용하므로, 특정 글꼴이 필요한 프로덕션 빌드에서는 글꼴 에셋과 로딩 정책을 별도로 제공해야 합니다. 제목과 부제목 클래스는 HTML 제목 수준을 바꾸지 않으면서 시각적 계층을 설정합니다.
이 편집 작업 공간에서는 페이지 제목에 title is-2, 양식 제목에 title is-4, 기사 제목에 title is-3을 사용합니다. 좁은 화면에서는 페이지 제목을 2rem으로 줄이는 재정의를 적용합니다. 이는 이 화면에만 적용되는 세부 조정입니다. 컨트롤은 기본 1rem 크기를 유지합니다. 도움말은 해당 필드 옆에 배치해 사용자가 별도의 사이드바에서 안내를 찾아보지 않아도 되도록 합니다.
부모 columns에는 is-variable is-6을, 하위 요소에는 column is-7과 column is-5를 적용합니다. 이 비율은 기사 미리보기보다 양식에 더 넓은 공간을 할당합니다. 기본 모바일 우선 동작에서는 모바일 너비일 때 열이 세로로 쌓이므로, 이 구성에는 비좁은 가로 레이아웃을 유지하게 하는 is-mobile을 추가하지 않습니다.
간격 헬퍼의 접미사는 픽셀에 비례하는 선형 척도가 아닙니다. 특히 접미사 5는 1.5rem이고 6은 3rem입니다. 카드와 메시지 사이에는 mt-5를, 작은 레이블에는 mb-3을 사용합니다. 바깥쪽 섹션의 세로 2rem 및 가로 1.5rem 간격은 애플리케이션에서 재정의한 값이며, 전체 추가 CSS은 설정에서 제공합니다.
제목과 요약은 레이블 및 도움말 텍스트와 명시적으로 연결됩니다. 제출을 거부하면 입력 필드와 도움말에 is-danger를 추가하고, aria-invalid=true를 설정한 뒤 첫 번째 유효하지 않은 컨트롤에 포커스를 둡니다. 제목은 공백을 제거한 뒤 최소 다섯 글자, 요약은 최소 스무 글자여야 합니다. 이는 예시로 정한 편집 기준이지 Bulma의 제약이 아닙니다.
문안 확인 체크박스도 선택해야 합니다. 체크박스와 설명 오류는 aria-describedby로 연결됩니다. Bulma은 이러한 상태를 표시할 수 있지만 문안이 준비되었는지는 판단하지 않습니다. 판단과 기본 양식 탐색 방지는 스크립트가 담당합니다. 서버 처리 결과는 임의로 만들어 내지 않습니다.
기사 카드는 card-header와 card-content를 구분합니다. 헤더 텍스트는 항목을 식별하고, 태그는 편집 상태를 표시합니다. 콘텐츠에는 실시간으로 업데이트되는 섹션, 제목, 요약이 이어지며, 그다음에 메타데이터가 표시됩니다. 미리보기는 의도적으로 텍스트를 중심에 둡니다. 작성자는 자리 표시용 이미지가 브리프를 압도하지 않는 상태에서 계층 구조와 길이를 살펴볼 수 있습니다.
메시지 컴포넌트는 message-header와 message-body를 사용해 검토 준비 여부가 이 화면에서만 관리된다는 점을 설명합니다. 유효성 검사 결과와 관계없이 계속 표시됩니다. 잠시 나타났다가 사라지는 성공 알림은 지속적으로 경계를 안내하는 이 메시지를 대신하기에 적절하지 않습니다. 알림을 닫은 뒤 사용자가 기사가 게시되었다고 오해할 수 있기 때문입니다.
입력할 때마다 미리보기가 업데이트되고 상태가 초안으로 초기화됩니다. 작성자가 검토된 텍스트를 수정한 뒤에도 준비 완료 태그가 남아 있는 문제를 방지합니다. textContent를 사용해 표시하므로 입력한 HTML은 마크업으로 해석되지 않고 텍스트로 표시됩니다. 이는 애플리케이션에서 처리해야 할 동작이며, Bulma 스타일시트만으로는 구현할 수 없습니다.
초안 복원 기능은 form.reset을 호출하고, 유효성 검사 클래스와 aria-invalid를 제거하며, 체크박스 도움말을 지우고 미리보기를 다시 구성합니다. 문서를 새로고침하지 않고 원래 예시 콘텐츠로 되돌립니다. status 문단은 제출 후 변경 사항을 알리기 위해 role=status를 사용하며, 입력 중에는 포커스를 반복해서 이동하지 않습니다.
[email protected]를 설치하고 컴파일된 CSS을 로컬 에셋으로 복사하거나, 기존 번들러에서 해당 CSS을 가져옵니다. 여기에 표시된 일반 HTML 설정은 에셋을 복사한 뒤 별도의 빌드 단계가 필요하지 않습니다. 편집 작업 공간의 마크업 전체를 body에 넣고 app.js는 defer와 함께 불러옵니다. 다른 JavaScript 패키지를 불러오면 Bulma의 컴포넌트가 활성화될 것이라고 기대하며 관련 없는 패키지를 추가하지 마세요.
나중에 모달이나 드롭다운을 추가한다면 해당 요소에 필요한 키보드, 포커스, 닫기 동작을 신중하게 구현하세요. is-active 같은 클래스는 모양만 바꾸며 포커스 트랩 기능을 제공하지 않습니다. 이 예제에서는 기본 입력 필드와 버튼만 사용해 동작 범위를 작고 검토하기 쉽게 유지합니다.
전역 --bulma 변수로 테마를 설정할 수 있지만, 컴포넌트도 자체 선택자에 변수를 정의합니다. 더 구체적인 컴포넌트 설정은 루트 수준의 값을 재정의할 수 있습니다. 루트 재정의가 적용되지 않는 것 같으면 컴파일된 CSS에서 해당 클래스를 확인한 뒤, 관련 없는 선언을 덧붙이는 대신 적절한 컴포넌트에 재정의를 적용하세요.
오래 사용할 제품이라면 패키지 기본값, 브랜드 재정의, 화면별 레이아웃 규칙을 구분하세요. 예제의 좁은 컨테이너와 모바일 제목 조정은 화면별 규칙입니다. 참조 표에는 실제 Bulma 값이 별도로 정리되어 있어 재사용할 수 있는 설정과 이 편집 작업 공간에만 적용되는 설정을 명확히 구분할 수 있습니다.
Bulma field/control/label/help 구성, 7:5 열, 카드, 메시지, 상태 태그.
html
<section class="section"><div class="container"><div class="level"><div class="level-left"><div><p class="is-size-7 has-text-weight-bold has-text-link mb-3">BULMA / LOCAL EDITORIAL DESK</p><h1 class="title is-2">Shape the next issue.</h1><p class="subtitle is-5">An article brief, a preview, and an explicit editorial state.</p></div></div><div class="level-right"><button class="button is-light" id="theme">Dark appearance</button></div></div><div class="columns is-variable is-6"><div class="column is-7"><form id="brief" class="box" novalidate><h2 class="title is-4">Article brief</h2><div class="field"><label class="label" for="headline">Headline</label><div class="control"><input class="input" id="headline" value="A quieter way to work" maxlength="90" aria-describedby="headline-help"></div><p class="help" id="headline-help">Use 5–90 characters. This field updates the preview as you type.</p></div><div class="field"><label class="label" for="section">Section</label><div class="control"><div class="select is-fullwidth"><select id="section"><option>Design notes</option><option>Field research</option><option>Product craft</option></select></div></div></div><div class="field"><label class="label" for="summary">Summary</label><div class="control"><textarea class="textarea" id="summary" rows="3" aria-describedby="summary-help">How small choices in layout and language can make a demanding interface feel manageable.</textarea></div><p class="help" id="summary-help">Use at least 20 characters to give the reviewer enough context.</p></div><div class="field"><label class="checkbox"><input id="checked" type="checkbox" aria-describedby="checked-help" aria-describedby="checked-help"> I have checked the headline and summary</label><p class="help" id="checked-help"></p></div><div class="field is-grouped is-grouped-multiline"><div class="control"><button type="submit" class="button is-link">Mark ready for review</button></div><div class="control"><button id="reset" type="button" class="button is-light">Restore draft</button></div></div><p id="result" class="help" role="status">Draft changes stay in this page only.</p></form></div><div class="column is-5"><article class="card"><header class="card-header"><p class="card-header-title">Issue 08 / Article preview</p><span id="state" class="tag is-warning is-light mr-4 my-4">Draft</span></header><div class="card-content"><p class="is-size-7 has-text-link has-text-weight-bold mb-3" id="preview-section">Design notes</p><h2 class="title is-3" id="preview-title">A quieter way to work</h2><div class="content" id="preview-summary">How small choices in layout and language can make a demanding interface feel manageable.</div><hr><p class="is-size-7">Copy desk · Reading time assigned after editing</p></div></article><article class="message is-info mt-5"><div class="message-header"><p>Review is a separate step</p></div><div class="message-body">Ready for review is a local label. It does not publish this article, send a notification, or save a draft on a server.</div></article></div></div><p class="is-size-7">Official Bulma 1.0.4 CSS. Form validation and preview updates are original JavaScript.</p></div></section>
원본 이벤트 핸들러가 동작을 제공하며, 이는 Bulma이 의도적으로 애플리케이션에 맡기는 부분입니다.
자바스크립트
const $=id=>document.getElementById(id);
const fields=['headline','summary'];
function draft(){ $('state').textContent='Draft';$('state').className='tag is-warning is-light mr-4 my-4';$('result').textContent='Draft changes stay in this page only.';}
function preview(){ $('preview-title').textContent=$('headline').value.trim()||'Untitled article';$('preview-summary').textContent=$('summary').value.trim()||'No summary yet.';$('preview-section').textContent=$('section').value;draft();}
for(const id of ['headline','summary','section','checked'])$(id).addEventListener('input',preview);
$('brief').addEventListener('submit',event=>{event.preventDefault();let first=null;for(const id of fields){const invalid=$(id).value.trim().length<(id==='headline'?5:20);$(id).classList.toggle('is-danger',invalid);$(id).setAttribute('aria-invalid',String(invalid));$(id+'-help').classList.toggle('is-danger',invalid);if(invalid&&!first)first=$(id);}$('checked-help').textContent=$('checked').checked?'':'Confirm the copy check before review.';$('checked-help').className='help is-danger';if(!$('checked').checked&&!first)first=$('checked');if(first){$('result').textContent='Check the highlighted brief fields.';first.focus();return;}$('state').textContent='Ready for review';$('state').className='tag is-success is-light mr-4 my-4';$('result').textContent='Marked ready in this local preview. Nothing was published.';});
$('reset').addEventListener('click',()=>{$('brief').reset();for(const id of fields){$(id).classList.remove('is-danger');$(id).removeAttribute('aria-invalid');$(id+'-help').classList.remove('is-danger');}$('checked-help').textContent='';preview();});
$('theme').addEventListener('click',()=>{const dark=document.documentElement.dataset.theme!=='dark';document.documentElement.dataset.theme=dark?'dark':'light';$('theme').textContent=dark?'Light appearance':'Dark appearance';});
안내된 대로 전체 마크업과 JavaScript 예제를 저장하세요. Bulma은 CSS을 제공하며, 제공된 애플리케이션 스크립트는 모든 유효성 검사와 로컬 상태를 구현합니다. 오프라인 미리보기에는 두 파일이 모두 인라인으로 포함되어 있습니다. HTML 래퍼에는 전체 본문 마크업이 포함됩니다. 제공된 상호작용 예제와 CSS 예제는 여기에 나온 파일 이름으로 저장하세요.
html
<!-- Install and copy the local asset:
npm install [email protected]
mkdir -p assets
cp node_modules/bulma/css/bulma.min.css assets/bulma.min.css
-->
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Editorial desk</title>
<link rel="stylesheet" href="assets/bulma.min.css">
<style>.section{padding:2rem 1.5rem}.container{max-width:1080px!important}.card-header{align-items:center;flex-wrap:wrap}.title{overflow-wrap:anywhere}.level-left{min-width:0}@media(max-width:768px){.title.is-2{font-size:2rem}.level-right{margin-top:1rem}}</style>
<script src="app.js" defer></script>
</head>
<body><section class="section"><div class="container"><div class="level"><div class="level-left"><div><p class="is-size-7 has-text-weight-bold has-text-link mb-3">BULMA / LOCAL EDITORIAL DESK</p><h1 class="title is-2">Shape the next issue.</h1><p class="subtitle is-5">An article brief, a preview, and an explicit editorial state.</p></div></div><div class="level-right"><button class="button is-light" id="theme">Dark appearance</button></div></div><div class="columns is-variable is-6"><div class="column is-7"><form id="brief" class="box" novalidate><h2 class="title is-4">Article brief</h2><div class="field"><label class="label" for="headline">Headline</label><div class="control"><input class="input" id="headline" value="A quieter way to work" maxlength="90" aria-describedby="headline-help"></div><p class="help" id="headline-help">Use 5–90 characters. This field updates the preview as you type.</p></div><div class="field"><label class="label" for="section">Section</label><div class="control"><div class="select is-fullwidth"><select id="section"><option>Design notes</option><option>Field research</option><option>Product craft</option></select></div></div></div><div class="field"><label class="label" for="summary">Summary</label><div class="control"><textarea class="textarea" id="summary" rows="3" aria-describedby="summary-help">How small choices in layout and language can make a demanding interface feel manageable.</textarea></div><p class="help" id="summary-help">Use at least 20 characters to give the reviewer enough context.</p></div><div class="field"><label class="checkbox"><input id="checked" type="checkbox" aria-describedby="checked-help" aria-describedby="checked-help"> I have checked the headline and summary</label><p class="help" id="checked-help"></p></div><div class="field is-grouped is-grouped-multiline"><div class="control"><button type="submit" class="button is-link">Mark ready for review</button></div><div class="control"><button id="reset" type="button" class="button is-light">Restore draft</button></div></div><p id="result" class="help" role="status">Draft changes stay in this page only.</p></form></div><div class="column is-5"><article class="card"><header class="card-header"><p class="card-header-title">Issue 08 / Article preview</p><span id="state" class="tag is-warning is-light mr-4 my-4">Draft</span></header><div class="card-content"><p class="is-size-7 has-text-link has-text-weight-bold mb-3" id="preview-section">Design notes</p><h2 class="title is-3" id="preview-title">A quieter way to work</h2><div class="content" id="preview-summary">How small choices in layout and language can make a demanding interface feel manageable.</div><hr><p class="is-size-7">Copy desk · Reading time assigned after editing</p></div></article><article class="message is-info mt-5"><div class="message-header"><p>Review is a separate step</p></div><div class="message-body">Ready for review is a local label. It does not publish this article, send a notification, or save a draft on a server.</div></article></div></div><p class="is-size-7">Official Bulma 1.0.4 CSS. Form validation and preview updates are original JavaScript.</p></div></section>
</body>
</html>
프로젝트를 위한 프롬프트
에이전트 프롬프트
전체 Bulma 1.0.4 편집 데스크를 사용하세요. 필드·컨트롤·도움말 구성, 반응형 열, 카드 및 메시지 구성 요소, 문서 수준의 라이트/다크 테마를 유지하세요. 제목과 요약을 수정하면 textContent를 통해 기사 미리보기가 업데이트되고 상태가 초안으로 돌아가야 합니다. 글자 수 제한은 앞뒤 공백을 제거한 텍스트를 기준으로 적용하고, 검토 준비 완료로 표시하기 전에 교정 확인을 받으세요. 유효하지 않은 필드를 관련 도움말과 연결하고 첫 번째 오류에 포커스를 두세요. 원본 초안을 복원하고 유효성 검사 상태를 지우되, 게시된 것으로 오해하게 해서는 안 됩니다.