CSSで、画像を丸く切り抜いて枠を付ける方法
プロフィールのアイコンのように画像を丸く表示し、まわりに枠を付けるには、img の幅と高さを同じ値にして、object-fit: cover と border-radius: 50% を付けます。枠は border で付けると、円に沿って丸くなります。元の画像が横長でも縦長でも、ゆがまずに真ん中が丸く切り抜かれます。
検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。HTML と CSS のページを Playwright で開いて画面を撮り、画像の中心から外へ1pxずつ色を読んで、どこに何が描かれているかを確かめました。Firefox と Safari では試していません。
検証には、次のような 300×200 の横長の画像を使いました。真ん中に緑の円、左右の端に幅40pxの青い帯を描いています。

コード全体
HTML は、ふつうの img 要素にクラスを付けるだけです。
<img class="avatar" src="photo.png" alt="">
CSS は次のとおりです。
.avatar {
width: 120px;
height: 120px;
object-fit: cover;
border-radius: 50%;
border: 4px solid #00c8e8;
}
width と height で、画像を表示する箱を正方形にします。object-fit: cover は、画像の縦横比を保ったまま箱全体を埋め、はみ出した部分を切り取る指定です。border-radius: 50% で正方形の角を丸めると円になり、border もその円に沿って描かれます。
この CSS で表示した画像を測ると、border を含めた箱の大きさは 128×128 でした。中心から左・上・左上のどの向きに進んでも、0〜36pxが緑、37〜60pxが砂色、61〜64pxが水色の枠で、その外は背景の白です。緑の円の半径は36pxで、元の60pxを、画像の高さに合わせて0.6倍にした大きさです。元の画像の左右にあった青い帯は、どの向きにも出てきません。横にはみ出した部分として切り取られています。
border-radius を付けない場合、左上の向きでは、枠が中心から85〜90pxの場所にありました。border-radius: 50% を付けると、正方形の角まで届いていた枠が、ほかの向きと同じ61〜64pxの位置に来て、円になります。
幅と高さをそろえないと、楕円になる
width だけを決めて height を決めないと、高さは画像の縦横比から決まります。300×200 の画像に width: 120px と border-radius: 50% だけを付けると、箱は 120×80 になり、丸くはならずに横長の楕円になりました。左右の青い帯も、そのまま見えています。
border-radius のパーセントの値は、横の半径が箱の幅に対する割合、縦の半径が箱の高さに対する割合です。120×80 の箱の 50% は、横の半径60px・縦の半径40pxになります。正円にしたいときは、width と height を同じ値にします。
object-fit がないと、画像が縮んでゆがむ
width と height を同じにしても、object-fit を書かないと、既定の fill になります。fill は、画像の縦横比を変えてでも箱いっぱいに広げる指定です。
object-fit を外して 120×120 にすると、緑の円は、中心から左へ24px、上へ36pxの縦長の楕円になりました。画像の幅は300pxから120px(0.4倍)に、高さは200pxから120px(0.6倍)に縮められたので、横のほうが強く縮んでいます。左右の青い帯も、中心から45〜60pxの場所に残っていました。
clip-path で切り抜くと、枠も一緒に切れる
border-radius の代わりに clip-path: circle(50%) で丸くすると、border の枠は円になりません。測ると、中心から左と上の向きには61〜64pxに水色の枠がありましたが、左上の向きには枠がありませんでした。clip-path の説明のとおり、形の基準になる箱は、指定しなければ border の外側の端で囲んだ箱です。その箱が円に切り抜かれ、枠は上下左右の4か所にだけ残ります。枠を付けるときは、border-radius で丸くします。
枠の分だけ大きくなるのを防ぐ
width: 120px に border: 4px を足すと、表示される大きさは 128×128 になりました。box-sizing が既定の content-box のときは、width と height に枠の太さが入らないためです(box-sizing の説明)。
枠を含めて 120×120 に収めたいときは、box-sizing: border-box を足します。
.avatar {
box-sizing: border-box;
}
box-sizing: border-box を足すと、箱は 120×120 になり、枠は中心から57〜60pxの場所に来ました。そのぶん、border の内側の画像の部分は 112×112 に小さくなりました。
枠と画像の間に、すき間を空ける
枠と画像の間にすき間を空ける書き方を、2つ試しました。下の画像の右上と左下です。

