사이먼's 코딩노트

[SpringBoot] Bootstrap 및 폰트 적용 / 공통 layout 추가 본문

Java/SpringBoot

[SpringBoot] Bootstrap 및 폰트 적용 / 공통 layout 추가

simonpark817 2024. 5. 12. 17:43

[Bootstrop 및 폰트 적용]

  • 기본 스타일시트를 생성하였다면, 보다 아름다운 디자인을 위해 부트스트랩을 도입해봅시다.
  • 부트스트랩(Bootstrap)이란 프론트엔드 프레임워크로 웹 페이지를 쉽게 디자인할 수 있게 도와주고, 전에 포스팅을 했던 테일즈윈드 데이지UI와 같이 각종 레이아웃, 버튼, 입력창 등의 디자인을 CSS와 JavaScript로 만들어 놓은 곳이다.
  • 부트스트랩은 트위터를 개발하면서 만들어졌으며, 현재 지속적으로 관리되고 있는 오픈소스 프로젝트로, 웹 디자이너의 도움 없이도 개발자 혼자서 상당히 괜찮은 수준의 웹 페이지를 만들 수 있게 도와준다는 것이 가장 큰 장점이다.
  • 직접 설치해서 부트스트랩을 적용하는 방법도 있지만, cdnjs에서 부트스트랩 링크를 복사하여 코드에 직접 추가하여 부트스트랩을 사용할 예정이다.
  • 부트스트랩을 통해 디자인을 적용해 볼 템플릿은 question_detail.html와 question_list.html 이다.
  • 아래는 question_list.html 템플릿에 부트스트랩을 적용한 코드이다.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css">

<div class="container my-3">
    <table class="table">
        <thead class="table-info">
            <tr>
                <th>번호</th>
                <th>제목</th>
                <th>작성일시</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="question, loop : ${questionList}">
                <td th:text="${loop.count}"></td>
                <td>
                    <a th:href="@{|/question/detail/${question.id}|}" th:text="${question.subject}"></a>
                </td>
                <td th:text="${#temporals.format(question.createDate, 'yyyy-MM-dd HH:mm')}"></td>
            </tr>
        </tbody>
    </table>
</div>
  • question_list는 현재 테이블로 구성된 총 질문 리스트를 출력하는 화면이다.
  • 부트스트랩을 템플릿 상단에 link 태그를 통해 적용시켜주고 테이블 각 태그에 부트스트랩에서 제공하는 class 네임을 붙혀주게 되면 기존의 테이블 디자인보다 더 세련된 모습을 볼 수 있다.
  • 아래는 부트스트랩 적용 후 변경된 localhost:8090/question/list 의 화면 디자인이다.

부트스트랩이 적용된 question_list.html

 

[폰트 적용]

  • 다음은 question_detail.html에 부트스트랩을 적용하면서 폰트도 새로 적용해봅시다.
  • 폰트 적용은 눈누 홈페이지를 통해 코드를 참조했다.
  • 아래는 question_detail.html 템플릿에 부트스트랩과 폰트를 모두 적용한 코드이다.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css">

<style>
@font-face {
    font-family: 'Pretendard-Regular';
    src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff');
    font-weight: 400;
    font-style: normal;
}
html > body {
    font-family: 'Pretendard-Regular';
}
</style>

<div class="container my-3">
    <!-- 질문 -->
    <h2 class="border-bottom py-2" th:text="${question.subject}"></h2>
    <div class="card my-3">
        <div class="card-body">
            <div class="card-text" style="white-space: pre-line;" th:text="${question.content}"></div>
            <div class="d-flex justify-content-end">
                <div class="badge bg-light text-dark p-2 text-start">
                    <div th:text="${#temporals.format(question.createDate, 'yyyy-MM-dd HH:mm')}"></div>
                </div>
            </div>
        </div>
    </div>
    <!-- 답변의 갯수 표시 -->
    <h5 class="border-bottom my-3 py-2"
th:text="|${#lists.size(question.answerList)}개의 답변이 있습니다.|"></h5>
    <!-- 답변 반복 시작 -->
    <div class="card my-3" th:each="answer : ${question.answerList}">
        <div class="card-body">
            <div class="card-text" style="white-space: pre-line;" th:text="${answer.content}"></div>
            <div class="d-flex justify-content-end">
                <div class="badge bg-light text-dark p-2 text-start">
                    <div th:text="${#temporals.format(answer.createDate, 'yyyy-MM-dd HH:mm')}"></div>
                </div>
            </div>
        </div>
    </div>
    <!-- 답변 반복 끝  -->
    <!-- 답변 작성 -->
    <form th:action="@{|/answer/create/${question.id}|}" method="post" class="my-3">
        <textarea name="content" id="content" rows="10" class="form-control"></textarea>
        <input type="submit" value="답변등록" class="btn btn-primary my-2">
    </form>
