스킨·레이아웃 제작
스킨은 모듈의 겉모습, 레이아웃은 사이트 전체의 틀입니다. 만드는 방법은 거의 같고 놓이는 위치와 선언 파일이 다릅니다.
| 위치 | 선언 파일 | 적용 대상 | |
|---|---|---|---|
| 모듈 스킨 | modules/{모듈}/skins/{스킨}/ | skin.xml | 그 모듈의 인스턴스(mid) |
| 레이아웃 | layouts/{레이아웃}/ | conf/info.xml | 사이트(또는 mid별 지정) |
모듈 스킨 만들기
기존 모듈에 새 겉모습을 입히려면, 그 모듈의 skins/default/ 를 통째로 복사해 이름을 바꾸는 것에서 시작하세요. 어떤 템플릿 파일이 필요하고 어떤 변수가 내려오는지는 기본 스킨이 정답지입니다.
modules/board/skins/myskin/
├── skin.xml
├── list.html ← 목록 (+ 상세는 _read.html 포함 방식)
├── _read.html
├── _comment.html
├── write_form.html
├── css/skin.css
└── ...skin.xml
<?xml version="1.0" encoding="UTF-8"?>
<skin version="0.2">
<responsive>true</responsive>
<title xml:lang="ko">내 스킨</title>
<description xml:lang="ko">설명</description>
<version>1.0.0</version>
<date>2026-08-05</date>
<author email_address="you@example.com" link="https://example.com">
<name xml:lang="ko">제작자</name>
</author>
<extra_vars>
<var name="list_style" type="select" default="list">
<title xml:lang="ko">목록 형태</title>
<options value="list"><title xml:lang="ko">목록형</title></options>
<options value="card"><title xml:lang="ko">카드형</title></options>
</var>
</extra_vars>
</skin><responsive>true</responsive>는 이 스킨이 좁은 화면까지 감당한다는 표시입니다. 반응형 뷰와 반응형 표시 참고.<extra_vars>로 선언한 스킨 설정은 템플릿에서$module_info->{변수명}으로 읽습니다.
지켜야 할 것
- 스킨은 화면만 바꿉니다. 서버가 내려주는 변수와 폼 규약은 기본 스킨과 같게 유지해야 합니다. 폼의 hidden 필드(module, act, mid 등)를 빼먹으면 저장이 안 됩니다.
- 게시판 목록 칼럼처럼 관리자 설정과 연동되는 부분(
$list_config등)은 하드코딩하지 말고 설정값을 따르세요. - 아이콘은 이미지 파일 대신 인라인 SVG를 권장합니다.
레이아웃 만들기
layouts/mylayout/
├── layout.html ← 뼈대. {!! $content !!} 자리에 본문이 들어감
├── conf/info.xml
├── css/layout.css
└── js/layout.jslayout.html 최소 골격
@version(2)
@load('css/layout.css')
@load('js/layout.js')
<div class="my-layout">
<header>
<a href="{{ getUrl('') }}">{{ $layout_info->logo_text ?: '사이트' }}</a>
<nav>
@foreach ($gnb->list ?? [] as $item)
<a href="{{ $item['href'] }}" @if (!empty($item['selected'])) class="on" @endif>{{ $item['text'] }}</a>
@endforeach
</nav>
</header>
<main>{!! $content !!}</main>
<footer>{{ $layout_info->copyright }}</footer>
</div>- 본문은
{!! $content !!}로 출력합니다. 이스케이프하면 안 됩니다. - 메뉴는 info.xml의
<menus>선언에 따라$gnb->list등으로 내려옵니다. 각 항목은text(이름)href(주소)selected/open(현재 위치)list(하위 메뉴) 를 가집니다.
conf/info.xml
<?xml version="1.0" encoding="UTF-8"?>
<layout version="0.2">
<responsive>true</responsive>
<title xml:lang="ko">내 레이아웃</title>
<version>1.0.0</version>
<author email_address="you@example.com" link="https://example.com">
<name xml:lang="ko">제작자</name>
</author>
<menus>
<menu name="gnb" maxdepth="3" default="true">
<title xml:lang="ko">상단 메뉴</title>
</menu>
</menus>
<extra_vars>
<group>
<title xml:lang="ko">기본</title>
<var name="logo_text" type="text">
<title xml:lang="ko">로고 텍스트</title>
</var>
<var name="point_color" type="color" default="#2677e3">
<title xml:lang="ko">포인트 색상</title>
</var>
</group>
</extra_vars>
</layout>- extra_vars의
<var>는 반드시<group>안에 두세요. 레이아웃 상세설정은 그룹을 탭으로 그리므로 그룹 밖의 변수는 화면에 보이지 않습니다. - 설정값은 템플릿에서
$layout_info->{변수명}으로 읽습니다. - 슬라이더·배너처럼 반복되는 항목은 반복 필드로 선언하세요.
레이아웃 CSS에서 지킬 것
html, body { margin: 0; background: ... }를 반드시 함께 선언하세요. 최상위 div에만 배경을 칠하면 body 기본 여백과 스크롤 거터가 흰색으로 남아, 다크 모드에서 화면 사방에 흰 테두리처럼 보입니다.- 다크 모드를 지원한다면 색을 CSS 변수로 모으고
data-theme속성 또는prefers-color-scheme으로 전환하세요. - 포인트 색상 설정을 받는다면
style="--brand: {{ $layout_info->point_color }}"처럼 변수로 내려서 CSS 전체가 따라가게 만드는 것이 관리하기 쉽습니다.
배포
스킨·레이아웃은 폴더째 압축해 스토어에 등록하거나 직접 설치(해당 경로에 업로드)합니다. 레이아웃과 모듈 스킨을 세트로 배포하려면 테마 패키지로 묶으세요.