HTMLメール: cellpadding, cellspacingは余白の実装手段となり得るか

## はじめに
HTMLメールでは`table`タグに`cellspacing="0"` `cellpadding="0"`を設定して意図しない余白が入らないように制御するのが一般的。
一方で、`td`には`padding`を適用できるが、HTMLメールにおいてはタグやメーラーなどの環境ごとに余白が意図通りに適用されないケースがある。
余白を実装する選択肢として`padding`やスペーサー画像を使う代替手段として、`cellspacing` `cellpadding`の属性による指定が有効なのかを試してみた。

### 結論
`cellspacing` `cellpadding`は0で指定して使うことが多いが、**上下左右同じ余白**など場合によっては有効に活用ができる場面もありそうではある。

## 検証
### `table`に`cellpadding`を適用
![cellpadding10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/1cf47815-c097-97d4-565b-80ca9aa5ef53.png)

- `td`に`padding`を記述せずとも、内部の上下左右に余白が適用される

```html
<table width="100%" border="0" cellpadding="10" cellspacing="0">
  <tr>
    <td valign="top" align="left" style="background-color:#0ff;">
      tableにcellpadding="10"を指定した場合<br>
      子要素のtd内部の上下左右に余白が適用される
    </td>
  </tr>
</table>
```

### `table`に`cellspacing`を適用
![cellspacing10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/45188c43-f307-b156-0cb6-31321a88b88f.png)

- `td`の外部の上下左右に余白が適用される

```html
<table width="100%" border="0" cellpadding="0" cellspacing="10">
  <tr>
    <td valign="top" align="left" style="background-color:#ff5;">
      tableにcellspacing="10"を指定した場合<br>
      子要素のtd外部の上下左右に余白が適用される
    </td>
  </tr>
</table>
```

### `table`に`cellpadding`と`cellspacing`の両方を適用

![cellpadding_cellspacing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/3d1accc1-1da1-d218-d476-bcb9721b6d23.png)

- `td`の内部、外部それぞれに上下左右に余白が適用される

```html
<table width="100%" border="0" cellpadding="10" cellspacing="10">
  <tr>
    <td valign="top" align="left" style="background-color:#0ff;">
      tableに<br>
      cellpadding="10"とcellspacing="10"を指定した場合<br>
      子要素のtd内部・外部それぞれの上下左右に余白が適用される
    </td>
  </tr>
</table>
```

### `table`に`cellpadding`と`cellspacing`の両方を適用(tdが複数の場合)
![cellpadding_cellspacing2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/86755786-be99-6f18-dc61-f9a753f5ada3.png)

- `td`の内部、外部それぞれに上下左右に余白が適用される
- `td`間の間隔も一様に余白が適用される

```html
<table width="100%" border="0" cellpadding="15" cellspacing="10"
  style="width: 100%; background-color: #008eef; max-width: 100%;">
  <tr>
    <td valign="top" align="left" style="background-color:#ff5; width: 200px;">
      tdを200px<br>
      tableに<br>
      cellpadding="15",<br>
      cellspacing="10"
    </td>
    <td valign="top" align="left" style="background-color:#0ff; width: 200px;">
      tdを200px<br>
      tableに<br>
      cellpadding="15",<br>
      cellspacing="10"
    </td>
    <td valign="top" align="left" style="background-color:#ff5; width: 200px;">
      tdを200px<br>
      tableに<br>
      cellpadding="15",<br>
      cellspacing="10"
    </td>
  </tr>
</table>
```

## 上記を踏まえて実装したもの
### Gmail(Mac Chrome)
- Mac OS: 13.5.1
- Chrome: バージョン 119.0.6045.199
![Mac_Chrome_gmail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/9b1582f4-b121-a163-1da1-09555b9e8b95.png)
### Gmail(iOS アプリ)
- iOS: 16.6.1
- Gmail: Version 6.0.231001
![iOS_gmail_app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/eee04586-6820-2947-6c8c-db875b174391.png)

### Outlook(Windows デスクトップアプリ)
- Windows 10
- Outlook: バージョン 2302

※ボタンの`a`タグの余白が効いていないが、今回の検証対象は`table`, `td`に絞るため割愛
![Windows_outlook.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/b3cf67a2-6f25-fe6c-3c48-9b30c89e8be6.png)

## 全体の大枠の構成
### 一番外側(祖先要素)のtableタグ
- `width="100%"`
- `cellspacing="0"`
- `cellpadding="0"`
- `max-width: 600px;`

