Figmaのデフォルト設定で作成したものを、HTMLで実装すると、ブラウザ描画時にズレて表示される事象について

TechCommit AdventCalendar2024の23日目の記事です。

https://adventar.org/calendars/10584

今回は表題の事象について説明いたします。

前提条件は以下の通りです。
* Figmaをデフォルト設定状態で使用する
* 有料の開発モードを使用していない

# ①Figmaで描いてみた
Figmaで日付の文字列を書いて、それを四角形で囲みました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/5cc76685-74d7-f0dd-3385-f38ad79edbbb.png" width="50% />

　
Figmaの構造は、以下のように、Frameの中に、テキストを内包しております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/78f1e28f-b8b6-abca-c4ad-2a4c451f8a98.png)


赤枠に注目すると、以下のことが分かります。
* 横幅は全体で71px
* 左右のpaddingは8px
* ボーダーは1px

# ②HTMLで描いてみた

Figmaの設定内容を参考に、HTMLを書いてみました。

```html
<style>
    .hoge {
      width: 71px;
      padding: 8px;
      border: solid 1px black;
      font-family:'Times New Roman';
      font-size:12px;
    }
  </style>
<div class="hoge">2024/12/15</div>
```
bodyタグ内の一部のみ表記しています。headタグで、CSSファイルを定義したり、読み込むことは行っておりません。

Chromeで開くと、以下のように表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/67fcbd4f-7418-c84b-a89b-409e415ab237.png" width="25% /><br /><br />

　
5の右側の余白が広く確保されています。
なぜ、こうなってしまったのでしょうか。

# CSSのbox-sizingプロパティ

CSSでは、box-sizingというプロパティがあります。
これは、指定された幅（今回は71px）をどのように確保するかをコントロールするものです。
https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing

デフォルト値の、content-boxの場合、コンテンツ領域（今回は日付の文字列のこと）に対して、71pxを割り当てて、それに加えて、padding（周囲8pxずつ）とborder（周囲1pxずつ）を付け足しています。

ブラウザの開発者ツールを使うと、その様子が分かります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/05a25357-b8a2-dc29-8f16-3c98b356d28c.png" width="50% />

　
トータルの横の長さは、1+8+71+8+1=89pxになりました。

box-sizingの値を、border-boxにすることで、paddingやborderを含んだ値で71pxが確保されるようになります。
そのように変更した結果が以下の通りです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/c2d19b46-8fcf-39d7-be60-ff835f84f7bd.png" width="50% />

　
これで問題が解決しているように見えます。

しかし、上の図をよく見ると、最後の5が、青いエリアの右端を突き破って、緑のエリアに入ってしまっていることが分かります。
これはコンテンツの領域がpaddingに入り込むことにより、実質的な（目に見える）右のpaddingが減ってしまったのです。

また、もし、ここのエリアの文字列が長い時は改行するという仕様があった場合は、以下のように表示されてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/6aa01c60-eb3d-23e4-2d19-8eb436c9b9fa.png)

（上図は、overflow-wrap: anywhere;を指定した場合）

CSSでは、overflow-wrapプロパティにて指定することができます。
https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap

# デフォルト設定でのFigmaのborderの扱い方

なぜ、このような現象が起きてしまうのでしょう。

理由は、Figmaはデフォルト設定の場合、borderがpadding領域を侵食する設定になっているためです。
以下の図では、左paddingの領域に、青い斜めの線が入っていますが、よく見ると、左の黒い線の上にもかかってしまっていることが分かります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/95aee231-6732-2774-9210-6875a51890f8.png" width="50% />

　
つまり、Figmaでは、paddingを8pxに設定したものの、描画上は、8 - 1 = 7pxでしか確保されていません。

それに対してブラウザ（少なくともChrome）では、borderとpaddingは完全に別領域であり、borderがpaddingの領域を侵食することがありません。

これにより、コンテンツ領域の横幅の差分が生まれます。

|| 全体の横幅 | （目にみえる）左右border |（目にみえる）左右padding | コンテンツ領域の横幅 |
|:-----------|------------:|------------:|------------:|------------:|
| Figma  | 71px | 1px | 7px(8-1) | 55px(71-1-7-1-7) |
| ブラウザ | 71px | 1px | 8px | 53px(71-1-8-1-8) |

日付文字列自体は、55px必要なのですが、ブラウザに描画すると2px不足するために、右のpadding領域を侵食したり、改行が入ってしまったわけです。

# Figmaで、borderがpadding領域を侵食しないように設定する。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/885e03a0-414d-84ce-7208-0fbe6fcccfa2.png" width="50% />

　
Figmaで四角形を選択し、「Auto layout」内の設定ボタン？を押し、開いたウィンドウ内の「Strokes」を「Excluded ~」から「Included ~」に変更することで、それを防ぐことができます。
（ややこしいことに、Figmaの右サイドメニューの下側に「Stroke」というプロパティがあるので、違いに注意しましょう。）

この設定を変更すると、Figma上の全体の横幅が、2px伸びて、73pxになりました。

# 改めてHTMLで実装

```html
<style>
    .hoge {
      width: 73px;
      padding: 8px;
      border: solid 1px black;
      font-family:'Times New Roman';
      font-size:12px;
      box-sizing: border-box;
      overflow-wrap: anywhere;
    }
  </style>
<div class="hoge">2024/12/15</div>
```

以下のように表示されました。Figmaの設定と一致しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680908/f725040d-3a99-a4cf-70c2-4be65b380e3b.png)

# 最後に

果たして、UIの設計や実装時に、ここまで気にする必要があるのか、疑問に思った方もいるかもしれません。

ピクセルパーフェクトの議論に近いものを感じます。
https://togetter.com/li/1595233

実装時には、「box-sizing:border-box;」は必要に応じて設定するとして、
UIデザイン時は、デフォルト設定のままFigmaで描きつつ、素人でも明らかにわかるような改行などが発生したら、その都度、Figma上でオブジェクトの横幅をもう少し広めに取る、などの方法も考えられます。