82人がいいねしました
更新日
【保存版】Perfect Pixelを使ってピクセルパーフェクトを実現する手順&デザインとの“ズレあるある6つ”の解決法
ピクセルパーフェクトの位置付けについて
個人的には「あくまで手段の1つ。1pxのずれもなくコーディングすることが目的ではなく、デザインのルールに則った実装ができているかのチェック手段」という位置付けで良いと思っています。
そのため本記事では、まずPerfect Pixelを使用して“ズレをチェックし解決する方法”を解説しますが、記事の最後ではどこまでデザインに合わせるべきかの考え方もお話ししています。
ゴールとして、自分なりのピクセルパーフェクトへの向き合い方を持ってもらえればOKです!
そもそもピクセルパーフェクトって何?
ピクセルパーフェクトとは「デザインデータ」と「コーディングデータ」見た目の数値(px)のズレがないようにすることです。
以下は今回紹介する方法でデザインデータとコーディングデータを重ねて表示したものですが、メインコピー部分が大きくずれていますよね。

このズレを解消し、デザインデータとコーディングデータでずれのないようにコーディングすることを「ピクセルパーフェクト」と呼びます。
今回は以下の順で解説していきます。
- 【導入編】Perfect Pixelをダウンロード
- 【準備編】素材の用意とPerfect Pixelのセッティング
- 【実践編_初級】実際のデータをもとにズレを修正
- 【実践編_中級】デザイン通りコーディングしているのにズレる6つの“あるある”
- 【考え方編】ピクセルパーフェクトの捉え方
- 【結論編】デザインに合わせる・合わせないケース
【導入編】Perfect Pixelをダウンロード

「Perfect Pixel」はChromeの拡張機能の1つです。Chrome以外のブラウザでもアドオンが提供されいるようですが、今回は全てのChrome環境で解説します。
ローカルファイルの利用を許可する
デフォルトでは「デスクトップ」フォルダ等のローカルファイルでの起動ができません。これだと少々不便なので有効化していきます。
Chromeの検索バーに「chrome://extensions」と入力してページを開くと以下のように現在インストールしている拡張機能の一覧が並びます。Perfect Pixelの「詳細」を開きます。

下記のようにシークレットモードでの実行とファイルのURLへのアクセスを許可しましょう。

【準備編】素材の用意とPerfect Pixelのセッティング
❶デザインデータからページ全体の画像をダウンロード
Figmaで書き出す場合
Figmaで書き出したいデザインデータのフレーム全体を選択し綺麗な画像で比較するために「2x(2倍サイズ)」で書き出しを行いまます。

XDで書き出す場合
XDの場合もほとんど同じです。出力したいページのアートボードを選択し、

「書き出し」→「選択したアートボード」で「書き出しサイズ」を2xで書き出します。

❷Perfect Pixelへアップロードしサイズを調整
こちらの手順は少し複雑なので動画を用意しました。動画で行っている手順は以下の通りです。
- 00:00〜:拡張機能を起動し画像をアップロード
- 00:11〜:2倍サイズで書き出しをしたので0.5(2分の1)で表示されていることを確認
- 00:16〜:スクロールすると透明度が動いてしまうので「鍵アイコンでロック」
- 00:25〜:デザインカンプが1440pxなのに対し、ブラウザサイズが1512pxであるため縦軸がずれている。デベロッパーツールで表示サイズを1440pxにすることで縦軸が揃い、ズレが明確になる。
色を反転して見やすくする

重ねた画像の色を反転してより見やすくすることもできます。デザインによっては微妙なズレが確認しにくくなるので個人的には通常の状態で良いと思います。
【実践編_初級】実際のデータをもとにズレを修正
それでは実際のページを使っていくつかのズレを調整していきましょう。基本的には上の要素から順に下に向かって余白やサイズ感を調整していきます。

STEP01
ズレている要素のCSSをデベロッパーツールで確認

コピーがずれていますが、これは余白が関係していそうです。その要素に対してついている余白を見てみると…

上に100px
、下に120px
の余白がついています。
STEP02
実際のデザインデータの余白を確認

しかし、実際のFigmaのデザインデータを確認すると…
コピーの上の余白は120pxになっています。
これを試しにデベロッパーツール上で変更してみると
STEP03
デザインデータと値を揃えて再度確認

ボタンは依然としてズレていますが、キャッチコピー部分はピッタリと揃えることができました!
このように1pxもズレがなくなると重ねていることがわからないレベルで一致します。
OKであれば実際のCSSファイルへ変更を反映させましょう。
かなり簡単な例ではありますが、基本的にこのようにフォントサイズ、余白、要素の横幅、高さに目を光らせつつデザインデータと照らし合わせて調整を繰り返していきます。
【実践編_中級】デザイン通りコーディングしているのにズレる6つの“あるある”
ここからが本題と言っても過言ではありません。
なぜならPerfect Pixelを用いてピクセルパーフェクトを目指そうとした場合、次のようなパターンに出くわすと、必ず「デザインと数値が合ってるのになんで合わないんだ…orz」と手が止まってしまうからです。
対応すべきかどうかは最後にまとめます
対応を求められた時の原因の見つけ方と解決方法をまず解説します。中にはそもそもピクセルパーフェクトまでして対応しなくても良いものも含まれていますが、主観を含んでしまうので最後にまとめます!
あるある1|font-familyが違う