```html
<!DOCTYPE html>
<html>

<head>
  <title></title>
</head>

<body>
  <table width="100%" cellspacing="0" cellpadding="0" style="max-width: 600px; margin: auto; font-family: sans-serif; font-size: 16px;">
    <!-- ヘッダー -->
    <tr>
    </tr>

    <!-- メインコンテンツ -->
    <tr>
    </tr>

    <!-- フッター -->
    <tr>
    </tr>
  </table>
</body>

</html>
```

## ヘッダー、メインコンテンツ、フッター
- それぞれ`tr`, `td`で構成
### ヘッダー、フッター
- いずれもtrの中に`td`という構成。
- 余白: `td`に`padding`を適用。

#### ヘッダー
![header.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/b1ad78e0-a246-9c9b-d5bd-2215beeda15a.png)

```html
<tr>
  <td style="padding: 20px; text-align: center; background-color: #bc9147; color: #ffffff; font-size: 24px; font-weight: bold; font-family: serif;">
    虹箱洋菓子店 おすすめ商品
  </td>
</tr>
```
#### フッター
![footer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/9d27573d-f707-ceb0-6420-49a61b911388.png)

```html
<tr>
  <td style="padding: 20px; text-align: center; background-color: #777; color: #ffffff;">
    &copy; 2023 虹箱洋菓子店 All rights reserved.
  </td>
</tr>
```
### メインコンテンツ
※商品3カラム部分の解説は割愛

![main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/a499a0ad-e1bf-01ff-e83e-2b575c0730e1.png)

#### 外側の大枠

- 商品2カラム、3カラムのエリアをそれぞれ個別の`table`で実装
- 上記のtableには`cellspacing="10"` `cellpadding="0"`
- これにより、商品ごとのカードUI同士は垂直方向にも水平方向にも10pxの間隔を空けることができる。
    - ※ただし、商品間の間隔の余白と、一番外側の余白部分で異なる値を当てる場合は`cellpadding`だと柔軟性に欠けるので不適。別途スペーサー画像などでの対応が必要になる。

```html
    <!-- メインコンテンツ -->
    <tr>
      <td style="background-color: #ffe76f;">
        <table width="100%" cellspacing="10" cellpadding="0">
          <tr>
          <!-- 商品　2カラム -->
          </tr>
        </table>
        <table width="100%" cellspacing="10" cellpadding="0" style="background-color:#bc9147; font-size: 12px;">
          <tr>
            <!-- 商品　3カラム -->
          </tr>
        </table>
      </td>
    </tr>
```

#### 商品2カラム部分の大枠

![2column.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/5f2b3e3a-3631-a4d7-862f-6d280302dd5f.png)

- 1つの`tr`内に`td`を2つずつ
    - `width="50%"`
    - `padding: 10px;`
    - tr内にtdが一つしかない場合は左寄せになり、右側は空く
```html
<table width="100%" cellspacing="10" cellpadding="0">
  <!-- 商品行 -->
  <tr>
    <!-- 商品1 -->
    <td align="center" width="50%" valign="top" style="padding: 10px; background-color: #fffde4;">
      <!-- 商品1　中身 -->
    </td>

    <!-- 商品2 -->
    <td align="center" width="50%" valign="top" style="padding: 10px; background-color: #fffde4;">
      <!-- 商品2　中身 -->
    </td>
  </tr>
  <tr>
    <!-- 商品3 -->
    <td align="center" width="50%" valign="top" style="padding: 10px; background-color: #fffde4;">
      <!-- 商品3　中身 -->
    </td>

    <!-- 商品4 (省略) -->
  </tr>
  <!-- 他の商品行（省略） -->
</table>
```
#### 商品2カラムの詳細(特に画像下部のエリアについて)

![detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256600/b3d65dab-0c83-8364-97a7-c2b0b1d5e3fa.png)

- `table`
    - `width="100%"`
    - `cellspacing="10"`
        - 子要素の`td`同士に10pxの間隔が開く
            - この例だと、画像・商品名・価格・商品説明・ボタンが互いに10px間隔で配置されている
    - `cellpadding="0"`

※今回の検証対象は`table`, `td`に絞るため、ボタンの`a`タグについては解説を割愛

