🥨

Prettier で HTML を整形しただけでデザインが崩れることがある

2021/01/09に公開2

概要

コードフォーマッタの Prettier (v2.2.1) でコードを整形しただけで、Web上でのデザインが崩れてしまった事例を紹介します。

元 HTML

<body>
  <div class="content">
    <div class="div-a">A</div><div class="div-b">B</div>
  </div>
</body>

オリジナルの HTML は div 内に div が複数あるだけのシンプル構造です。

Prettier 適用後

<body>
  <div class="content">
    <div class="div-a">A</div>
    <div class="div-b">B</div>
  </div>
</body>

デフォルト設定の Prettier を HTML に実行すると、1行に複数の div を記述していた箇所が、改行で分割されます。

フォーマット前後でデグレが発生

フォーマッターを適用しただけなら挙動は変わらないと思い込んでいましたが、動作を確認してみると、フォーマット前後で以下のようなデグレが発生していました。

フォーマット前

フォーマット後

原因

A B が横並びで表示されている時点で察した方もいると思いますが、この HTML ファイルは以下のようなスタイルが適用されていました。

<style>
  .div-a,
  .div-b {
    display: inline;
  }
</style>

これによって、 .div-a .div-b は、インライン要素となってしまい、改行が半角スペースとして扱われるようになってしまいました。

Prettier から見れば、 div はブロック要素なのだから改行してフォーマットを整えても影響は無いと判断していたようです。

解決策

要素のデフォルトの display 属性を無闇矢鱈を変えるものじゃないなと学んだので、 display: inline の設定を削除し、横並びのスタイルを維持するために flex を活用するようにすることで、デザインを維持しながらコードのスタイルを自動修正できるようにしました。

<style>
  .content {
    display: flex;
  }
</style>

学んだこと

ただのフォーマッタだからって、プロジェクト全体に Prettier をまとめて実行すると事故ることがある。

  • 本業では、ここまで単純な話ではなく、入り組んだコードの中でこのような問題が意図せず発生していました
  • ちなみにスナップショットテストがちゃんと機能して差分を検知してくれたので、デグレがリリースされることはありませんでした。
GitHubで編集を提案

Discussion

catnosecatnose

この問題僕もときどきハマります。PrettierのオプションでhtmlWhitespaceSensitivity: "strict"にすれば、勝手にwhite-spaceができることはなくなるのですが、整形の結果がひどくなるのですよね…。
僕も今は「display 属性を無闇矢鱈を変えるものじゃないな」という感じで気をつけながら書いてます。

shingo.sasakishingo.sasaki

htmlWhitespaceSensitivity は初めて知りました!

確かに a のようなインライン要素だと、文字数的に改行したいけどスタイルは崩せないからやむを得ずっていう結果になってビックリしちゃうんですよねぇ。。

それもあって最近は Prettier がお気に召すようなコードを意識して書くようになって、ちょっと本末転倒だなとも感じちゃってます。