[SpringBoot + Thymeleaf] layoutを使用して各画面共通のhtmlを作成する

# はじめに
本記事で以下を解説。
* layoutタグを使用して「ヘッダー」「メニューバー」といった各画面共通のhtmlを適用する方法

以下のような流れで記載します。
1. layout作成サンプル用ページの画面構成把握
1. layout属性の概要と、属性の配置全体像の把握
1. layout属性の記述形式
1. layout適用のための準備作業
1. html、cssファイルの作成
1. 完成画面


# layout適用の構成イメージ
画面構成としては以下のような配置を目指す。
「コンテンツ」部分を画面ごとに切り替え、「ヘッダー」「メニューバー」「フッター」は固定で配置。

![画面レイアウト配置イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355023/1455b12a-dc3d-6b13-0977-d72c8d8682c8.png)


用意するhtmlは以下。
| ファイル名 | 用途 |
|:-:|:-:|
| layout.html  | レイアウトのベースとなるhtml。このhtmlにヘッダーやメニューバーを適用していく  |
| header.html  | ヘッダー用html  |
| menu.html  | メニューバー用html  |
| content.html  | コンテンツ用html  |
| footer.html  | フッター用html  |

# レイアウト用の属性など
適用する属性は以下です。
同じ要素名でも、layout.html（本記事ではベースファイルと呼称　※1）とそれ以外（本記事ではパーツファイルと呼称　※1）で記載する場合では意味が異なってくるので注意。

| 要素名 | 用途 |
|:-:|:-:|
| layout:replace  | べース側に記載。要素に指定されたhtmlでタグの内容を置き換える  |
| layout:fragment（ベース側）  | ベース側に記載。要素に指定されたhtmlをタグに追加する。  |
| layout:fragment（パーツ側）  | パーツ側に記載。ベースから参照するためのキー名を記載する  |
| layout:decorate  | パーツ側に記載。どのレイアウトにhtmlを組み込むかを指定　※2  |

※1 「ベース」「パーツ」は正式な名称ではなくあくまで本記事のみで区別するための名称。
※2 デフォルトでは「src/main/resources/templates」からの相対パスを指定。

全体像として、各htmlに記載する要素は以下のように記載。

![画面レイアウトhtml構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355023/b7ea7d6e-7083-c2e3-aaab-65c8fd6508e6.png)

# layout属性の記述形式

layout:replace

![layout属性_replace.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355023/b52263b1-7685-789b-a9d1-63825f35e0e0.png)

layout:fragment
ベース側とパーツ側で記述形式は同じ。
![layout属性_fragment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355023/f755e2b8-5057-a23d-e137-2b0ca6a5fbf4.png)

layout:decorate
![layout属性_decorate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355023/95ea9e0a-5a3e-f3d4-8f4e-ef442872364a.png)


# 準備
Thymeleafでlayout要素を使えるようにする。
```gradle:build.gradle
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
```

layoutを使う際はhtmlタグに以下定義を記載する。
```html:xxx.html
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
```

src/main/resources/templatesの配下に「layout」フォルダを作成し、各htmlファイルを作成して配置。
```
src/main/resources/templates
 - layout
  - layout.html
  - menu.html
  - content.html
  - footer.html
 ```

cssも作成。
```
src/main/resources/static/css
   - layout
    - css
     - layout.css
```

Contlloerの作成。「layout/content.html」に遷移するようにしておく。
```java:Controller.java
	@GetMapping()
	public String get(Model model) {
		return "layout/content";		
	}
```

# html作成

画面の配置などを調整する要素は必要最小限にとどめています。

layout.html
```html:layout.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">

<head>
<meta charset="UTF-8">

<!-- CSS読み込み -->
<link rel="stylesheet"
	th:href="@{/webjars/bootstrap/css/bootstrap.min.css}">
<link rel="stylesheet" th:href="@{/css/layout/layout.css}">

<title></title>
</head>

<body>

	<!-- ヘッダー -->
	<div>
		<div layout:replace="~{layout/header::header}"></div>
	</div>

	<!-- メニュー -->
	<div>
		<nav class="menu col-sm-2">
			<div layout:replace="~{layout/menu::menu}"></div>
		</nav>
	</div>

	<!-- コンテンツ -->
	<div>
		<nav class="main col-sm-10 offset-sm-2">
			<div layout:fragment="content"></div>
		</nav>
	</div>

	<!-- フッター -->
	<div>
		<div layout:replace="~{layout/footer::footer}"></div>
	</div>

</body>
</html>
```

header.html
```html:header.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="~{layout/layout}">

<head>
</head>

<body>
	<nav layout:fragment="header" class="header navbar navbar-fixed-top">
		<div>
			<a>ヘッダー部分</a>
		</div>
	</nav>
</body>
</html>
```
menu.html
```html:menu.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="~{layout/layout}">

<head>
</head>

<body>
	<div layout:fragment="menu">
		<ul class="nav">
			<li role="presentaion"><a>メニュー項目部分</a></li>
		</ul>
	</div>
</body>
</html>
```
content.html
```html:content.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="~{layout/layout}">

<head>
<title>レイアウトテスト用ページ</title>
</head>

<body>
	<div layout:fragment="content">
		<div>
			<a>コンテンツ部分</a>
		</div>
	</div>
</body>

</html>

```
footer.html
```html:footer.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="~{layout/layout}">

<head>
</head>

<body>

	<nav layout:fragment="footer" class="footer navbar fixed-bottom">
		<div>
			<a>フッター部分</a>
		</div>
	</nav>
</body>
</html>
```

# css作成

画面の配置などを調整する要素は必要最小限にとどめています。

```css:layout.css
.header{
	border:2px solid;
}

.menu{
	position:fixed;
	display:block;
	top:58px;
	bottom:0;
	left:0;
	border:2px solid;
	margin-bottom:58px;
}
	
.main{
	position:fixed;
	display:block;
	bottom:0;
	top:58px;
	margin-bottom:58px;
	padding-left:20px;
	border:2px solid;
}

.footer{
	border:2px solid;
}
```

# 完成画面
![レイアウト完成画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355023/33a4ab90-5aad-a802-f399-3d40b65f1ed3.png)