◆ マージン相殺の都合で body の内側に margin 付き要素を置くとスクロールバーが出る
◆ border → 1px でも border つけたくない
◆ overflow:hidden → スクロールバーは消えるけど body の場合は相殺できてない
◆ body を 100% にしないで 100vh → はみ出ないけど body の高さは全画面じゃない
◆ body の display を flex や grid に → はみ出ないし body が全画面になる

body の内側に全体を囲むブロック要素を置いた構造にしてその要素に margin をつけたいとき

<!doctype html>

<style>
html, body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.container{
width: 80%;
height: calc(100% - 40px);
margin: 20px auto;
background: beige;
}
</style>

<div class="container"></div>

上下に 20px のマージンで残りを高さに指定しています
これで問題なさそうなのですが マージン相殺のせいでスクロールバーが表示されてしまいます

.container のマージンが body の内側でなく外側にできるので body の 100% が上から 20px の部分から始まり終わりの位置は 100% + 20px の場所になってしまいます

対処方法

簡単なものはマージンの相殺で親の外側にマージンが出ないようにすることです
マージン相殺をなくすためには border を付ける方法がありますが border を 1px で透明であってもつけたくない場合もあります

また overflow:hidden もありますが body の場合はちょっと特別な動きをします
結果的には overflow した部分を隠してスクロールバーを表示しないので目的は果たせているのですが body が画面全体の高さをはみ出ていることは変わっていません
スクロールバーはなくてマウスのホイール回してもスクロールはしないので JavaScript でスクロールでもしなければ問題はないのですがあまり気持ち良い解決方法じゃないです
body の上に隙間があるので css の設定によってはうまく動かないかもしれませんし

ここまでのことは前の記事にも同じようなことを書いています

vh

別の方法 1 つ目
body に 100% しない方法です

もともと html と body に 100% をつけてるのは .container を 100% するためのものでした
画面全体に対しての 100% なら親のサイズを決めなくても 100vh を指定することができます

html, body{
margin: 0;
padding: 0;
}
.container{
width: 80%;
height: calc(100vh - 40px);
margin: 20px auto;
background: beige;
}

これだと body の高さは .container のマージンを除いた部分です
なのでスクロールバーはでません
上下に body じゃない隙間が残るのは一緒ですが隠してるだけとは違うのでこっちのほうが好みです

body の display

body の display を変えることでも対処できました

  • inline (initial, unset)
  • flex
  • grid
  • flow-root
  • table

inline と table は意味的に変だと思うので flow-root や flex などを使うと良さそうです
この方法だと body が全体になってスクロールバーもないので一番目的の動きになっています