例えば、こちらのボタンはfont-size
やpadding
はデザインデータと正しいですが、font-family
の種類が違うことによりズレが発生しています。
正しいパターン

間違ったパターン

とりわけ英語フォントだと気づきにくいので、そもそもフォントが合っているかを確認してみましょう。
あるある2|一行の文字に行間がついている


複数行になることが想定されないテキストに対しても、デザインデータ上で行間が設定されている場合があります。その場合はテキストにline-height
を追加することでピッタリ揃えることができます。
あるある3|XDとWebで行間の付き方が異なる
この問題がもっとも根深い問題でありWebデザインがXDで行われるうちはデザイナー・コーダーの双方がこの仕様を理解しておく必要があります。

例えば文字サイズ16pxに対して、行間を文字1文字分(=line-height:2
)に設定した左のような文章があるとします。


文字サイズも行間も同じなのに、XDよりもWebの方が上に余白が多く下にズレていますよね。
これはXDとWebではCSSでは行間の付き方が異なることが原因で起こります。


XDの場合、文字の下に対して16px
の行間が付きますが、CSSで装飾した場合は16px / 2 = 8px
が上下に均等につく形でline-height: 2
が再現されます。
つまり、本来設定したい行間の半分ずつが上下につくことで再現されているということです。
ハーフ・レディング(half-leading)について

Webの行間は「要素に設定された行間(32px)から文字サイズ(16px)を引いて、その値を2で割った数値(8px)を上下に割り振る」という計算式でついています。
このように「レディング(行間)が半分ずつつく」ことからWebでの行間に付き方をハーフ・レディングと呼びます。
ネガティブマージンを使用してハーフ・レディングを解決
対応としてはとてもシンプルでハーフ・レディング分の行間を逆方向のマージン(ネガティブマージン)で打ち消してあげればOKです。

p{
font-size: 16px;
line-height: 2;
margin-top: -8px;
margin-bottom: -8px;
}
実際にPerfect Pixelを使用してハーフ・レディングの調整前後で比較したものが以下です。


SCSSを使えば計算を自動化できますが今回は長くなるので割愛させてもらいます…
あなたがデザイナーならFigmaに乗り換えるのが早い
FigmaはそもそもWebデザインを作成するために作られたツールであるため、ハーフ・レディングを気にする必要なくデザインを作成することができます。個人的にはXD→Figmaへの移行で困ったことはなく、むしろ効率化に繋がったことの方が多いため、これまでFigmaを敬遠していた人はぜひお試しを。
あるある4|テキストの最後の文字に字間がついている
以下のように高さやサイズ感は合っているものの、X軸(左右)がズレてしまうケースがあります。

これはデザインデータとCSSのletter-spacing
の字間の付き方の違いによって起こります。

デザインデータでは字の間にだけ設定した字間がつくのに対して、CSSのletter-spacing
は最後の文字の右隣にも字間がついてしまいます。


もっとわかりやすい例でいえば、左のような例の場合、右側の余白の方が多くなってしまっていますよね。
最後の文字の字間を打ち消す
解決するには、最後の文字の字間分のpadding
を左側につけるという方法があります。
<a class="button">
<img src="img/contact__icon.svg" alt="お問い合わせボタンのアイコン">
contact
</a>
.button{
/*説明に関係のあるCSSだけ抜粋*/
font-size: 80px;
letter-spacing: 0.2em;
padding: 30px 0 30px 0.2em; /*左側に字間分の余白を追加して揃える*/
}

テキストにspan
(擬似要素でもOK)を追加しネガティブマージンを設定する方法があります。
<a class="button">
<img src="img/contact__icon.svg" alt="お問い合わせボタンのアイコン">
<span>contact</span>
<!-- ネガティブマージンを適用したいテキストをspanの入れ子に -->
</a>
.button{
font-size: 80px;
letter-spacing: 0.2em;
padding: 30px 0;
}
.button span{
margin-right: 0.2em; /*右側の字間分の余白をネガティブマージンで打ち消す*/
}
あるある5|ボーダーが内側についている
font-size
もpadding
も合っているのに、ボックスの高さがずれてしまうケース。

よく見るとボックスの下部がズレていますよね。
これは「デザインデータの線がボックスの内側」についてしまっている場合に起こるケースです。
以下が実際のデザインデータですが、上下の余白が30px取られており、3pxの白い線が引かれています。


一見何の問題もないように思えますよね。
しかし、よく見てみると「30」という余白は白い線を含めてついていることがわかります。
つまり、線の3pxを除いた、27pxずつが本来設定されている余白ということになります。

