타임리프 레이아웃을 이용한 UI 개편기
들어가며
“부트스트랩으로 어려운 거만 커스텀 CSS를 작성해달라”는 요청에서 시작된 프로젝트였습니다. 기존의 레거시 UI를 현대적인 SNS 스타일로 완전히 리뉴얼하면서 겪었던 경험과 해결책을 공유하고자 합니다.
문제 상황
기존 블로그는 전통적인 웹 블로그 레이아웃을 따르고 있었습니다. 하지만 사용자 경험을 개선하고 더 현대적인 인터페이스를 제공하기 위해 트위터 같은 SNS 피드 형태로의 전환이 필요했습니다. 특히 백엔드 개발자 입장에서 프론트엔드를 직접 구성하기 위해서는 다음과 같은 고민이 있었습니다.
-
유지보수가 쉬운 구조
-
중복을 최소화한 코드 재사용성
-
일관된 디자인 시스템 적용
-
모바일 반응형 지원
기술 선택: 타임리프 레이아웃 패턴
먼저 적용한 기술은 Thymeleaf의 레이아웃 Dialect를 활용한 계층적 템플릿 구조입니다.
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.3.0'
레이아웃 계층 구조
layouts/default.html (기본 레이아웃)
├── fragments/components.html (재사용 가능한 모든 컴포넌트)
│ ├── navbar
│ ├── sidebar-left
│ ├── sidebar-right
│ ├── post-card
│ └── mobile-nav
└── 각 페이지 (index.html, viewer.html 등)
이 구조를 통해 모든 페이지에서 일관된 헤더, 사이드바, 푸터를 자동으로 적용할 수 있었습니다. 새로운 페이지를 추가할 때는 단순히 layout:decorate="~{layouts/default}"를 선언하고 layout:fragment="content"에만 집중하면 됩니다.
디자인 시스템 구축
브랜드 일관성 유지
모든 색상, 크기, 스타일을 CSS 변수와 유틸리티 클래스로 정의했습니다.
/* 브랜드 컬러 */
.brand-color {
color: #4A7822;
}
.post-action-btn {
text-decoration: none !important;
border-radius: 50px;
padding: 6px 12px !important;
transition: all 0.2s ease;
}
.post-action-btn:hover {
background-color: rgba(74, 120, 34, 0.1);
color: #4A7822 !important;
}
부트스트랩의 기본 스타일을 최대한 활용하면서, 프로젝트 고유의 디자인이 필요한 부분만 커스텀 CSS를 작성했습니다. 이를 통해 CSS 파일의 크기를 최소화하면서도 브랜드 일관성을 유지할 수 있었습니다.
주요 구현 사항
1. 반응형 레이아웃
부트스트랩의 그리드 시스템을 활용하되, 모바일에서의 사용성을 특별히 고려했습니다.
<div class="container-fluid main-container">
<div class="row justify-content-center">
<!-- 왼쪽 사이드바: 데스크탑에서만 표시 -->
<aside class="col-lg-2 d-none d-lg-block sidebar-left">
...
</aside>
<!-- 메인 콘텐츠 -->
<main class="col-12 col-lg-6 main-content px-0">
...
</main>
<!-- 오른쪽 사이드바: 데스크탑에서만 표시 -->
<aside class="col-lg-3 d-none d-lg-block sidebar-right">
...
</aside>
</div>
</div>
<!-- 모바일 하단 네비게이션: 화면 크기 992px 이하에서만 표시 -->
<nav class="d-lg-none mobile-nav">
...
</nav>
데스크탑에서는 3단 레이아웃으로 정보를 풍부하게 제공하고, 모바일에서는 메인 콘텐츠에 집중할 수 있도록 설계했습니다. 특히 하단 네비게이션을 고정시켜 모바일 사용자가 항상 접근할 수 있도록 했습니다.
2. 게시물 길이 제어 및 더보기 기능
사용자가 피드에서 긴 게시물로 인한 불편함을 겪지 않도록, 300px 이상의 게시물은 자동으로 페이드 효과와 함께 “더보기” 버튼을 노출합니다.
function checkHeightAndFade(viewerEl) {
const wrapper = viewerEl.closest('.post-content-wrapper');
const maxHeight = 300;
if (viewerEl.offsetHeight > maxHeight) {
wrapper.classList.add('has-fade');
const showMoreBtn = wrapper.parentElement.querySelector('.show-more-btn');
if (showMoreBtn) showMoreBtn.classList.remove('d-none');
}
}
function togglePostContent(btn) {
const wrapper = document.querySelector(btn.getAttribute('data-target'));
if (wrapper.classList.contains('expanded')) {
wrapper.classList.remove('expanded');
btn.textContent = '더보기';
} else {
wrapper.classList.add('expanded');
btn.textContent = '접기';
}
}
CSS에서 max-height 속성과 그래디언트를 활용한 페이드 효과로 부드러운 사용자 경험을 제공했습니다.
3. 에디터 화면 최적화
처음에는 에디터가 스크롤될 때도, 페이지 자체가 스크롤될 때도 있는 불일관한 동작이 있었습니다. 이를 해결하기 위해 Flexbox를 활용한 완전한 레이아웃 재설계를 진행했습니다.
html, body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
#postForm {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
.editor-body {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
#editor {
flex: 1;
overflow: hidden !important;
}
이를 통해 페이지 전체 스크롤을 제거하고 에디터 내부에서만 스크롤이 발생하도록 제한했습니다. 그 결과 사용자는 언제나 헤더와 제목 입력창을 볼 수 있게 되었고, 에디터에만 집중할 수 있는 환경을 구성했습니다.
배운 점
1. 프론트엔드는 백엔드의 책임이 아니지만
백엔드 개발자가 UI를 구성할 때는 프레임워크와 라이브러리의 기본 기능을 최대한 활용하는 것이 중요합니다. 부트스트랩이나 타임리프 같은 도구들은 이미 검증된 패턴을 제공하고 있으므로, 이를 올바르게 활용하면 생각보다 효율적인 결과를 얻을 수 있습니다.
2. 모듈화와 재사용성
타임리프의 프래그먼트를 활용한 컴포넌트 기반 개발은 템플릿에서도 동일하게 적용됩니다. 각 컴포넌트를 독립적으로 유지하면 나중에 스타일 변경이나 기능 추가 시 영향 범위를 최소화할 수 있습니다.
3. 반응형 디자인의 중요성
모바일 사용자의 비율이 높아지는 만큼, 반응형 디자인은 선택이 아닌 필수입니다. 특히 SNS 형태의 피드는 모바일에서 더욱 자연스러운 사용자 경험을 제공해야 합니다.
마치며
이 프로젝트를 통해 백엔드 개발자도 기본적인 UI/UX 원칙을 이해하고 적절한 도구를 활용하면 전문가 수준의 프론트엔드를 구성할 수 있다는 것을 배웠습니다. 물론 전문 프론트엔드 개발자의 감각을 완전히 대체할 수는 없지만, 작은 팀이나 개인 프로젝트에서는 충분히 가능한 영역입니다.
특히 타임리프 레이아웃 패턴과 부트스트랩의 조합은 생각보다 강력한 도구입니다. 이를 활용하면 빠르고 일관성 있게 웹 인터페이스를 구성할 수 있으며, 나중의 유지보수도 한결 수월해집니다.
링크:
링크: » 일본어로 보기 (日本語で見る)
링크: » 영어로 보기 (Switch to English)
공유: