CSS round()関数でピクセルパーフェクトなレイアウトを実現する


CSS round()関数とは

round() は CSS の数学関数の一つで、計算結果を指定した間隔(倍数)に丸めることができます。2023年にブラウザサポートが進み、Chrome 107+、Firefox 108+、Safari 15.4+ で利用可能になりました。

基本構文

round(<rounding-strategy>, <value>, <interval>)
  • rounding-strategy: 丸め方(省略可能、デフォルトは nearest
    • nearest: 最も近い間隔に丸める
    • up: 切り上げ
    • down: 切り下げ
    • to-zero: ゼロ方向に丸める
  • value: 丸めたい値
  • interval: 丸める間隔(倍数)

シンプルな例

/* 10pxの倍数に丸める */
.element {
  width: round(nearest, 47px, 10px);
  /* 結果: 50px */
}

/* 切り下げ */
.element {
  width: round(down, 47px, 10px);
  /* 結果: 40px */
}

/* 切り上げ */
.element {
  width: round(up, 47px, 10px);
  /* 結果: 50px */
}

なぜround()が必要なのか

問題: calc()による小数点の誤差

従来の calc() 関数では、計算結果が小数点以下の値になることがあります。

.grid-item {
  /* 3カラムグリッド */
  width: calc(100% / 3);
  /* 結果: 33.333333...% */
  /* ブラウザによってレンダリングが微妙にずれる */
}

この問題により:

  • ピクセルの端数でぼやけた表示
  • グリッドアイテム間の隙間の不均一
  • サブピクセルレンダリングの不一致

解決策: round()で明確な値に

.grid-item {
  width: round(down, calc(100% / 3), 1%);
  /* 結果: 33% (明確な値) */
}

実践的な使用例

1. レスポンシブグリッドの最適化

コンテナクエリと組み合わせて、常にピクセルパーフェクトなグリッドを実現:

.grid {
  display: grid;
  gap: 1rem;
}

.grid-item {
  /* コンテナ幅を3で割り、16pxの倍数に丸める */
  width: round(nearest, calc(100cqw / 3), 16px);
}

/* 5カラムの場合 */
.grid-5col .grid-item {
  width: round(down, calc(100cqw / 5), 8px);
}

2. フォントサイズの均一化

フォントサイズを2pxや4pxの倍数に揃えることで、より整ったタイポグラフィに:

:root {
  --base-size: 16px;
}

h1 {
  /* ビューポート幅に基づいて、4pxの倍数に */
  font-size: round(nearest, calc(var(--base-size) + 2vw), 4px);
}

h2 {
  font-size: round(nearest, calc(var(--base-size) + 1.5vw), 4px);
}

p {
  /* 2pxの倍数に */
  font-size: round(nearest, calc(var(--base-size) + 0.5vw), 2px);
}

3. パディングとマージンの統一

デザインシステムのスペーシングスケールに合わせて丸める:

:root {
  --spacing-unit: 8px;
}

.card {
  /* 動的な値を8pxの倍数に */
  padding: round(nearest, calc(2vw + 0.5rem), var(--spacing-unit));
  margin-bottom: round(nearest, calc(3vh), var(--spacing-unit));
}

.container {
  /* 16pxの倍数に */
  padding-inline: round(nearest, 5vw, 16px);
}

4. アスペクト比の維持

画像やビデオコンテナで、アスペクト比を保ちながらピクセルパーフェクトに:

.video-container {
  width: 100%;
  /* 16:9のアスペクト比で、ピクセル単位に丸める */
  height: round(nearest, calc(100vw * 9 / 16), 1px);
  max-height: 720px;
}

.square-image {
  width: round(nearest, 30vw, 4px);
  height: round(nearest, 30vw, 4px);
  aspect-ratio: 1;
}

5. スクロールスナップの調整

スクロールコンテナのアイテムサイズを均一に:

.scroll-container {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  gap: 1rem;
}

.scroll-item {
  flex-shrink: 0;
  /* ビューポート幅の40%を、16pxの倍数に */
  width: round(nearest, 40vw, 16px);
  scroll-snap-align: start;
}

高度なテクニック

カスタムプロパティとの組み合わせ

:root {
  --grid-columns: 4;
  --gap: 1rem;
  --snap-interval: 8px;
}

.dynamic-grid {
  display: grid;
  grid-template-columns: repeat(
    var(--grid-columns),
    minmax(
      round(
        nearest,
        calc((100% - (var(--gap) * (var(--grid-columns) - 1))) / var(--grid-columns)),
        var(--snap-interval)
      ),
      1fr
    )
  );
  gap: var(--gap);
}

メディアクエリと併用

.adaptive-element {
  /* モバイル: 4pxの倍数 */
  width: round(nearest, calc(100vw - 2rem), 4px);
}

@media (min-width: 768px) {
  .adaptive-element {
    /* タブレット: 8pxの倍数 */
    width: round(nearest, calc(50vw - 2rem), 8px);
  }
}

@media (min-width: 1024px) {
  .adaptive-element {
    /* デスクトップ: 16pxの倍数 */
    width: round(nearest, calc(33.333vw - 2rem), 16px);
  }
}

clamp()との組み合わせ

最小・最大値を設定しつつ、round()で値を整える:

.responsive-text {
  font-size: clamp(
    16px,
    round(nearest, calc(1rem + 1vw), 2px),
    32px
  );
}

.flexible-container {
  width: clamp(
    320px,
    round(nearest, 80vw, 16px),
    1200px
  );
}

パフォーマンスと最適化

GPU加速との相性

整数値に丸めることで、GPU加速が効きやすくなります:

.animated-element {
  /* transformは整数値の方がスムーズ */
  transform: translateX(round(nearest, calc(var(--scroll) * 1px), 1px));
  will-change: transform;
}

サブピクセルレンダリングの回避

テキストのシャープさを保つ:

.text-container {
  /* テキストコンテナは整数ピクセルに */
  width: round(nearest, 60vw, 1px);

  /* フォントサイズも整数に */
  font-size: round(nearest, calc(1rem + 0.5vw), 1px);
}

デザインシステムへの統合

スペーシングスケールの実装

:root {
  --spacing-base: 4px;

  /* スペーシングスケール */
  --space-1: calc(var(--spacing-base) * 1); /* 4px */
  --space-2: calc(var(--spacing-base) * 2); /* 8px */
  --space-3: calc(var(--spacing-base) * 3); /* 12px */
  --space-4: calc(var(--spacing-base) * 4); /* 16px */
  --space-6: calc(var(--spacing-base) * 6); /* 24px */
  --space-8: calc(var(--spacing-base) * 8); /* 32px */
}

.component {
  /* 動的な値をスケールに合わせる */
  padding: round(nearest, calc(2vw), var(--spacing-base));
  margin-block: round(nearest, calc(3vh), var(--spacing-base));
}

グリッドシステムの構築

:root {
  --grid-unit: 8px;
  --grid-columns: 12;
}

.grid-container {
  display: grid;
  grid-template-columns: repeat(
    var(--grid-columns),
    round(
      down,
      calc(100% / var(--grid-columns)),
      var(--grid-unit)
    )
  );
}

.col-4 {
  grid-column: span 4;
  /* 幅を8pxの倍数に */
  padding-inline: round(nearest, 2vw, var(--grid-unit));
}

レスポンシブタイポグラフィ

:root {
  --text-snap: 2px;
}

.heading-xl {
  font-size: round(nearest, clamp(2rem, 5vw, 4rem), var(--text-snap));
  line-height: round(nearest, calc(1.2em), var(--text-snap));
}

.heading-lg {
  font-size: round(nearest, clamp(1.5rem, 4vw, 3rem), var(--text-snap));
}

.heading-md {
  font-size: round(nearest, clamp(1.25rem, 3vw, 2rem), var(--text-snap));
}

.body {
  font-size: round(nearest, clamp(1rem, 2.5vw, 1.125rem), var(--text-snap));
}

ブラウザサポートと代替案

サポート状況(2025年2月時点)

  • Chrome/Edge: 107+
  • Firefox: 108+
  • Safari: 15.4+

フォールバック戦略

.element {
  /* フォールバック: calc()のみ */
  width: calc(100% / 3);

  /* round()をサポートしているブラウザのみ */
  width: round(down, calc(100% / 3), 1%);
}

@supportsでの分岐

@supports (width: round(nearest, 100%, 1px)) {
  .modern-layout {
    width: round(nearest, 80vw, 16px);
    padding: round(nearest, 5vw, 8px);
  }
}

@supports not (width: round(nearest, 100%, 1px)) {
  .modern-layout {
    width: 80vw;
    padding: 5vw;
  }
}

PostCSSプラグイン

古いブラウザ向けには、PostCSSでフォールバックを自動生成:

// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-round')({
      fallback: true, // フォールバック生成
    }),
  ],
};

