Viewport Units ของ CSS กับความเจ็บปวดบน Mobile Browser
หลายๆคนที่เป็น Front-end Developer คงจะเคยเห็น meta tag viewport อยู่ตามเว็บไซต์ต่างๆ ซึ่งจะมีหน้าตาประมาณนี้
<meta name="viewport" content="width=device-width, initial-scale=1 />
แล้วแม่งมีอยู่ในทุกๆ website เลย เคยสงสัยมั้ยครับว่า มีไว้ทำอะไร ทำไมถึงต้องใส่มันเอาไว้ด้วยนะ ?
ขอย้อนอดีตกลับไปในยุคก่อนที่จะมี Smartphone เว็บไซต์นั้นได้ถูกออกแบบมาให้ใช้กับหน้าจอของ Computer เพียงอย่างเดียว แต่เมื่อท่านศาสดา Steve Jobs เปิดตัว iPhone ความลำบากของ Developer ก็เพิ่มขึ้นคือ เว็บแม่งต้องเปิดบนหน้าจอของ Smartphone ได้ด้วยนะ แต่เว็บไซต์มันไม่ได้ทำมาเพื่อ Smartphone ไง พอไปเปิดแล้วขนาดของมันก็เล็กเกินไป จะอ่านอะไรก็ต้อง ซูมเข้าไป แล้ว Scroll ซ้าย ขวา ขึ้น ลง โอ้ WTF! ชีวิตแม่งโคตรจะเหนื่อยเลย
ซึ่ง meta tag viewport มาช่วยเราตรงนี้แหละ เย้ !!!
What is The Viewport?
viewport คือ ส่วนที่เรามองเห็นได้ของหน้าเว็บไซต์นั้นๆ
<meta name="viewport" content="width=device-width, initial-scale=1 />
จาก code meta tag ข้างบนจะอธิบายได้ว่า
width=device-width
จะบอกให้ Web Browser กำหนดความกว้างของเว็บไซต์ ให้เท่ากับความกว้างของหน้าจอ ของ device นั้นๆ
initial-scale=1
จะเป็นการบอกให้ Web Browser กำหนดการซูมของเว็บไซต์
What are viewport units?
vw
, vh
, vmin
, and vmax
หน่วยเหล่านี้จะแสดงถึงเปอร์เซ็นต์ของ viewport บน Browser นั้นๆ
Viewport Width (vw
) จะบอกถึง เปอร์เซ็นต์ความกว้างทั้งหมดของ viewport เช่น เราบอกว่า หน้าจอเรามีความกว้าง 100px ถ้าเราเราบอกว่า เราต้องการแสดงผลแค่ 10% ของความกว้างหน้าจอ เราสามารถเขียนแทนได้ด้วย 10vw ซึ่งจะมีค่าเท่ากับ 10px
Viewport Height (vh
) จะบอกถึง เปอร์เซ็นต์ความสูงทั้งหมดของ viewport
Viewport Minimum (vmin
) จะบอกถึงเปอร์เซ็นต์ของ ค่าต่ำสุด ของ viewport
Viewport Maximum (vmax
) จะบอกถึงเปอร์เซ็นต์ของ ค่าสูงสุด ของ viewport
จากหน่วยที่เราเรียนรู้มาทั้งหมด เราสามารถสรุปได้ว่า ถ้าเราต้องการทำหน้าเว็บไซต์ ให้มีความสูงเท่ากับความสูง viewport ของ Browser เราจะสามารถกำหนด CSS ได้ดังนี้
my-element {
height: 100vh;
}
ซึ่งการแสดงผลจะเห็นว่าหน้าเว็บไซต์มีขนาดเท่ากับขนาดของ Browser (จากรูปข้างบน ผมกำหนดให้ รูปมีขนาด 100vh)
ทีนี้ลองเปลี่ยนเป็นแสดงผลตามขนาดจอ Mobile ใน browser ดู
จะเห็นว่าการแสดงผล ก็ขึ้นอยู่กับเปอร์เซ็นต์ความสูงของ device นั้นๆ ในที่นี้กำหนดให้รูปเท่ากับ 100vh ความสูงเลยเท่ากับ 100% ของ viewport
หากลองเข้าไปดูที่เว็บ https://caniuse.com จะเห็นว่า Browser หลายๆตัว ก็รองรับ Viewport กันหมดแล้ว
แต่ Mobile Browser บน Device จริงนั้นช่างเจ็บปวด
จะเห็นว่าแค่เรากำหนด 100vh เข้าไป Browser ก็จะจัดการความสูงตามขนาด viewport ให้เราแล้ว แต่บน Mobile Browser (Safari iOS) 100vh มันจะมี Bar ข้างล่างมาบังอยู่ด้วย
จากรูปข้างบน ความคาดหวังของเรา 100vh มันควรจะมีขนาดเท่ากับ 635 px แต่ความเป็นจริงแล้ว 100vh มันคือ 748 px ใน Safari iOS Browser
จากรูปข้างบน ผมกำหนดให้ element มีความสูง 100vh ซึ่งในความเป็นจริง มันไม่ควรจะ scroll ได้ แต่เนื่องจาก Safari iOS Browser มีการคำนวณค่า 100vh โดยที่มันไม่ได้นับว่า Bar ข้างล่างนั้นเป็นส่วนหนึ่งของ Browser Interface ทำให้หน้าเว็บเราสามารถ scroll ได้
ในความมืดมิดยังคงมีแสงสว่างอยู่เสมอ
เราสามารถใช้ javascript และ css ช่วยคำนวณหา 100vh ที่ควรจะเป็นได้นะ โดยให้เราเพิ่ม css ดังนี้
.my-element {
height: 100vh;
height: calc(var(--vh, 1vh) * 100);
}
จากโค้ดอธิบายได้ว่า เรากำหนด element ให้มีความสูง 100vh เอาไว้เพื่อให้ Browser เก่าๆ ที่ไม่รองรับตัวแปร var() ของ css ใช้งานตัวข้างบน สำหรับ Browser ที่รองรับก็มาอ่านตัวข้างล่าง โดยตัวข้างล่าง จะมีการใช้ ฟังก์ชัน calc() ของ css เพื่อคำนวณหาความสูง โดยจะเอาตัวแปร — vh มาคูณกับ 100 หรือ กรณี — vh ไม่มีค่า ให้ใช้ 1vh คูณกับ 100 แทน
จากนั้นเราก็เพิ่ม javascript ที่ใช้คำนวณหาความสูงของ viewport ดังนี้
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
โดย javascript ข้างบน จะเป็นการบอกให้ไปเซ็ตตัวแปรชื่อ — vh ไว้ที่ root element ให้มีค่าเท่ากับ window.innerHeight * 0.01 และมีหน่วยเป็น px เมื่อเราได้ค่า — vh มาแล้ว มันจะไปแทนที่ตัวแปรในฟังก์ชัน var() ที่เราประกาศไว้ตั้งแต่ตอนแรก สุดท้ายเราก็จะได้ค่า viewport ที่เป็นส่วนในการแสดงผลจริงๆของ Browser นั้น
สามารถเปรียบเทียบผลลัพธ์กันได้จากภาพข้างล่าง
- อันซ้ายจะเป็น 100vh ธรรมดา (จะเห็นว่ามัน scroll ได้)
- อันขวาจะเป็น 100vh ที่มาจากคำนวณของ javascript
ใครอยากเอาไปลองเปิดเองบน Mobile Browser ก็ได้นะ ตามลิ้งนี้เลย
ในส่วนของ Browser บน Android ยังไม่เคยลองแหะ ใครว่างๆ ฝากลองหน่อยนะฮับว่า 100vh มันสามารถ scroll ได้มั้ย เท่าที่ลองตอนนี้เป็นแค่ใน iOS นะ ฮ่าๆ
Source Code
ของแถม
สำหรับใครที่อยากลองเล่นเกี่ยวกับ meta tag viewport เพิ่มเติม ก็จะมี viewport-fit=cover เอาไว้ใช้สำหรับ มือถือที่มี safe-area
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">