Article (아티클)
Va.Article — HTML <article> 시맨틱 컨테이너
HTML5의 <article> 태그를 감싸는 시맨틱 컨테이너. 독립적으로 배포·재사용 가능한 콘텐츠를 나타내는 랜드마크 요소입니다. 블로그 글·뉴스 기사·상품 카드처럼 그 자체로 완결된 콘텐츠 단위에 어울립니다. VanillaFront에서 가장 자주 쓰는 semantic 태그 중 하나 — 데모 코드에서도 최상위 컨테이너로 자주 등장.
- 클래스: Va.Article — va_component.js:21824
- short name: article
- 상속: Va.Semantic (Main·Section과 같은 부모)
- DOM 태그: <article>
- isContainer: true
- 베이스 CSS: va-article
1. 기본 사용
{
tagName: 'article',
layout: 'ds-flex fd-column gap-m',
tags: [
{ tagName: 'h1', innerHTML: '기사 제목' },
{ tagName: 'p', innerHTML: '본문 내용...' }
]
}
- HTML <article> 태그로 렌더링
- 자식을 자유롭게 담음
- 스크린리더가 "독립 콘텐츠"로 인식
2. Va.Article의 성격
Va.Semantic을 상속한 얇은 확장. 코드 자체는 매우 단순(30줄)하지만, VanillaFront 데모·문서 페이지의 최상위 컨테이너로 관행처럼 사용되고 있습니다.
항목Va.DivVa.Article
| HTML 태그 | <div> | <article> |
| 시맨틱 의미 | 없음 | 독립 콘텐츠 단위 |
| 접근성 | 기본 | 랜드마크 (제목 있으면) |
| SEO | 기본 | 크롤러가 독립 콘텐츠로 인식 |
| 한 페이지 여러 개 | 자유 | 자유 (Main과 다름) |
| 재사용 시맨틱 | 없음 | 자체 완결 콘텐츠 (RSS·공유 등) |
한 줄 요약: "독립 콘텐츠 단위를 표현하는 시맨틱 컨테이너 — 데모·문서 최상위로 자주 사용."
3. <article> HTML 표준의 의미
HTML5 표준상 <article>은 **"독립적으로 배포하거나 재사용할 수 있는 완결된 콘텐츠"**를 나타냅니다. 판단 기준:
- RSS 피드에 넣을 수 있는가? — 블로그 글, 뉴스 기사 O
- 다른 사이트로 그대로 옮겨도 의미가 통하는가? — 상품 카드, 리뷰 O
- 댓글·평점처럼 각각 독립적인 단위인가? — 개별 댓글 O
한 페이지에 여러 개 있을 수 있고 (Main과 다름), 중첩도 가능 (기사 안 관련 기사 등).
4. Semantic 계열에서의 위치
Va.Article은 시맨틱 형제들 중 하나:
컴포넌트시맨틱 의미
| Va.Main | 페이지 주요 콘텐츠 (한 페이지 하나) |
| Va.Article | 독립 배포 가능 콘텐츠 |
| Va.Section | 주제별 콘텐츠 섹션 |
| Va.Aside | 부수적 콘텐츠 |
| Va.Nav | 네비게이션 |
| Va.Header / Va.Footer | 헤더/푸터 |
Article과 Section 헷갈리기 쉬움:
- Article — 독립적, 그 자체로 완결 (블로그 글)
- Section — 문서 안 하나의 섹션, 주제별 그룹
5. 주요 속성
Semantic 상속만. 자체 추가 없음:
속성설명
| innerHTML | HTML 콘텐츠 (_sanitize 적용) |
| text | 순수 텍스트 |
| layout | Flex/Grid 레이아웃 |
| style / mobileStyle | 스타일 |
| class / addClass | CSS 클래스 |
| mediaQuery | 반응형 |
Component의 표준 속성 그대로.
6. 이벤트 (Semantic 상속)
이벤트시그니처발생 시점
| click | (component, element, evt) | 클릭 |
| contextmenu | (component, element, evt) | 우클릭 (기본 컨텍스트 메뉴 자동 차단) |
| focus / blur | (component, element, evt) | 포커스 진입/이탈 |
7. 메서드
메서드설명
| setText(text) | 텍스트 변경 (Semantic 상속) |
| setInnerHTML(html) | HTML 콘텐츠 변경 |
8. 내부 구조
<article elname="element" class="va-article [layout classes]"
tag-name="article">
<!-- 자식 컴포넌트들 -->
</article>
매우 단순. HTML <article> 태그 + va-article CSS 클래스.
9. VanillaFront에서의 관행
Demo·API 문서 페이지의 최상위 컨테이너로 관행처럼 사용됩니다:
// 프로젝트 내 대부분 Demo 파일이 이 구조로 시작
config() {
return {
tagName: 'article',
layout: 'ds-flex fd-column gap-m',
tags: [
{ tagName: 'h3', innerHTML: '데모 제목' },
/* ... */
]
};
}
이유:
- 데모 하나가 그 자체로 완결된 예제 → Article이 시맨틱상 적절
- Page/Panel보다 가벼워서 데모용으로 부담 없음
- HTML 표준 준수
⚠️ 다만 실무 화면은 page > panel 구조가 프로젝트 표준 (CLAUDE.md 3장). Article은 데모 성격이 강함.
10. 언제 쓰나
Va.Article이 맞을 때
- 블로그 글, 뉴스 기사 등 완결 콘텐츠
- 상품 카드, 리뷰 아이템 등 독립 단위
- 데모·API 문서 페이지 최상위 (VanillaFront 관행)
- 댓글·게시글 목록의 각 아이템
다른 걸 쓸 때
- 실무 화면 최상위 → Va.Page + Va.Panel (VanillaFront 표준)
- 페이지 주요 콘텐츠 랜드마크 → Va.Main
- 주제별 섹션 → Va.Section
- 부수 콘텐츠 → Va.Aside
- 단순 컨테이너 → Va.Div
11. 흔한 조합 예시
// 데모 페이지 표준 (VanillaFront 관행)
{
tagName: 'article',
layout: 'ds-flex fd-column gap-m',
tags: [
{ tagName: 'h3', innerHTML: '컴포넌트 데모' },
{ tagName: 'button', text: '테스트' }
]
}
// 블로그 글 카드
{
tagName: 'article',
layout: 'ds-flex fd-column gap-s',
style: { border: '1px solid gray', padding: '16px' },
tags: [
{ tagName: 'h2', innerHTML: '제목' },
{ tagName: 'p', innerHTML: '요약 텍스트' },
{
tagName: 'div',
layout: 'ds-flex fd-row gap-s',
tags: [
{ tagName: 'span', innerHTML: '작성자' },
{ tagName: 'span', innerHTML: '2026-09-14' }
]
}
]
}
// 상품 카드
{
tagName: 'article',
layout: 'ds-flex fd-column',
style: { border: '1px solid gray', borderRadius: '8px' },
tags: [
{ tagName: 'img', src: '/product.jpg' },
{
tagName: 'div',
style: { padding: '12px' },
tags: [
{ tagName: 'h3', innerHTML: '상품명' },
{ tagName: 'p', innerHTML: '10,000원' },
{ tagName: 'button', text: '장바구니' }
]
}
]
}
// 리뷰 목록의 각 아이템
{
tagName: 'section',
tags: [
{ tagName: 'h2', innerHTML: '리뷰' },
{
tagName: 'div',
layout: 'ds-flex fd-column gap-m',
tags: [
{
tagName: 'article', // 리뷰 하나가 독립 콘텐츠
tags: [ /* 별점, 리뷰 텍스트, 작성자 */ ]
},
{
tagName: 'article',
tags: [ /* ... */ ]
}
]
}
]
}
12. 실전 예 — 블로그 목록 페이지
class BlogList extends Va.View {
async mounted() {
const res = await BlogService.list(this);
if (res.result) this.renderPosts(res.data.list);
}
renderPosts(posts) {
const container = this.getRef('posts');
container.innerHTML = '';
posts.forEach(post => {
const article = new Va.Article({
layout: 'ds-flex fd-column gap-s',
style: { border: '1px solid var(--colorNeutralStroke)', padding: '16px' }
});
article.append(new Va.H2({ innerHTML: post.title }));
article.append(new Va.P({ innerHTML: post.summary }));
container.append(article);
});
}
config() {
return {
tagName: 'main', // 전체는 main (랜드마크)
layout: 'ds-flex fd-column gap-l',
style: { padding: '20px' },
tags: [
{ tagName: 'header', tags: [{ tagName: 'h1', innerHTML: '블로그' }] },
{
tagName: 'section', // 목록 섹션
ref: 'posts',
layout: 'ds-flex fd-column gap-m'
}
]
};
}
}
시맨틱 계층:
- <main> — 페이지 주요 콘텐츠 (한 페이지 하나)
- <section> — 블로그 목록 섹션
- <article> × N — 각 블로그 글 (독립 콘텐츠, RSS로 넣을 수 있는 단위)
13. 알아두면 좋을 주의사항
- Article vs Section 구분 — "독립적 재배포 가능한가?"가 판단 기준.
- 한 페이지 여러 개 OK — Main과 달리 개수 제한 없음.
- 중첩 가능 — 기사 안 관련 기사 등.
- VanillaFront 데모 관행 — article 최상위는 데모용. 실무는 page 권장.
- contextmenu 자동 preventDefault — 우클릭 시 브라우저 기본 메뉴 차단.
- 자체 스타일 최소 — va-article 클래스만. gap·padding은 layout·style로 명시.
- text/innerHTML은 자식 tags와 배타적 — 대개 자식으로 구조화된 콘텐츠 담음.
- 접근성 랜드마크 — 스크린리더가 인식하려면 aria-labelledby 등으로 제목 연결 권장.
- SEO 최적화 — 크롤러가 독립 콘텐츠로 인식 → 목록 페이지에서 각 글을 article로 감싸는 게 유리.
- Va.Semantic 상속 — Section·Header·Footer 등과 동작 방식 완전 동일.
14. article vs section vs main vs page 선택
상황추천
| 독립 콘텐츠 단위 (블로그 글, 상품) | article |
| 문서 안 주제 섹션 | section |
| 페이지 주요 콘텐츠 (랜드마크) | main |
| VanillaFront 실무 화면 | page + panel |
| 데모·API 문서 페이지 | article (관행) |
| 부수 콘텐츠 | aside |
"블로그·상품·리뷰처럼 그 자체로 완결되면 article, 페이지 안 섹션 나누기면 section".
참고
- API 문서 페이지: https://vanillafront.com/docs.html?theme=light#main#apiarticle
- 연관: Va.Semantic(부모), Va.Section(가장 자주 비교되는 형제)