Viewport Units ของ CSS กับความเจ็บปวดบน Mobile Browser

Supakorn Thongtra
Nextzy
Published in
5 min readSep 15, 2018

หลายๆคนที่เป็น 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 กำหนดการซูมของเว็บไซต์

https://www.w3schools.com/css/css_rwd_viewport.asp

What are viewport units?

https://cdn-images-1.medium.com/max/800/1*x4A1kpLEJs8GFA4gXC3eJg.png

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;
}
100vh on chrome (pc screen)

ซึ่งการแสดงผลจะเห็นว่าหน้าเว็บไซต์มีขนาดเท่ากับขนาดของ Browser (จากรูปข้างบน ผมกำหนดให้ รูปมีขนาด 100vh)

ทีนี้ลองเปลี่ยนเป็นแสดงผลตามขนาดจอ Mobile ใน browser ดู

100vh on chrome (mobile screen)

จะเห็นว่าการแสดงผล ก็ขึ้นอยู่กับเปอร์เซ็นต์ความสูงของ device นั้นๆ ในที่นี้กำหนดให้รูปเท่ากับ 100vh ความสูงเลยเท่ากับ 100% ของ viewport

หากลองเข้าไปดูที่เว็บ https://caniuse.com จะเห็นว่า Browser หลายๆตัว ก็รองรับ Viewport กันหมดแล้ว

https://caniuse.com/#feat=viewport-units

แต่ 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">

References

--

--