```html
<td align="center" width="50%" valign="top" style="padding: 10px; background-color: #fffde4;">
  <img src="https://placehold.jp/F7DC7F/777/300x300.png?text=image" alt="カヌレ" width="100%" style="width: 100%;">
  <table width="100%" cellspacing="10" cellpadding="0">
    <tr>
      <td>
        <p style="margin: 0; color: #333; text-align: left; font-weight: bold; font-size: 20px;">カヌレ</p>
      </td>
    </tr>
    <tr>
      <td>
        <p style="margin: 0; color: #333;">500円(税込)</p>
      </td>
    </tr>
    <tr>
      <td>
        <p style="margin: 0; color: #333;">商品説明: こだわりの小麦粉と卵を使用しています。</p>
      </td>
    </tr>
  </table>
  <table width="100%" cellspacing="0" cellpadding="0">
    <tr>
      <td style="background-color: #FFA726; text-align: center;">
        <a href="https://www.google.co.jp/" width="100%" style="display: block; text-decoration: none; padding: 10px; color: #ffffff;">
          詳細を見る
        </a>
        </td>
      </tr>
    </table>
</td>
```

## 全体のコード
- 解説を割愛した商品3カラム部分も含めた全体のコードは以下を参照
<details>
  <summary>全体のコードはこちら</summary>