ボックスモデルでは必ずpadding
の外にborder
がつくため、内側に線がつくことはありません。
そのため、左記のようにpadding
を設定することでデザインデータとピッタリ合わせることができます。
あるある6|box-sizingがcontent-boxになっている
例えば、以下のように高さがが明示的になっていて、paddingではなく、heightで指定するデザインを再現するとします。

しかし、デザイン通りコーディングしたはずがPerfect Pixelで見るとズレています。

<p>Perfect Pixel</p>
p{
display: flex;
justify-content: center;
align-items: center;
border: solid 5px #0B78D7;
height: 100px; /*高さを固定*/
color: #0B78D7;
font-size: 24px;
font-weight: bold;
}

実は、デベロッパーツールでよく見るとheight: 100px
と設定したはずのp
が110pxの高さになっています。
これには「box-sizing」というプロパティの設定が関係しています。
box-sizingとは?
box-sizing
とは要素の横幅や高さを決める際にborderやpaddingを計算に含めるかどうかを決めるプロパティです。
box-sizing: content-box
→ border・paddingを計算に含めない👈デフォルトbox-sizing: border-box
→ border・paddingを計算に含める
それぞれ上記のようになっていますが、いまいちピンとこないと思うので今回の例をもとに解説します。

ボックスモデルを見てみると、heightには100pxが指定され、borderが5pxあるため、全体の高さは110pxになっています。
これはbox-sizing: content-box
でborder
は100px
の計算から外れているためです。

p要素に対して以下のコードを追加してあげると…
p{
box-sizing: border-box; /*追加*/
}
borderの10pxを差し引いた90pxが要素自体の高さとなり、ちょうど100pxになるように自動計算されます。
実際に調整前と調整後を比較すると以下のようになり、狙い通り100pxの高さにすることができました。


【考え方編】ピクセルパーフェクトの捉え方
さて、ピクセルパーフェクトについてはよく議論がなされますが、様々なデバイス環境やレスポンシブ対応が当然のように求められる昨今では否定的な意見の方が見受けられます。
その理由は「ピクセルパーフェクト」という単語の持つ意味が強すぎるからだと考えています。
ピクセルパーフェクトはその字面から「デザインデータの数値こそ正義。1pxのズレもなくコーディングする。」という意味を強く感じますが、実際には実装者によって柔軟な解釈があって良い言葉です。
前提として1pxのズレもなく実装するのは無理
複数のデバイス・ブラウザ幅でデザイン通り完璧に再現するのは当然無理です。
そのため、基本的には以下のことを意識し守ることができればOKだと考えています。
- デザインの数値上のルールを守る(例:8の倍数で組まれた余白や、見出しの文字サイズ)
- デザインデータと「ルック・アンド・フィール」を合わせる
【結論編】デザインに合わせる・合わせないケース
さて、先ほどの前提を踏まえた上で、実際のコーディングの際にデザインデータに合わせるべきかどうかをケース別に紹介していきます
対応しなくてもいい場合 → デザイナーの意図を感じない場合
デザイナーの意図を感じないというのは「人為的なミス」により意図しない数値が生まれている場合を指します。

例えば他の余白は綺麗に10の倍数で組まれているのに一部だけ微妙な数値になっている場合があります。
ボタンのpadding-top
が19px
になっていますが、これはデザイナーが意図せず生まれた数値です。

他にもガイドラインから少しはみ出てしまっていることがあります。
このようにデザインデータ作成は手作業であるためこういった人為的なミスは多少起こります。
対応することで逆にデザインルールからはみ出るような場合はピクセルパーフェクトな対応はしないのがベターです。
対応したほうがいい場合 → デザイナーの意図を感じる場合
以下デザインは「アイコンと文字」がグループ化された上で真ん中寄せになっているデザインです。

しかしletter-spacing
を指定すると「あるある4」のように最後の文字に意図しない余白がつき完全な中央寄せにはなりません。この場合はデザイナーの意図を汲んで対応してあげる必要があります。

「あるある3」で解説した、ハーフ・レディングに関しても極力対応してあげた方が良いです。
以下の例でもパッと見てズレていますが、これが複数要素重なってくるとそのズレはどんどん大きくなってきます。


ただ、ハーフ・レディングに関しては、実装者だけに委ねるのはベストとは言えず、デザイナー側もそれを理解し、
- ハーフ・レディング分の余白をあらかじめ削る
- Figmaに移行できるなら移行する
などデザイナー側で協力していく姿勢も大切だと思います!
対応を相談した方がいい場合 → デザイナーに意図があるか判断が難しい場合

判断が難しいケースでいえば「あるある2」のように意図しない行間がつくことで余白を生んでいる場合です。
デザイナーとしては意図せず行間が入ったものの、それを含めて上下の余白を設定している可能性があるのでデザイナー側へ意図を確認する必要があります。
書いてみると結構ボリューミーな内容になってしまったので、ぜひ読み返して自分なりの再現度の高いコーディングを身につけてください👍