はじめに
以下のように、<table>
内で<tbody>
をループして動的に生成するコードがあります。
データの切れ目がわかるように<tbody>
間に余白を設けたいのですが、margin
を指定しても効きません。
<script setup>
import { ref } from 'vue'
const userList = ref([
{ name: "John", age: 12 },
{ name: "Mike", age: 54 },
{ name: "Hanako", age: 23 }
])
</script>
<template>
<table>
<tbody v-for="(user, index) in userList" :key="index">
<tr>
<th>名前</th>
<td>{{ user.name }}</td>
</tr>
<tr>
<th>年齢</th>
<td>{{ user.age }}</td>
</tr>
</tbody>
</table>
</template>
<style scoped>
/* tbodyにmarginを指定しても効かない */
tbody {
margin-bottom: 1rem;
}
/* 後略 */
</style>
二番目以降の<tbody>
に疑似要素を指定することで上手くいったので、紹介します。
サンプルコードはVue.jsを用いていますが、本題では特にVue.jsに限定した機能は用いていません
疑似要素を用いた解決策
結論から示すと、以下で上手くいきます。
tbody:not(:first-of-type)::before {
content: "";
display: block;
height: 1rem;
}
解説
-
:first-of-type
- 兄弟要素の中の最初の1個
- 今回は最初の1個以外の上に余白が欲しいので、
:not
を指定
-
::before
- 実際のDOMにはないが、指定した要素の前に疑似的に要素を作り出す
-
content: "";
- 疑似要素を表示させるために必要。空で良い
-
display:block;
-
::befoe
はinline
なので高さを指定できるようにblock
に変更
-
-
height: 1rem;
- これで疑似的な余白を作成(remでなくてもOKです)
サンプルコード全体
サンプルコード全文
<script setup>
import { ref } from 'vue'
const userList = ref([
{ name: "John", age: 12 },
{ name: "Mike", age: 54 },
{ name: "Hanako", age: 23 }
])
</script>
<template>
<table>
<tbody v-for="(user, index) in userList" :key="index">
<tr>
<th>名前</th>
<td>{{ user.name }}</td>
</tr>
<tr>
<th>年齢</th>
<td>{{ user.age }}</td>
</tr>
</tbody>
</table>
</template>
<style scoped>
tbody:not(:first-of-type)::before {
content: "";
display: block;
height: 1rem;
}
/* tbodyにmarginを指定しても効かない */
/*
tbody {
margin-bottom: 1rem;
}
*/
/* 以下は装飾 */
table {
width: 100%;
max-width: 400px;
margin: 0 auto;
font-family: sans-serif;
background-color: #fdfdfd;
border-collapse: collapse;
}
th, td {
padding: 0.5rem;
vertical-align: top;
border: 1px solid #ccc;
}
th {
background-color: #f0f0f0;
width: 30%;
}
td {
background-color: #fff;
}
</style>
おわりに
<tbody>
の下に<span>
を作ったり色々試したのですが上手くいかず。なんとか解決して良かったです。
ちなみに、今回の本筋とは関係ないのですが、<tbody>
は複数作成しても良いらしいです。
連続していれば、1 つの表の中に複数の
<tbody>
を使用することができます。これにより必要に応じて、巨大な表の行を複数のセクションに分割し、個別に整形することができます。