MJMLを使ってHTMLメールを作る

急にHTMLメールを作らないといけなくなったときに調べたことのメモ

# MJML
https://mjml.io/
様々なメーラーに対応したHTMLメールフレームワーク
知見がなくても崩れの心配をしないで書くことができた。

## 用意されているコンポーネント
https://mjml.io/documentation/#components
defalutがn/aなプロパティは反映されない。

### mj-section
基本は塊（mj-section, mj-column）を積んでいく。

```
<mj-section>
  <mj-column>
    // content
  </mj-column>
</mj-section>
```
### mj-column
mj-section内にmj-columnを複数置くと横並びになる。
スマホ幅では縦積み。
mj-columnにはwidthを設定できる。

```
<mj-section>
  <mj-column width="400px">
    // left
  </mj-column>
  <mj-column width="200px">
    // right
  </mj-column>
</mj-section>
```

### mj-group
スマホ幅でも横並びにしたいときはmj-groupで囲む。
このとき幅は％で指定する。

```
<mj-section>
  <mj-group>
    <mj-column width="30%">
      // left
    </mj-column>
    <mj-column width="70%">
      // right
    </mj-column>
  </mj-group>
</mj-section>
```

### mj-image
親の幅を超えたwidthを指定しても計算していい感じにしてくれる。

```
<mj-section padding="20px">
  <mj-column padding="20px">
    <mj-image width="600px" src="image.png" />
  </mj-column>
</mj-section>
```
mj-bodyのwidth指定が600pxの場合、mj-imageは例えば次のように出力される。

```
<td style="width:520px;">           
  <img height="auto" src="image.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;" width="520">
</td>
```
hrefを設定すると画像リンクにもなる。

### mj-text
本文はこのタグに放り込む。
中ではHTMLタグを書くことができる。

```
<mj-section>
  <mj-column>
    <mj-text>
      <h1>
        Hey Title!
      </h1>
    </mj-text>
  </mj-column>
</mj-section>
```

### mj-wrapper
余白やボーダーで要素をグルーピングしたいときに使う。

```
<mj-wrapper border="1px solid #000000" padding="50px 30px">
  <mj-section>
    <mj-column>
        // content
    </mj-column>
  </mj-section>
  <mj-section>
    <mj-column>
        // content
    </mj-column>
  </mj-section>
</mj-wrapper>
```

### mj-navbar
サンプル(スマホ幅でハンバーガーメニューになる)
https://mjml.io/try-it-live/templates/racoon
JSを使わずinputタグを使って開閉をコントロールしている。
Webメールなど一部の環境ではハンバーガーがうまく表示されないものがあるのに注意。

### mj-accordion
サンプル
https://mjml.io/try-it-live/components/accordion
JSを使わずinputタグを使って開閉をコントロールしている。
> The elements of the accordion are unwrapped by default as the email client doesn't support interactions to wrap and unwrap them.

とあるように、Webメールなど一部の環境ではアコーディオンが開いたままで表示されてしまう。

### etc.
他にもいろいろある。

## 自分が使う上でのルール
* mj-text, mj-imageで実現できないかまず考える。それ以外は使ってもmj-table, mj-buttonくらいに留める。
* mj-imageで実現できない画像の使い方はしない（メーラーによってimgタグの周りに余白ができてしまうなどするので生のimgタグは書かない）。
* mj-textの中身はシンプルなタグ構造を心がける。モダンブラウザで慣れた書き方はしない。いろいろ諦める。
* 幅や行間などの構造はmjタグにプロパティで指定できる範囲でやる（classを使えばいろいろ指定できるが、計算に反映されないときがあるため)。


## モバイルファーストで作る
メディアクエリを使えば画面幅によってスタイルの切り替えは可能だが、メディアクエリに対応していないメーラーも多い。
また、メーラーは2カラム、3カラムのものが多く、メール表示領域が狭い。
メーラーはPC幅だが領域はスマホ幅以下、段落ちしてしまうケースが多々発生する。
PC幅でのデザインはおまけ程度に考えて、段落ち前提（縦積み）でデザインしておいたほうがよい。

そもそもMJML自体がモバイルファースト思想で作られている。
https://mjml.io/documentation/#mjml-section
> `direction` attribute to `rtl` to change the order in which columns display on desktop. Because MJML is mobile-first, structure the columns in the order you want them to stack on mobile, and use `direction` to change the order they display on desktop.

mj-text内のHTMLにつけるスタイルも、
スマホビューを作る→メディアクエリでPCビューを作る
という順に進めると全体で調和がとれてよい。

## TIPS
### IEでだけリンクが画面からはみ出てしまう
リンクの親要素に
`word-break: break-all;`
をつければよい。

mj-columnによって生成されるtd要素には
`word-break: break-word;`と指定されているのだが、これはIEだけサポートされていない。
※ 正しくは、標準外だがChrome等ではサポートされている。
https://caniuse.com/#feat=word-break
> Chrome, Safari and other WebKit/Blink browsers also support the unofficial break-word value which is treated like word-wrap: break-word.

### テキストが中央揃え（または右揃え）にならない
一番下のmjタグにalignプロパティをつける。

```
<mj-text align="center">
<mj-image align="right">
```

mj-sectionにtext-alignプロパティが用意されてはいるが、
その内部でmj-imageやmj-textを使えば、そのタグがデフォルトで持っているtext-align: leftが有効になってしまう。

mj-section配下には何かしらmjタグを指定する必要があるので、mj-sectionのtext-alignプロパティはほとんどの場合意味がない。

### mj-classを使うときの注意
mj-sectionやmj-columnに付与するmj-classにはpaddingは設定しないほうがよい。
mj-sectionやmj-columnは出力時にwidthの計算をしているが、その計算にmj-classの値が考慮されないため、崩れてしまう。人が計算すれば調整もできるが事故の元。

### 画像の切り替え
mj-imageにsrcsetを使えるが、Webメールではたいてい機能しないので、切り替わらなくても成立するデザインを心がける。
Retina対応をする分にはsrcsetはありがたい。しかしどんな環境でも絶対にきれいに見せたい画像は、はじめから2倍サイズにしておくのがよい。

## 感想
便利でした。