Post

Create a layout centered and stretched to full screen height

Create a layout centered and stretched to full screen height

รูปแบบหน้าจอที่ใช้บ่อยและแทบจะเป็นรูปแบบเริ่มต้นที่ผมใช้บ่อยจะเป็นลักษณะนี้:

1
2
3
4
5
6
7
8
9
------------
   header
------------

    main

------------
   footer
------------

ลองจินตนาการดูว่าในตอนแรกที่เราทำ ทุกอย่างจะไปอยู่ด้านบนหมด แน่นอนว่าหากมี content ยาวมากพอ ก็จะไม่ดูแปลกอะไร แต่หาก content สั้น footer จะลอยอยู่กลางหน้า ไม่ติดขอบล่าง

เพื่อให้ได้ในสิ่งที่ต้องการ เราจะกำหนด css พื้นฐานที่เราพยายามจะไม่อิงกับ css framework ตัวไหน ๆ เลย ก็จะได้ออกมาดังนี้:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
html {
  height: 100%;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh; /* handles mobile address bar automatically */
}

main {
  flex: 1 1;
}

หลักการสั้นๆ:

  • display: flex + flex-direction: column บน body ทำให้ลูกแต่ละตัวเรียงต่อกันลงในแนวตั้ง
  • min-height: 100dvh ตั้ง min height ของ body เท่าความสูง viewport ปัจจุบัน (dvh = dynamic viewport height ที่ปรับตาม mobile address bar ให้อัตโนมัติ) บรรทัด 100vh เก็บไว้เป็น fallback สำหรับ browser เก่า
  • flex: 1 1 บน main บอกให้กินพื้นที่เหลือทั้งหมดที่ header กับ footer ไม่ได้ใช้ ดัน footer ไปติดขอบล่าง

ในโพสเดิมเคยใช้ min-height: -webkit-fill-available เป็น workaround สำหรับ mobile viewport ตอนนี้ browser สมัยใหม่รองรับ dvh/svh/lvh หมดแล้ว ใช้ 100dvh ตรงๆ คลีนกว่า

รูปแบบ html ง่ายสุดที่เราจะใช้คือ:

1
2
3
4
5
<header>
  <nav></nav>
</header>
<main></main>
<footer></footer>

ใช้ <main> แทน <div class="main"> เพราะเป็น semantic HTML5 — screen reader จับ landmark ได้ ไม่ต้องประกาศ class เพิ่ม

เมื่อเราดูผลลัพธ์ที่ออกมาจะได้ว่าส่วน main จะยืดและดันให้ header และ footer ติดขอบบนและล่าง ซึ่งในระหว่าง main กับ header และ footer เราก็สามารถที่จะแทรก section หรืออะไรที่เราอยากจะแทรกไปได้เลย:

1
2
3
4
5
6
7
<header>
  <nav></nav>
</header>
<div></div>
<main></main>
<section></section>
<footer></footer>

การแสดงผลก็ยังจะเต็มหน้าจอยู่เหมือนเดิม จนว่าจะมี content มากจน main ยืดอีกไม่ได้แล้ว จากนั้นหน้าก็จะเลื่อนลงได้

ทางเลือก: CSS Grid

ถ้าชอบ grid syntax อ่านง่ายกว่าก็ใช้แทนได้:

1
2
3
4
5
6
body {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
  min-height: 100dvh;
}
  • auto แถวแรกและแถวสุดท้าย — สูงเท่ากับ content (header กับ footer)
  • 1fr ตรงกลาง — กินพื้นที่เหลือทั้งหมด

HTML ใช้แบบเดียวกัน ไม่ต้องเปลี่ยน

References

This post is licensed under CC BY 4.0 by the author.