```html
<!DOCTYPE html>
<html>

<head>
  <title></title>
</head>

<body>
  <table width="100%" cellspacing="0" cellpadding="0" style="max-width: 600px; margin: auto; font-family: sans-serif; font-size: 16px;">
    <!-- ヘッダー -->
    <tr>
      <td style="padding: 20px; text-align: center; background-color: #bc9147; color: #ffffff; font-size: 24px; font-weight: bold; font-family: serif;">
        虹箱洋菓子店 おすすめ商品
      </td>
    </tr>

    <!-- メインコンテンツ -->
    <tr>
      <td style="background-color: #ffe76f;">
        <table width="100%" cellspacing="10" cellpadding="0">
          <!-- 商品行 -->
          <tr>
            <!-- 商品1 -->
            <td align="center" width="50%" valign="top" style="padding: 10px; background-color: #fffde4;">
              <img src="https://placehold.jp/F7DC7F/777/300x300.png?text=image" alt="カヌレ" width="100%" style="width: 100%;">
              <table width="100%" cellspacing="10" cellpadding="0">
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; text-align: left; font-weight: bold; font-size: 20px;">カヌレ</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333;">500円(税込)</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333;">商品説明: こだわりの小麦粉と卵を使用しています。</p>
                  </td>
                </tr>
              </table>
              <table width="100%" cellspacing="0" cellpadding="0">
                <tr>
                  <td style="background-color: #FFA726; text-align: center;">
                    <a href="https://www.google.co.jp/" width="100%" style="display: block; text-decoration: none; padding: 10px; color: #ffffff;">
                      詳細を見る
                    </a>
                    </td>
                  </tr>
                </table>
            </td>

            <!-- 商品2 -->
            <td align="center" width="50%" valign="top" style="padding: 10px; background-color: #fffde4;">
              <img src="https://placehold.jp/F7DC7F/777/300x300.png?text=image" alt="フィナンシェ" width="100%" style="width: 100%;">
              <table width="100%" cellspacing="10" cellpadding="0">
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; text-align: left; font-weight: bold; font-size: 20px;">フィナンシェ</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333;">500円(税込)</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333;">商品説明: こだわりの小麦粉と卵を使用しています。こだわりの小麦粉と卵を使用しています。</p>
                  </td>
                </tr>
              </table>
              <table width="100%" cellspacing="0" cellpadding="0">
                <tr>
                  <td style="background-color: #FFA726; text-align: center;">
                    <a href="https://www.google.co.jp/" width="100%" style="display: block; text-decoration: none; padding: 10px; color: #ffffff;">
                      詳細を見る
                    </a>
                    </td>
                  </tr>
                </table>
            </td>
          </tr>
          <tr>
            <!-- 商品3 -->
            <td align="center" width="50%" valign="top" style="padding: 10px; background-color: #fffde4;">
              <img src="https://placehold.jp/F7DC7F/777/300x300.png?text=image" alt="マドレーヌ" width="100%" style="width: 100%;">
              <table width="100%" cellspacing="10" cellpadding="0">
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; text-align: left; font-weight: bold; font-size: 20px;">マドレーヌ</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333;">500円(税込)</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333;">商品説明: こだわりの小麦粉と卵を使用しています。</p>
                  </td>
                </tr>
              </table>
              <table width="100%" cellspacing="0" cellpadding="0">
                <tr>
                  <td style="background-color: #FFA726; text-align: center;">
                    <a href="https://www.google.co.jp/" width="100%" style="display: block; text-decoration: none; padding: 10px; color: #ffffff;">
                      詳細を見る
                    </a>
                    </td>
                  </tr>
                </table>
            </td>

            <!-- 商品4 -->
          </tr>
          <!-- 他の商品行（省略） -->
        </table>
        <table width="100%" cellspacing="10" cellpadding="0" style="background-color:#bc9147; font-size: 12px;">
          <tr>
            <!-- 商品1 -->
            <td align="center" width="33%" valign="top" style="padding: 10px; background-color: #fffde4;">
              <img src="https://placehold.jp/F7DC7F/777/300x300.png?text=image" alt="カヌレ" width="100%" style="width: 100%;">
              <table width="100%" cellspacing="10" cellpadding="0">
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; text-align: left; font-weight: bold; font-size: 16px;">カヌレ</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; font-size: 12px;">500円(税込)</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; font-size: 12px;">商品説明: こだわりの小麦粉と卵を使用しています。</p>
                  </td>
                </tr>
              </table>
              <table width="100%" cellspacing="0" cellpadding="0">
                <tr>
                  <td style="background-color: #FFA726; text-align: center;">
                    <a href="https://www.google.co.jp/" width="100%" style="display: block; text-decoration: none; padding: 10px; color: #ffffff;">
                      詳細を見る
                    </a>
                    </td>
                  </tr>
                </table>
            </td>

            <!-- 商品2 -->
            <td align="center" width="33%" valign="top" style="padding: 10px; background-color: #fffde4;">
              <img src="https://placehold.jp/F7DC7F/777/300x300.png?text=image" alt="フィナンシェ" width="100%" style="width: 100%;">
              <table width="100%" cellspacing="10" cellpadding="0">
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; text-align: left; font-weight: bold; font-size: 16px;">フィナンシェ</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; font-size: 12px;">500円(税込)</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; font-size: 12px;">商品説明: こだわりの小麦粉と卵を使用しています。こだわりの小麦粉と卵を使用しています。</p>
                  </td>
                </tr>
              </table>
              <table width="100%" cellspacing="0" cellpadding="0">
                <tr>
                  <td style="background-color: #FFA726; text-align: center;">
                    <a href="https://www.google.co.jp/" width="100%" style="display: block; text-decoration: none; padding: 10px; color: #ffffff;">
                      詳細を見る
                    </a>
                    </td>
                  </tr>
                </table>
            </td>

            <!-- 商品3 -->
            <td align="center" width="33%" valign="top" style="padding: 10px; background-color: #fffde4;">
              <img src="https://placehold.jp/F7DC7F/777/300x300.png?text=image" alt="マドレーヌ" width="100%" style="width: 100%;">
              <table width="100%" cellspacing="10" cellpadding="0">
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; text-align: left; font-weight: bold; font-size: 16px;">マドレーヌ</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; font-size: 12px;">500円(税込)</p>
                  </td>
                </tr>
                <tr>
                  <td>
                    <p style="margin: 0; color: #333; font-size: 12px;">商品説明: こだわりの小麦粉と卵を使用しています。</p>
                  </td>
                </tr>
              </table>
              <table width="100%" cellspacing="0" cellpadding="0">
                <tr>
                  <td style="background-color: #FFA726; text-align: center;">
                    <a href="https://www.google.co.jp/" width="100%" style="display: block; text-decoration: none; padding: 10px; color: #ffffff;">
                      詳細を見る
                    </a>
                    </td>
                  </tr>
                </table>
            </td>
          </tr>
        </table>
      </td>
    </tr>

    <!-- フッター -->
    <tr>
      <td style="padding: 20px; text-align: center; background-color: #777; color: #ffffff;">
        &copy; 2023 虹箱洋菓子店 All rights reserved.
      </td>
    </tr>
  </table>
</body>

</html>
```
  
</details>

## まとめ
- HTMLメールでは`table`タグに`cellspacing="0"` `cellpadding="0"`を設定して意図しない余白が入らないように制御するのが一般的
- `td`には`padding`が適用できるが、HTMLメールにおいてはタグやメーラーなどの環境ごとに余白が意図通りに適用されないケースがある
- `table`タグに`cellspacing`で値を適用した場合
    - 子要素の`td`外部の上下左右に余白が適用される
    - `td`が複数ある場合はtd同士の間隔にもその値が適用される
        - `gap`に少し似た振る舞いをする
- `table`タグに`cellpadding`で値を適用した場合
    - 子要素の`td`内部の上下左右に余白が適用される
    - `td`には`padding`が適用できるので、上下左右違う値を適用したい場合は`padding`の方が適してそう
- `cellspacing` `cellpadding`は0で指定して使うことが多いが、**上下左右同じ余白**など場合によっては有効に活用ができる場面もありそうではある。今回の挙動の確認を通して、実装の選択肢の一つになり得ることがわかった。