実践プロジェクト例

レスポンシブカードグリッド

.card-grid {
  --min-card-width: 280px;
  --grid-gap: 1rem;
  --snap: 8px;

  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(
      round(nearest, var(--min-card-width), var(--snap)),
      1fr
    )
  );
  gap: var(--grid-gap);
  padding: round(nearest, 5vw, var(--snap));
}

.card {
  border-radius: round(nearest, calc(0.5rem + 0.5vw), 4px);
  padding: round(nearest, calc(1rem + 1vw), var(--snap));
}

.card-title {
  font-size: round(nearest, clamp(1.25rem, 3vw, 2rem), 2px);
  margin-bottom: round(nearest, calc(0.5rem + 0.5vh), var(--snap));
}

フルード画像ギャラリー

.gallery {
  display: flex;
  flex-wrap: wrap;
  gap: round(nearest, 2vw, 8px);
}

.gallery-item {
  /* 画像サイズを16pxの倍数に */
  flex-basis: round(
    down,
    calc((100% - (round(nearest, 2vw, 8px) * 3)) / 4),
    16px
  );
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: round(nearest, 1vw, 4px);
}

.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

モーダルダイアログ

.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);

  /* モーダルサイズを16pxの倍数に */
  width: round(nearest, min(90vw, 600px), 16px);
  max-height: round(nearest, 90vh, 16px);

  padding: round(nearest, 5vw, 8px);
  border-radius: round(nearest, 2vw, 4px);
}