</div>
  • 코드 상단에 link 태그를 통해 마찬가지로 부트스트랩을 적용하고 각 태그별로 부트스트랩에서 제공하는 class 네임을 붙혀주게 되면 기존보다 더 세련된 디자인의 폼 형태를 볼 수 있다. 
  • 폰트는 그 아래 style 태그를 통해 적용했고, html > body 라는 선택자를 통해 전체 폰트를 Pretendard-Regular로 지정하였다.
  • 사실 폰트는 CSS에서 코드를 작성하지만, 지금과 같이 HTML에서 style 태그를 사용하고 그 안에 폰트를 지정해도 크게 상관없다.
  • 아래는 부트스트랩 적용 후 변경된 localhost:8090/question/detail/2의 화면 디자인이다.

부트스트랩과 폰트가 적용된 question_detail.html

 

  • 아래 표는 참고용으로 부트스트랩 클래스에 대한 몇 가지 설명을 담았다.

부트스트랩 클래스 설명

 

[공통 layout 추가 및 템플릿 상속]

  • 현재까지 작성된 템플릿의 문제가 있다면 표준 HTML 구조로 작성하지 않고 <body> 태그가 있다는 가정 하에 일반 태그들을 사용하였다.
  • 사실 어떤 웹 브라우저를 사용하더라도 웹 페이지가 동일하게 보이고 정상적으로 작동하게 하려면 반드시 웹 표준을 지키는 HTML 문서로 작성을 하는 것이 당연하다.
  • 표준 HTML 구조를 작성하는 방법은 .html 파일을 생성한 다음 !를 작성하고 tab 버튼을 누르게 되면 자동으로 구조가 완성된다.
  • 하지만 모든 템플릿에 일일이 표준 HTML 구조를 적용시키는 것은 body 아래의 요소를 제외하고는 모두 같은 내용으로 중복된다.
  • 그렇게 되면 link 태그에서 CSS 파일 이름이 변경되거나 새로운 CSS 파일을 추가할 때마다 모든 템플릿을 일일이 수정해야하는 수고로움이 발생한다.
  • 타임리프는 이런 중복의 불편함을 해소하기 위해템플릿 상속 기능을 제공하고, 템플릿 상속은 기본 틀이 되는 템플릿을 먼저 작성하고 다른 템플릿에서 기본 템플릿을 상속해 사용하는 방법이다.
  • 먼저 기본 틀이 되는 공통 템플릿인 layout.html를 생성하여 아래와 같이 코드를 작성한다.
<!doctype html>
<html lang="ko">
<head>
    <!-- Required meta tags-->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS   -->
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css">

    <!-- sbb CSS -->
    <link rel="stylesheet" type="text/css" th:href="@{/style.css}">
    <title>Hello, sbb!</title>
</head>
<body>
    <!-- 기본 템플릿 안에 삽입될 내용 시작 -->
    <th:block layout:fragment="content"></th:block>
    <!-- 기본 템플릿 안에 삽입될 내용 끝 -->
</body>
</html>
  • 모든 템플릿이 상속해야하는 layout.html이기 때문에 <head> 태그 아래에 라이브러리나 프레임워크, 기본 스타일시트를 모두 이 곳에서 link 시켜주는 것이 좋다.
  • <body> 태그 안의 <th:block layout:fragment="content"></th:block>은 layout.html을 상속한 템플릿에서 개별적으로 구현해야 하는영역이 된다. 즉, layout.html 템플릿을 상속하면 해당 부분만 수정해도 표준 HTML 문서로 작성이 되는것이다.
  • 더 쉽게 말하자면 layout.html를 상속받는 다른 템플릿에서는 HTML 구조를 쓰지 않아도 fragment="content" 라는 속성값만 가지고 있으면 layout.html을 그대로 가져와 쓰는 것이랑 똑같다.

 

[공통 템플릿 상속받기]

  • 공통 템플릿인 layout.html를 각 템플릿에 상속하는 방법은 동일한데, 대표적으로 question_list.html에 추가된 모습을 아래 코드를 통해 살펴봅시다.
<html layout:decorate="~{layout}">
    <div layout:fragment="content" class="container my-3">
        (내용 생략...)
    </div>
</html>
  • layout.html을 상속하려고 <html layout:decorate="~{layout}">을 작성하였다.
  • 타임리프의 layout:decorate 속성은 템플릿의 레이아웃으로 사용할 템플릿을 설정한다. 속성값인 ~{layout}이 바로 위에서 만들어놨던 layout.html 파일을 의미한다.
  • 그리고 부모인 layout.html에서 작성했던 layout:fragment="content"도 자식 템플릿의내용으로 적용될 수 있게 사용하였다.
  • 다시 로컬 서버를 실행하여 list나 detail 페이지에 접속하게 되면 디자인이 바뀌거나 그렇지 않지만 F12를 통해 확인해보면 기존엔 적용하지 않았던 HTML 구조를 확인할 수 있다. 
반응형