1つ目は、border の代わりに outline を使う書き方です。outline-offset で、枠を画像から離せます。
.avatar {
width: 120px;
height: 120px;
object-fit: cover;
border-radius: 50%;
outline: 4px solid #00c8e8;
outline-offset: 4px;
}
中心から左へ測ると、61〜64pxがすき間、65〜68pxが水色の枠でした。左上の向きでも同じ距離に枠があり、outline も border-radius の円に沿って描かれています。このすき間には何も描かれず、後ろの背景が見えます。背景が白のときは白、背景を薄い水色(#eefafd)にしたときは薄い水色になりました。箱の大きさは 120×120 のままでした。outline の説明にあるとおり、outline は場所を取らないので、まわりの要素の配置は変わりません。
2つ目は、白い border の外に、ぼかしのない box-shadow を重ねる書き方です。
.avatar {
width: 120px;
height: 120px;
object-fit: cover;
border-radius: 50%;
border: 4px solid #fff;
box-shadow: 0 0 0 4px #00c8e8;
}
box-shadow の4つ目の値は、影を広げる長さです。ずらす量とぼかしを0にして4pxだけ広げると、外側に太さ4pxの線ができます。測った結果は outline のときと同じく、61〜64pxが白、65〜68pxが水色でした。箱の大きさは、白い border の分を含めて 128×128 です。こちらのすき間は border の色なので、背景を薄い水色にしたページでも白のままでした。
box-shadow だけを付けて border を付けない場合は、61〜64pxに水色の線ができ、箱は 120×120 のままでした。枠の分の場所を取らずに、border と同じ見た目の枠を付けられます。
グラデーションの枠は、親要素の背景で作る
枠の色をグラデーションにしたいときは、img を span などで包み、親要素の背景にグラデーションを敷きます。親要素に padding を付けて丸くすると、padding の部分の背景が枠に見えます。
<span class="ring"><img src="photo.png" alt=""></span>
.ring {
display: inline-block;
padding: 4px;
border-radius: 50%;
background: linear-gradient(135deg, #00c8e8, #d85878);
}
.ring img {
display: block;
width: 120px;
height: 120px;
object-fit: cover;
border-radius: 50%;
border: 4px solid #fff;
}
img の白い border が、画像とグラデーションの間のすき間になります。この CSS では、親要素の大きさは 136×136 で、画像の上と下の余白はどちらも4pxでした。
.ring img の display: block を書き忘れると、親要素の大きさは 136×141 になりました。画像の上の余白は4px、下の余白は9pxです。img は既定で文字と同じ行の中に並ぶ要素(display: inline)で、vertical-align の既定値は baseline です。親要素の中に高さ0の要素を置いてベースラインの位置を測ると、画像の下端とベースラインは同じ位置で、親要素の下端はそこから9px下でした。padding の4pxを除いた5pxが、ベースラインより下に残った余白です。
display: block の代わりに vertical-align: top を付けた場合も、親要素は 136×136 になり、上下の余白は4pxずつでした。
この余白が残ると、画像は親要素の真ん中から上にずれます。border-radius: 50% は幅と高さそれぞれに対する割合なので、136×141 の親要素は正円ではなく、わずかに縦長の楕円になります。
使えるブラウザ
MDN の互換性データ(@mdn/browser-compat-data 8.1.8)では、border-radius は Chrome 4、Edge 12、Firefox 4、Safari 5(iOS の Safari は 4.2)から使えます。object-fit は Chrome 32、Edge 79、Firefox 36、Safari 10(iOS の Safari も 10)からです。