.modal-header {
  padding-bottom: round(nearest, 2vh, 8px);
  margin-bottom: round(nearest, 2vh, 8px);
}

デバッグとテスト

CSS変数で確認

:root {
  --debug: false;
}

.element {
  --original: calc(100% / 3);
  --rounded: round(down, var(--original), 1%);

  width: var(--rounded);
}

/* デバッグモード */
@media (prefers-color-scheme: dark) {
  .element::after {
    content: 'Original: ' var(--original) ', Rounded: ' var(--rounded);
    display: block;
    font-size: 0.75rem;
    color: yellow;
  }
}

DevToolsでの確認

Chrome DevToolsのComputedタブで、round()の計算結果を確認できます。

.test {
  --test-value: 47.3px;
  width: round(nearest, var(--test-value), 10px);
  /* Computed: 50px */
}

まとめ

CSS round() 関数は、レスポンシブデザインにおけるピクセルパーフェクトなレイアウトの実現を大幅に簡単にします。

主な利点:

  • サブピクセルレンダリングの問題を解決
  • デザインシステムのスナップポイントに値を揃えられる
  • 計算結果の予測可能性が向上
  • GPU加速との相性が良い
  • グリッドやフレックスボックスとの組み合わせが強力

2025年現在、主要ブラウザでのサポートも充実しており、実務で積極的に活用できる段階に達しています。特にデザインシステムやコンポーネントライブラリを構築する際には、必須の機能と言えるでしょう。