CSSでborderを内側に引くには?ボックスの内側に枠線をつけるテクニック

CSS

「ボーダー(border)をつけたいけど、外側に膨らむのは困る」

「paddingで余白を確保しているのに、borderが外に広がってレイアウトがずれる…」

そんな経験はありませんか?

実は、CSSのborderはデフォルトではボックスの外側に付くため、サイズや位置が思わぬ形でずれてしまうことがあります。

この記事では、CSSで枠線(border)を内側に引くための方法を、初心者にもわかりやすく解説します。

スポンサーリンク

そもそもCSSのborderはどこにつくの?

標準的なボックスモデルの仕組み

CSSの標準的なボックスモデルは以下の順序で構成されています:

content → padding → border → margin

つまり、borderは常にコンテンツの外側に付くため、以下のような構造になります:

  • 要素のwidthやheightはコンテンツ領域の大きさ
  • その外側にpadding(内側の余白)
  • さらに外側にborder(枠線)
  • 一番外側にmargin(外側の余白)

視覚的な理解

┌──────────── margin ────────────┐
│ ┌─────────── border ───────────┐ │
│ │ ┌──────── padding ────────┐ │ │
│ │ │                        │ │ │
│ │ │      content area      │ │ │
│ │ │                        │ │ │
│ │ └────────────────────────┘ │ │
│ └─────────────────────────────┘ │
└───────────────────────────────────┘

これがズレの原因になる理由

例えば以下のCSSを書いた場合:

.box {
  width: 200px;
  height: 100px;
  padding: 20px;
  border: 5px solid #333;
}

実際に描画されるサイズは:

  • 横幅:200px(content)+ 40px(padding左右)+ 10px(border左右)= 250px
  • 縦幅:100px(content)+ 40px(padding上下)+ 10px(border上下)= 150px

となり、指定したサイズより大きくなってしまいます。

よくある問題

レイアウト崩れの例

/* 3つ並べたいカード */
.card {
  width: 33.33%;
  float: left;
  border: 1px solid #ddd; /* これで幅が増えてしまう */
}

この場合、borderの分だけ幅が増えて、3つのカードが1行に収まらなくなってしまいます。

グリッドレイアウトでの問題

.grid-item {
  width: calc(25% - 10px);
  border: 5px solid #333; /* 計算が狂ってしまう */
}

calcで計算しても、borderの分が考慮されていないとレイアウトがずれます。

borderを内側にする方法

実はCSS単体には「borderを内側だけに付ける」プロパティはありません。

そのため、以下の方法で実現します。

方法1:box-sizingで調整する(推奨)

基本的な使い方

box-sizing: border-box;を使えば、指定したwidthやheightの中にpaddingとborderを含めることができます。

.box {
  width: 200px;
  height: 100px;
  padding: 20px;
  border: 5px solid #333;
  box-sizing: border-box;
}

こうすると、見た目のサイズは常に200×100pxのままで、内側にborderとpaddingを収めた形になります。

box-sizingの種類

content-box(デフォルト)

.box {
  box-sizing: content-box; /* デフォルト値 */
  width: 200px;
  /* 実際のサイズ = width + padding + border */
}

border-box(推奨)

.box {
  box-sizing: border-box;
  width: 200px;
  /* 実際のサイズ = width(paddingとborderを含む) */
}

全体に適用する方法

多くの開発者が以下のリセットCSSを使用します:

*, *::before, *::after {
  box-sizing: border-box;
}

これで、すべての要素が直感的なサイズ計算になります。

実際の使用例

カードレイアウト

.card {
  width: 300px;
  height: 200px;
  padding: 20px;
  border: 2px solid #ddd;
  box-sizing: border-box;
  /* 実際のサイズは300×200pxのまま */
}

グリッドアイテム

.grid-item {
  width: 25%;
  padding: 10px;
  border: 1px solid #333;
  box-sizing: border-box;
  float: left;
  /* 4つがぴったり横に並ぶ */
}

方法2:outlineを使う

outlineの特徴

outlineはborderと似ていますが、ボックスの外側に重なる形で描画され、サイズに影響しないのが特徴です。

.box {
  width: 200px;
  height: 100px;
  padding: 20px;
  outline: 5px solid #333;
  /* サイズは変わらない */
}

borderとoutlineの違い

プロパティサイズへの影響位置角丸対応
borderありボックス境界あり
outlineなしボックス外側なし

outlineのメリット・デメリット

メリット

  • レイアウトに影響しない
  • アニメーションでの表示・非表示が簡単
  • フォーカス表示に最適

デメリット

  • 角丸(border-radius)が効かない
  • 要素の外側にはみ出す
  • 細かい位置調整ができない

実際の使用例

ボタンのホバー効果

.button {
  padding: 10px 20px;
  background: #007BFF;
  color: white;
  transition: outline 0.3s ease;
}

.button:hover {
  outline: 3px solid rgba(0, 123, 255, 0.5);
  outline-offset: 2px;
}

方法3:擬似要素を使って完全に内側に描く

基本的な実装

::before::afterで擬似要素を作り、内側にborderを引くテクニックです。

.box {
  position: relative;
  width: 200px;
  height: 100px;
  padding: 20px;
}

.box::before {
  content: "";
  position: absolute;
  top: 5px;
  left: 5px;
  right: 5px;
  bottom: 5px;
  border: 2px solid #333;
  pointer-events: none; /* クリック操作の邪魔をしない */
}

これでpaddingの内側にborderを引いたような見た目にできます。

より高度な実装

内側の任意の位置にborder

.inner-border {
  position: relative;
}

.inner-border::after {
  content: '';
  position: absolute;
  top: 10px;
  left: 10px;
  right: 10px;
  bottom: 10px;
  border: 3px solid #FF6B6B;
  border-radius: 8px;
  pointer-events: none;
}

複数の内側border

.double-inner-border {
  position: relative;
}

/* 外側の内側border */
.double-inner-border::before {
  content: '';
  position: absolute;
  top: 5px;
  left: 5px;
  right: 5px;
  bottom: 5px;
  border: 2px solid #333;
  pointer-events: none;
}

/* 内側の内側border */
.double-inner-border::after {
  content: '';
  position: absolute;
  top: 15px;
  left: 15px;
  right: 15px;
  bottom: 15px;
  border: 1px solid #666;
  pointer-events: none;
}

擬似要素の注意点

pointer-events: none が重要

.box::before {
  pointer-events: none; /* マウスイベントを無視 */
}

これがないと、擬似要素がクリックやホバーの邪魔をしてしまいます。

z-indexでの重なり制御

.box::before {
  z-index: 1; /* 必要に応じて重なり順を調整 */
}

方法4:insetプロパティ(現代的なアプローチ)

CSS Inset Propertyを活用

比較的新しいCSSプロパティinsetを使うと、より簡潔に書けます:

.box {
  position: relative;
}

.box::before {
  content: '';
  position: absolute;
  inset: 10px; /* top, right, bottom, left すべてに10px */
  border: 2px solid #333;
  pointer-events: none;
}

insetの書き方

/* 全方向同じ値 */
inset: 10px;

/* 上下、左右 */
inset: 10px 20px;

/* 上、左右、下 */
inset: 10px 20px 30px;

/* 上、右、下、左 */
inset: 10px 20px 30px 40px;

応用テクニックと実践例

レスポンシブデザインでの活用

メディアクエリと組み合わせ

.responsive-border {
  box-sizing: border-box;
  border: 2px solid #333;
}

@media (max-width: 768px) {
  .responsive-border {
    border-width: 1px; /* スマホでは細く */
  }
}

@media (max-width: 480px) {
  .responsive-border {
    border: none; /* 小さい画面では非表示 */
    outline: 1px solid #999;
  }
}

アニメーション効果

border-boxでのアニメーション

.animated-border {
  box-sizing: border-box;
  width: 200px;
  height: 100px;
  border: 0px solid #007BFF;
  transition: border-width 0.3s ease;
}

.animated-border:hover {
  border-width: 5px;
}

擬似要素でのアニメーション

.slide-border {
  position: relative;
  overflow: hidden;
}

.slide-border::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  right: 100%;
  bottom: 0;
  border: 3px solid #FF6B6B;
  transition: left 0.5s ease, right 0.5s ease;
}

.slide-border:hover::before {
  left: 10px;
  right: 10px;
}

特殊な形状のborder

角だけのborder

.corner-border {
  position: relative;
}

.corner-border::before,
.corner-border::after {
  content: '';
  position: absolute;
  width: 20px;
  height: 20px;
}

.corner-border::before {
  top: 10px;
  left: 10px;
  border-top: 3px solid #333;
  border-left: 3px solid #333;
}

.corner-border::after {
  bottom: 10px;
  right: 10px;
  border-bottom: 3px solid #333;
  border-right: 3px solid #333;
}

グラデーションborder風

.gradient-inner-border {
  position: relative;
  background: white;
}

.gradient-inner-border::before {
  content: '';
  position: absolute;
  inset: 5px;
  border: 3px solid;
  border-image: linear-gradient(45deg, #FF6B6B, #4ECDC4, #45B7D1) 1;
}

よくある質問と解決方法

Q. box-sizing: border-boxでpadding領域が狭くなる

A. paddingの値を調整するか、widthを大きくする

/* 調整前 */
.box {
  width: 200px;
  padding: 20px;
  border: 5px solid #333;
  box-sizing: border-box;
  /* 実際のcontent領域は150px×50px */
}

/* 調整後:content領域を広くしたい場合 */
.box {
  width: 250px; /* widthを大きく */
  padding: 20px;
  border: 5px solid #333;
  box-sizing: border-box;
  /* content領域は200px×100px */
}

Q. 擬似要素のborderがクリックの邪魔をする

A. pointer-events: none を設定

.box::before {
  content: '';
  /* その他のスタイル */
  pointer-events: none; /* 必須 */
}

Q. 古いブラウザでbox-sizingが効かない

A. ベンダープレフィックスを追加

.box {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

Q. outlineとborderを両方使いたい

A. 重ねて使用可能

.double-line {
  border: 2px solid #333;
  outline: 1px solid #666;
  outline-offset: 2px;
}

パフォーマンスとブラウザ対応

パフォーマンスの考慮

最も軽い方法

推奨順位

  1. box-sizing: border-box(最軽量)
  2. outline(軽量)
  3. 擬似要素(やや重い)

大量の要素での注意点

/* 重い:大量の擬似要素 */
.item::before { /* 100個の要素で100個の擬似要素 */ }

/* 軽い:box-sizingの活用 */
.item {
  box-sizing: border-box;
  border: 1px solid #ddd;
}

ブラウザ対応状況

box-sizing

  • IE8+:対応
  • Chrome/Firefox/Safari:完全対応
  • モバイル:完全対応

outline

  • IE8+:基本対応
  • outline-offset:IE15+

insetプロパティ

  • Chrome 87+
  • Firefox 66+
  • Safari 14.1+

まとめ

CSSのborderは標準ではボックスの外側に付くため、意図せずサイズが大きくなってしまいがちです。

手法の使い分け

box-sizing: border-box

  • 最も実用的で推奨
  • レスポンシブデザインに最適
  • 計算が簡単

outline

  • レイアウトに影響させたくない場合
  • ホバー効果やフォーカス表示
  • アニメーションが簡単

擬似要素

  • 完全に内側にborderを引きたい場合
  • 複雑なデザイン効果
  • 特殊な形状のborder

基本的な推奨パターン

/* 全体的なリセット */
*, *::before, *::after {
  box-sizing: border-box;
}

/* 通常のborder */
.element {
  border: 1px solid #ddd;
  /* サイズ計算が直感的 */
}

/* 特殊効果 */
.special-effect {
  position: relative;
}

.special-effect::before {
  content: '';
  position: absolute;
  inset: 5px;
  border: 2px solid #333;
  pointer-events: none;
}

コメント

タイトルとURLをコピーしました