บทช่วยสอนเค้าโครง CSS: จากแนวทางคลาสสิกไปจนถึงเทคนิคล่าสุด
เผยแพร่แล้ว: 2022-03-11การเรียนรู้เค้าโครงเว็บโดยไม่ต้องเรียนรู้ CSS นั้นเป็นไปได้พอๆ กับการเรียนรู้การว่ายน้ำบนบก แต่แตกต่างจากการว่ายน้ำ ซึ่งเมื่อเชี่ยวชาญแล้ว ก็คือทักษะที่จะคงอยู่กับคุณไปตลอดชีวิต การเรียนรู้ CSS เป็นกระบวนการที่ไม่มีวันสิ้นสุดจริงๆ เนื่องจาก CSS เองมีการพัฒนาอย่างต่อเนื่อง
ความท้าทายนั้นรุนแรงขึ้นด้วยความแตกต่างในการใช้งาน CSS และการสนับสนุนในเบราว์เซอร์ต่างๆ (และแม้แต่ในเบราว์เซอร์เดียวกันในเวอร์ชันต่างๆ) รวมถึงอัตราการยอมรับคำแนะนำ CSS ที่แตกต่างกัน เป็นเวลากว่าทศวรรษแล้วที่นักออกแบบเว็บไซต์และนักพัฒนาต้องต่อสู้กับฟีเจอร์ CSS3 เพิ่มเติมที่ได้รับการสนับสนุนเป็นระยะๆ และไม่สอดคล้องกันในเบราว์เซอร์เวอร์ชันใหม่แต่ละเวอร์ชัน
แต่อย่างไรก็ตาม การเรียนรู้ CSS เป็นสิ่งจำเป็นอย่างยิ่งสำหรับนักออกแบบเว็บไซต์หรือนักพัฒนาซอฟต์แวร์ บทความนี้จะแนะนำคุณเกี่ยวกับหลักการพื้นฐานของเลย์เอาต์ CSS ตั้งแต่เทคนิค CSS2 แบบคลาสสิกไปจนถึงเลย์เอาต์ล่าสุดใน CSS3
หมายเหตุ: ตัวอย่างโค้ดทั้งหมดในบทความนี้ใช้องค์ประกอบ HTML5 และไวยากรณ์ Sass รหัสการทำงานแบบเต็มสามารถโคลนได้จาก https://github.com/laureanoarcanio/css-layout-examples
ใช้กรณี
วิธีที่ดีที่สุดวิธีหนึ่งในการเรียนรู้เทคโนโลยีคือการมีกรณีการใช้งานเฉพาะที่คุณพยายามจะสนับสนุนหรือปัญหาเฉพาะที่คุณพยายามแก้ไข ในตอนท้าย เราจะเน้นที่กรณีการใช้งานที่มีข้อกำหนดเฉพาะ
กรณีการใช้งานของเราประกอบด้วยเค้าโครง Web App ที่มีพฤติกรรมแบบไดนามิกบางอย่าง โดยจะมีองค์ประกอบคงที่ในหน้า เช่น ส่วนหัว ส่วนท้าย เมนูการนำทาง และการนำทางย่อย ตลอดจนส่วนเนื้อหาที่เลื่อนได้ ต่อไปนี้คือข้อกำหนดเฉพาะของเลย์เอาต์:
- เค้าโครงพื้นฐาน
- ส่วนหัว ส่วนท้าย เมนูการนำทาง และการนำทางย่อยทั้งหมดยังคงคงที่บน scroll
- องค์ประกอบการนำทางและการนำทางย่อยใช้พื้นที่ว่างในแนวตั้งทั้งหมด
- ส่วนเนื้อหาใช้พื้นที่ว่างที่เหลืออยู่ทั้งหมดบนหน้าและมีพื้นที่ที่เลื่อนได้
- พฤติกรรมแบบไดนามิก
- เมนูการนำทางจะแสดงเฉพาะไอคอนตามค่าเริ่มต้น แต่สามารถขยายเพื่อแสดงข้อความได้เช่นกัน (แล้วสามารถยุบเพื่อแสดงเฉพาะไอคอนได้อีกครั้ง)
- รูปแบบเค้าโครง
- บางหน้ามีการนำทางย่อยถัดจากเมนูการนำทางและบางหน้าไม่มี
บทช่วยสอน CSS โดยใช้เทคนิค CSS2 แบบคลาสสิก
สำหรับผู้เริ่มต้น นี่คือมาร์กอัป HTML5 ที่เราจะใช้กับตัวอย่างการใช้งานโดยใช้ CSS แบบคลาสสิก:
<body class="layout-classic"> <header></header> <nav></nav> <aside></aside> <main></main> <footer></footer> </body>
ตำแหน่งคงที่
ใน CSS2 เราสามารถบรรลุองค์ประกอบคงที่บนหน้า (ส่วนหัว ส่วนท้าย ฯลฯ) โดยใช้รูปแบบการจัดวางตำแหน่งที่ใช้ตำแหน่งคงที่
นอกจากนี้ เราจะใช้คุณสมบัติ CSS z-index
เพื่อให้แน่ใจว่าองค์ประกอบคงที่ของเรายังคง "อยู่ด้านบนสุดของ" เนื้อหาอื่นๆ ในหน้า คุณสมบัติ z-index
ระบุลำดับการเรียงซ้อนขององค์ประกอบ โดยที่องค์ประกอบที่มีลำดับการเรียงซ้อนมากกว่ามักจะ "อยู่ด้านบนสุดของ" องค์ประกอบที่มีลำดับการเรียงซ้อนที่ต่ำกว่า โปรดทราบว่าคุณสมบัติ z-index
งานได้กับองค์ประกอบที่มี ตำแหน่ง เท่านั้น สำหรับตัวอย่างของเรา เราจะใช้ค่า z-index
20 โดยพลการ (ซึ่งสูงกว่าค่าเริ่มต้น) เพื่อให้แน่ใจว่าองค์ประกอบคงที่ของเรายังคงมองเห็นได้ในระดับแนวหน้า
นอกจากนี้ เราจะตั้งค่าคุณสมบัติ width
เป็น 100% ซึ่งสั่งให้เบราว์เซอร์ใช้พื้นที่ว่างทั้งหมดในแนวนอนสำหรับองค์ประกอบ
#header, #footer { position: fixed; width: 100%; z-index: 20; } #header { top: 0; height: 5em; } #footer { bottom: 0; height: 3em; }
ตกลง นั่นคือส่วนหัวและส่วนท้าย แล้ว #nav
และ #subnav
ล่ะ ?
การขยาย CSS
สำหรับ #nav
และ #subnav
เราจะใช้เทคนิคที่ซับซ้อนกว่าเล็กน้อยที่เรียกว่า CSS Expansion ซึ่งสามารถใช้เมื่อวางตำแหน่งองค์ประกอบเป็น แบบคงที่ (เช่น ที่ตำแหน่งคงที่บนหน้า) หรือ แบบสัมบูรณ์ (เช่น ที่ ตำแหน่งที่ระบุโดยสัมพันธ์กับ ตำแหน่ง ที่ใกล้เคียงที่สุดหรือกับบล็อกที่บรรจุอยู่)
การขยายแนวตั้งทำได้โดยการตั้งค่าคุณสมบัติ top
และ bottom
ขององค์ประกอบให้เป็นค่าคงที่ ดังนั้นองค์ประกอบจะขยายในแนวตั้งเพื่อใช้พื้นที่แนวตั้งที่เหลือตามลำดับ โดยพื้นฐานแล้ว สิ่งที่คุณทำคือการผูกส่วนบนขององค์ประกอบเข้ากับระยะห่างเฉพาะจากด้านบนของหน้าและด้านล่างขององค์ประกอบจนถึงระยะที่กำหนดจากด้านล่างของหน้า ดังนั้นองค์ประกอบจะขยายเพื่อเติมเต็มพื้นที่แนวตั้งทั้งหมด ระหว่างสองจุดนั้น
ในทำนองเดียวกัน การขยายแนวนอนทำได้โดยการตั้งค่าทั้งคุณสมบัติ left
และ right
ขององค์ประกอบให้เป็นค่าคงที่ ดังนั้นองค์ประกอบจะขยายในแนวนอนเพื่อใช้พื้นที่แนวนอนที่เหลือตามลำดับ
สำหรับกรณีการใช้งานของเรา เราจำเป็นต้องใช้การขยายแนวตั้ง
#nav, #subnav { position: fixed; top: 6em; /* leave 1em margin below header */ bottom: 4em; /* leave 1em margin above footer */ z-index: 20; } #nav { left: 0; width: 5em; } #subnav { left: 6em; /* leave 1em margin to right of nav */ width: 13em; }
ตำแหน่งเริ่มต้น (คงที่)
พื้นที่เนื้อหาที่เลื่อนได้หลักสามารถพึ่งพาการวางตำแหน่งเริ่มต้น (คงที่) ได้โดยง่าย โดยองค์ประกอบจะแสดงผลตามลำดับตามที่ปรากฏในโฟลว์เอกสาร เนื่องจากทุกสิ่งทุกอย่างในหน้าของเราอยู่ในตำแหน่งคงที่ องค์ประกอบนี้จึงเป็นองค์ประกอบเดียวที่อยู่ในโฟลว์ของเอกสาร ด้วยเหตุนี้ สิ่งที่เราต้องทำเพื่อวางตำแหน่งอย่างถูกต้องคือการระบุคุณสมบัติของ margin
เพื่อหลีกเลี่ยงการทับซ้อนกับส่วนหัว ท้ายกระดาษ และการนำทาง/การนำทางย่อยแบบคงที่:
#main { margin: 6em 0 4em 20em; }
และด้วยเหตุนี้ เราจึงตอบสนองความต้องการเค้าโครงพื้นฐานของกรณีการใช้งานของเราโดยใช้ CSS2 แล้ว แต่เรายังต้องปฏิบัติตามข้อกำหนดเพิ่มเติมสำหรับฟังก์ชันการทำงานแบบไดนามิก
พฤติกรรมแบบไดนามิกโดยใช้เทคนิค CSS2 แบบคลาสสิก
ข้อกำหนดระบุว่าโดยค่าเริ่มต้นเมนูการนำทางของเราจะแสดงเฉพาะไอคอน แต่จะสามารถขยายเพื่อแสดงข้อความได้เช่นกัน (และจากนั้นสามารถยุบเพื่อแสดงเฉพาะไอคอนอีกครั้งได้อีกครั้ง)
เริ่มต้นด้วยการเพิ่ม 5em
ให้กับความกว้างของเมนูการนำทางเมื่อขยายออก เราจะทำสิ่งนี้โดยการสร้างคลาส CSS "ขยาย" ที่เราสามารถเพิ่มหรือลบออกจากองค์ประกอบเมนูการนำทางแบบไดนามิก:
#nav { left: 0; width: 5em; &.expanded { /* Sass notation */ width: 10em; } }
ต่อไปนี้คือตัวอย่างโค้ด JavaScript (ในตัวอย่างนี้ เราใช้ jQuery) ที่สามารถใช้เพื่อสลับเมนูการนำทางแบบไดนามิกระหว่างโหมดขยายและโหมดยุบ โดยขึ้นอยู่กับผู้ใช้ที่คลิกไอคอนสลับการนำทาง:
$('.layout-classic #nav').on('click', 'li.nav-toggle', function() { $('#nav'').toggleClass('expanded'); });
และด้วยเหตุนี้ เมนูการนำทางของเราสามารถขยายหรือยุบแบบไดนามิกได้ ยอดเยี่ยม.
ดีมาก แต่ก็ไม่เชิง แม้ว่าเมนูการนำทางจะสามารถขยายและย่อได้ แต่ไม่สามารถเล่นได้กับส่วนที่เหลือของหน้า ขณะนี้เมนูการนำทางแบบขยายทับซ้อนกับการนำทางย่อยซึ่งไม่ใช่ลักษณะการทำงานที่ต้องการอย่างแน่นอน
สิ่งนี้เผยให้เห็นหนึ่งในข้อจำกัดที่สำคัญของ CSS2; กล่าวคือ มี วิธี มากเกินไปที่จะต้องฮาร์ดโค้ดด้วยค่าตำแหน่งคงที่ ด้วยเหตุนี้ สำหรับองค์ประกอบอื่นๆ บนหน้าที่จำเป็นต้องจัดตำแหน่งใหม่เพื่อรองรับเมนูการนำทางที่ขยาย เราจำเป็นต้องกำหนดคลาส CSS ที่ "ขยาย" เพิ่มเติม ด้วยค่าตำแหน่งคงที่ที่ มากขึ้น
#subnav { left: 6em; width: 13em; &.expanded { left: 11em; /* move it on over */ } } #main { margin: 6em 0 4em 20; z-index: 10; &.expanded { margin-left: 25em; /* move it on over */ } }
จากนั้นเราจำเป็นต้องขยายโค้ด JavaScript ของเราเพื่อเพิ่มการปรับแบบไดนามิกขององค์ประกอบอื่นๆ เหล่านี้เช่นกันเมื่อผู้ใช้คลิกสลับการนำทาง:
$('.layout-classic #nav').on('click', 'li.nav-toggle', function() { $('#nav, #subnav, #main').toggleClass('expanded'); });
ตกลงที่ทำงานได้ดีขึ้น
รูปแบบเลย์เอาต์โดยใช้เทคนิค CSS2 แบบคลาสสิก
ตอนนี้ มาดูข้อกำหนดของการมีบางหน้าที่ซ่อนเมนูนำทางย่อย โดยเฉพาะอย่างยิ่ง เราต้องการซ่อนเมนูการนำทางย่อยเมื่อผู้ใช้คลิกไอคอน "ผู้ใช้" ในพื้นที่การนำทางหลัก
ก่อนอื่น เราจะสร้างคลาสใหม่ "hidden" ที่ใช้ display: none
:
.hidden { display: none; }
และอีกครั้ง เราจะใช้ JavaScript (jQuery) เพื่อใช้คลาส CSS "ที่ซ่อน" กับองค์ประกอบ #subnav
เมื่อผู้ใช้คลิกที่ไอคอนผู้ใช้:
$('#nav.fa-user').on('click', function() { $('#subnav').toggleClass('hidden'); });
ด้วยการเพิ่มนี้ องค์ประกอบ #subnav
จะถูกซ่อนไว้อย่างเหมาะสมเมื่อผู้ใช้คลิกที่ไอคอน "ผู้ใช้" แต่พื้นที่ที่ถูกครอบครองนั้นยังคงไม่ได้ใช้ แทนที่จะเป็นองค์ประกอบอื่น ๆ ที่ขยายเพื่อใช้พื้นที่ว่างโดยองค์ประกอบ #subnav
เพื่อให้ได้พฤติกรรมที่ต้องการเมื่อเราซ่อนองค์ประกอบ #subnav
เราจะใช้หนึ่งในตัวเลือก CSS ที่รู้จักกันน้อยแต่มีประโยชน์อย่างมากซึ่งเรียกว่า ตัวเลือกพี่น้องที่อยู่ติดกัน
ตัวเลือก CSS พี่น้องที่อยู่ติดกัน
ตัวเลือกพี่น้องที่อยู่ติดกันช่วยให้คุณระบุสององค์ประกอบ โดยเลือกเฉพาะอินสแตนซ์ขององค์ประกอบที่สองที่ตามหลังองค์ประกอบแรกที่ระบุทันที
ตัวอย่างเช่น รายการต่อไปนี้จะเลือกเฉพาะองค์ประกอบที่มี ID main
ที่ตาม หลัง องค์ประกอบที่มี ID subnav
:
#subnav + #main { margin-left: 20em; }
ข้อมูลโค้ด CSS ด้านบนตั้งค่าระยะขอบด้านซ้ายของ #main
เป็น 20em
เฉพาะในกรณี ที่ติดตาม #subnav
ที่แสดงในทันที
อย่างไรก็ตาม หาก #nav
ถูกขยาย (ซึ่งทำให้เพิ่มคลาสที่ expanded
ใน #main
ด้วย ตามรหัสก่อนหน้าของเรา) เราจะย้ายระยะขอบด้านซ้ายของ #main
เป็น 25em
#subnav + #main.expanded { margin-left: 25em; }
และถ้า #subnav
ถูกซ่อน เราจะย้ายระยะขอบด้านซ้ายของ #main
ไปจนถึง 6em ให้อยู่ติดกับ #nav
:
#subnav.hidden + #main { margin-left: 6em; }
(หมายเหตุ: ข้อเสียอย่างหนึ่งของการใช้ตัวเลือกพี่น้องที่อยู่ติดกันคือมันบังคับให้เรามี #subnav
อยู่ใน DOM เสมอ ไม่ว่าจะแสดงหรือไม่ก็ตาม)
สุดท้าย หาก #subnav
ถูกซ่อน และ #nav
ถูกขยาย เราจะตั้งค่าระยะขอบด้านซ้ายของ #main
ที่ 11em
:
#subnav.hidden + #main.expanded { margin-left: 11em; }
สิ่งนี้ทำให้เราสามารถเชื่อมโยงสิ่งต่าง ๆ เข้าด้วยกันโดยไม่ต้องใช้โค้ด JavaScript ที่หนักหน่วง แต่เราสามารถเห็นได้ว่าโค้ดนี้ซับซ้อนเพียงใดหากเราเพิ่มองค์ประกอบเพิ่มเติมลงในหน้า เราเห็นอีกครั้งว่าด้วย CSS2 นั้นจำเป็นต้องมีการฮาร์ดโค้ดของค่าตำแหน่ง จำนวนมาก เพื่อให้สิ่งต่าง ๆ ทำงานได้อย่างถูกต้อง
ใช้ประโยชน์จาก CSS3
CSS3 นำเสนอฟังก์ชันการทำงานและเทคนิคการจัดวางที่ได้รับการปรับปรุงอย่างมาก ซึ่งทำให้ง่ายต่อการใช้งานและไม่ต้องพึ่งพาค่าฮาร์ดโค้ดมากนัก CSS3 ได้รับการออกแบบมาโดยเนื้อแท้เพื่อรองรับพฤติกรรมแบบไดนามิกมากขึ้นและ "ตั้งโปรแกรมได้" ในแง่นั้น ลองตรวจสอบความสามารถใหม่เหล่านี้ที่เกี่ยวข้องกับกรณีการใช้งานของเรา
CSS3 calc()
ฟังก์ชั่น
ฟังก์ชัน CSS3 calc()
ใหม่ สามารถใช้ในการคำนวณค่าคุณสมบัติ CSS แบบไดนามิกได้ (แต่โปรดทราบว่าการรองรับจะแตกต่างกันไปตามเบราว์เซอร์) นิพจน์ที่จัดเตรียมให้กับฟังก์ชัน calc()
สามารถเป็นนิพจน์ง่ายๆ ที่รวมตัวดำเนินการเลขคณิตพื้นฐาน ( +
, -
, *
, /
) โดยใช้กฎการมาก่อนตัวดำเนินการมาตรฐาน
การใช้ฟังก์ชัน calc()
สามารถช่วยหลีกเลี่ยงฮาร์ดโค้ดของค่าต่างๆ ที่ CSS2 ต้องการได้ ในกรณีของเรา สิ่งนี้ช่วยให้เราสามารถขยาย CSS ได้แบบไดนามิกมากขึ้น ตัวอย่างเช่น:
#nav, #subnav { position: fixed; height: calc(100% - 10em); /* replaces */ z-index: 20; }
ด้วยข้อกำหนด height
ด้านบนโดยใช้ฟังก์ชัน calc()
เราได้ผลลัพธ์เช่นเดียวกับที่เราทำใน CSS2 ด้วย top:6em
และ bottom:4em
แต่มีความยืดหยุ่นและปรับเปลี่ยนได้ดีกว่ามาก และไม่จำเป็นต้องฮาร์ดโค้ดตำแหน่ง top
และ bottom
ค่านิยม
CSS3 Flexbox Layout
Flexbox เป็นเลย์เอาต์ใหม่ที่นำมาใช้ใน CSS3 (การสนับสนุนแตกต่างกันไปตามเบราว์เซอร์) เลย์เอาต์ flexbox ทำให้ง่ายต่อการจัดเรียงองค์ประกอบบนหน้าในลักษณะที่สามารถคาดเดาได้บนขนาดหน้าจอ ความละเอียด และอุปกรณ์ต่างๆ ดังนั้นจึงมีประโยชน์อย่างยิ่งในบริบทของการออกแบบเว็บที่ตอบสนอง
คุณสมบัติที่สำคัญ ได้แก่ :
- การวางตำแหน่งองค์ประกอบย่อยนั้นง่ายกว่ามากและการจัดวางที่ซับซ้อนสามารถทำได้ง่ายกว่าและด้วยโค้ดที่สะอาดกว่า
- องค์ประกอบย่อยสามารถจัดวางได้ในทิศทางใดก็ได้และมีขนาดที่ยืดหยุ่นเพื่อปรับให้เข้ากับพื้นที่แสดงผล
- องค์ประกอบย่อยจะขยายสัญญาโดยอัตโนมัติเพื่อปรับให้เข้ากับพื้นที่ว่างที่มีอยู่
Flexbox นำเสนอชุดคำศัพท์และแนวคิดที่เป็นเอกลักษณ์ของตัวเอง สิ่งเหล่านี้รวมถึง:
- คอนเทนเนอร์แบบยืดหยุ่น องค์ประกอบที่มีคุณสมบัติการ
display
ที่ตั้งค่าเป็นflex
หรือinline-flex
ซึ่งทำหน้าที่เป็นองค์ประกอบคอนเทนเนอร์สำหรับรายการ flex - รายการแบบยืดหยุ่น องค์ประกอบใดๆ ภายในคอนเทนเนอร์แบบยืดหยุ่น (หมายเหตุ: ข้อความที่อยู่ในคอนเทนเนอร์ flex โดยตรงจะถูกรวมไว้ในรายการ flex ที่ไม่ระบุชื่อ)
- แกน . เลย์เอาต์ flexbox ทุกอันมี
flex-directio
n ที่กำหนด แกนหลัก ตามที่วางรายการ flex แกนไขว้ จะเป็นแกนตั้งฉากกับแกนหลัก - เส้น รายการ Flex สามารถวางได้ทั้งในบรรทัดเดียวหรือหลายบรรทัดตามคุณสมบัติ
flex-wrap
- ขนาด ความสูงและความกว้างเทียบเท่าของ flexbox
main size
cross size
ซึ่งระบุขนาดของแกนหลักและแกนตัดของคอนเทนเนอร์แบบยืดหยุ่น ตามลำดับ
โอเค ด้วยอินโทรสั้นๆ นั้น นี่คือมาร์กอัปทางเลือกที่เราสามารถใช้ได้หากเราใช้เลย์เอาต์ flexbox:

<body class="layout-flexbox"> <header></header> <div class="content-area"> <nav></nav> <aside></aside> <main></main> </div> <footer></footer> </body>
สำหรับตัวอย่างกรณีการใช้งาน เลย์เอาต์หลักของเรา (ส่วนหัว เนื้อหา ส่วนท้าย) เป็นแนวตั้ง ดังนั้นเราจะตั้งค่า flexbox ให้ใช้เลย์เอาต์คอลัมน์:
.layout-flexbox { display: flex; flex-direction: column; }
แม้ว่าเลย์เอาต์หลักของเราจะเป็นแนวตั้ง แต่องค์ประกอบในพื้นที่เนื้อหาของเรา (nav, subnav, main) จะถูกจัดวางในแนวนอน คอนเทนเนอร์แบบยืดหยุ่นแต่ละรายการสามารถกำหนดทิศทางได้เพียงทิศทางเดียว (เช่น เค้าโครงต้องเป็นแนวนอนหรือแนวตั้ง) ดังนั้น เมื่อเลย์เอาต์ต้องการมากกว่านี้ (กรณีทั่วไปสำหรับเลย์เอาต์ของแอพ) เราสามารถซ้อนคอนเทนเนอร์หลายอันเข้าด้วยกัน โดยแต่ละอันมีเลย์เอาต์ทิศทางต่างกัน
นั่นเป็นเหตุผลที่เราได้เพิ่มคอนเทนเนอร์พิเศษ (ที่ฉันเรียกว่า content-area
) การห่อ #nav
, #subnav
และ #main
ด้วยวิธีนี้ เค้าโครงโดยรวมสามารถเป็นแนวตั้งได้ ในขณะที่เนื้อหาของพื้นที่เนื้อหาสามารถจัดวางในแนวนอนได้
ตอนนี้เพื่อวางตำแหน่งรายการ flex ของเรา เราจะใช้คุณสมบัติ flex
ที่เป็นชวเลขสำหรับ flex: <flex-grow> <flex-shrink> <flex-basis>;
. คุณสมบัติ flex ทั้งสามนี้เป็นคุณสมบัติที่กำหนดวิธีที่รายการ flex ของเรากระจายพื้นที่ว่างที่เหลือระหว่างคุณสมบัติเหล่านี้ในทิศทางการไหล ดังนี้:
- flex-grow: ระบุว่าไอเท็มสามารถเติบโตได้มากเพียงใดเมื่อเทียบกับไอเท็มยืดหยุ่นที่เหลือภายในคอนเทนเนอร์เดียวกัน
- flex-shrink: ระบุวิธีที่รายการสามารถย่อให้สัมพันธ์กับรายการยืดหยุ่นที่เหลือภายในคอนเทนเนอร์เดียวกัน
- flex-basis: ระบุขนาดเริ่มต้นของไอเท็ม (เช่น ก่อนที่มันจะย่อหรือขยาย)
การตั้งค่า flex-grow
และ flex-shrink
เป็นศูนย์หมายความว่าขนาดของรายการได้ รับการแก้ไข และจะไม่ขยายหรือหดตัวเพื่อรองรับพื้นที่ว่างที่พร้อมใช้งานมากขึ้นหรือน้อยลง นี่คือสิ่งที่เราทำสำหรับส่วนหัวและส่วนท้ายของเรา เนื่องจากมีขนาดคงที่:
#header { flex: 0 0 5em; } #footer { flex: 0 0 3em; }
หากต้องการให้รายการใช้พื้นที่ว่างทั้งหมด ให้ตั้งค่า flex-grow
และ flex-shrink
เป็น 1 และตั้งค่า flex-basis
เป็น auto
นี่คือสิ่งที่เราทำสำหรับพื้นที่เนื้อหา เนื่องจากเราต้องการใช้พื้นที่ว่างที่มีอยู่ทั้งหมด
และดังที่เราได้กล่าวไว้ก่อนหน้านี้ เราต้องการให้รายการภายใน content-area
จัดวางในทิศทางของแถว ดังนั้นเราจะเพิ่ม display: flex
; และ flex-direction: row;
. สิ่งนี้ทำให้พื้นที่เนื้อหาเป็นคอนเทนเนอร์แบบยืดหยุ่นใหม่สำหรับ #nav
, #subnav
และ `#main
นี่คือสิ่งที่เราได้สำหรับ CSS สำหรับ content-area
:
.content-area { display: flex; flex-direction: row; flex: 1 1 auto; /* take up all available space */ margin: 1em 0; min-height: 0; /* fixes FF issue with minimum height */ }
ในพื้นที่เนื้อหา ทั้ง #nav
และ #subnav
มีขนาดคงที่ ดังนั้นเราจึงตั้งค่าคุณสมบัติ flex
ตามลำดับ:
#nav { flex: 0 0 5em; margin-right: 1em; overflow-y: auto; } #subnav { flex: 0 0 13em; overflow-y: auto; margin-right: 1em; }
(โปรดทราบว่าฉันได้เพิ่ม overflow-y: hidden
ในข้อกำหนด CSS เหล่านี้เพื่อเอาชนะเนื้อหาที่เกินและล้นความสูงของคอนเทนเนอร์ จริงๆ แล้ว Chrome ไม่ต้องการสิ่งนี้ แต่ FireFox ทำได้)
#main
จะใช้พื้นที่ว่างที่เหลือ:
#main { flex: 1 1 auto; overflow-y: auto; }
ทั้งหมดนี้ดูดี ดังนั้นตอนนี้ เรามาเพิ่มพฤติกรรมแบบไดนามิกของเราลงไปแล้วดูว่าจะเป็นอย่างไร
JavaScript นั้นเหมือนกับที่เรามีมาก่อน (ยกเว้นที่นี่ คลาสคอนเทนเนอร์องค์ประกอบ CSS ที่เราระบุคือ layout-flexbox
ในขณะที่ก่อนหน้านี้เป็น layout-classic
):
$('.layout-flexbox #nav').on('click', 'li.nav-toggle', function() { $('#nav').toggleClass('expanded'); });
เราเพิ่มคลาสที่ expanded
ไปยัง CSS ดังนี้:
#nav { flex: 0 0 5em; /* collapsed size */ margin-right: 1em; overflow-y: auto; &.expanded { flex: 0 0 10em; /* expanded size */ } }
แล้วโว้ย!
โปรดทราบว่าครั้งนี้เราไม่จำเป็นต้องแจ้งให้รายการอื่นทราบเกี่ยวกับการเปลี่ยนแปลงความกว้าง เนื่องจากเลย์เอาต์ flexbox จะจัดการทั้งหมดนั้นให้เรา
สิ่งเดียวที่เหลือคือการซ่อนการนำทางย่อย และคาดเดาอะไร? นั่น "ใช้งานได้" เช่นกัน โดยไม่มีการเปลี่ยนแปลงเพิ่มเติมใดๆ โดยใช้โค้ด JavaScript เดิมเหมือนเมื่อก่อน Flexbox รู้เกี่ยวกับพื้นที่ว่างและทำให้เลย์เอาต์ของเราทำงานโดยอัตโนมัติโดยไม่ต้องใช้โค้ดเพิ่มเติม สวยเย็น
Flexbox ยังมีวิธีที่น่าสนใจในการจัดกึ่งกลางองค์ประกอบทั้งแนวตั้งและแนวนอน เราตระหนักดีถึงความสำคัญของภาษาในการนำเสนอในการรวมแนวคิดเรื่องพื้นที่ว่างและความสามารถในการปรับขนาดโค้ดของเราโดยใช้เทคนิคประเภทต่างๆ เหล่านี้ ในทางกลับกัน แนวคิดและสัญกรณ์ที่นี่อาจต้องใช้เวลามากกว่าที่จะเชี่ยวชาญมากกว่า CSS แบบคลาสสิก
เค้าโครงกริด CSS3
หากเลย์เอาต์ Flexbox อยู่ที่ขอบชั้นนำของ CSS3 เลย์เอาต์กริดอาจกล่าวได้ว่าอยู่ที่ขอบเลือดออก ข้อมูลจำเพาะของ W3C ยังอยู่ในสถานะร่างและยังมีการรองรับเบราว์เซอร์ที่ค่อนข้างจำกัด (เปิดใช้งานใน Chrome ผ่านการตั้งค่าสถานะ “คุณลักษณะแพลตฟอร์มเว็บทดลอง” ใน chrome://flags)
ที่กล่าวว่าโดยส่วนตัวแล้วฉันไม่ถือว่าร่างนี้เป็นการปฏิวัติ แทนที่จะเป็นเช่นนั้น ตามหลักการออกแบบ HTML5 ระบุว่า: "เมื่อแนวปฏิบัติแพร่หลายในหมู่ผู้เขียนแล้ว ให้พิจารณานำไปใช้มากกว่าที่จะห้ามหรือคิดค้นสิ่งใหม่"
ด้วยเหตุนี้ กริดแบบมาร์กอัปจึงถูกใช้มาเป็นเวลานาน ดังนั้นตอนนี้ CSS Grid Layout เป็นเพียงการปฏิบัติตามกระบวนทัศน์เดียวกันเท่านั้น โดยนำเสนอประโยชน์ทั้งหมดและอื่น ๆ อีกมากมายในเลเยอร์การนำเสนอโดยไม่มีข้อกำหนดเกี่ยวกับมาร์กอัป
แนวคิดทั่วไปคือการมีเค้าโครงกริดที่กำหนดไว้ล่วงหน้า คงที่ หรือยืดหยุ่น ซึ่งเราสามารถจัดตำแหน่งองค์ประกอบของเราได้ เช่นเดียวกับ flexbox มันทำงานบนหลักการพื้นที่ว่างและช่วยให้เราสามารถกำหนด "ทิศทาง" ทั้งแนวตั้งและแนวนอนในองค์ประกอบเดียวกัน ซึ่งทำให้ได้เปรียบในด้านขนาดโค้ดและความยืดหยุ่น
เลย์เอาต์กริดแนะนำกริด 2 ประเภท; กล่าวโดย ชัดแจ้ง และ โดยปริยาย เพื่อความง่าย เราจะเน้นที่กริดที่ชัดเจนในเรื่องนี้
เช่นเดียวกับ flexbox เลย์เอาต์ Grid นำเสนอชุดคำศัพท์และแนวคิดที่เป็นเอกลักษณ์ของตัวเอง สิ่งเหล่านี้รวมถึง:
- คอนเทนเนอร์กริด องค์ประกอบที่มีคุณสมบัติการ
display
ที่ตั้งค่าเป็น "กริด" หรือ "อินไลน์กริด" ซึ่งองค์ประกอบที่มีอยู่จะถูกจัดวางโดยการจัดตำแหน่งและจัดแนวไปยังกริดที่กำหนดไว้ล่วงหน้า (โหมดที่ชัดเจน) ตารางเป็นชุดที่ตัดกันของเส้นตารางแนวนอนและแนวตั้งที่แบ่งพื้นที่ของคอนเทนเนอร์กริดออกเป็นเซลล์กริด เส้นกริดมีสองชุด อันหนึ่งสำหรับกำหนดคอลัมน์และอีกอันหนึ่งตั้งฉากสำหรับกำหนดแถว - ติดตามกริด ช่องว่างระหว่างเส้นกริดสองเส้นที่อยู่ติดกัน แทร็กกริดแต่ละแทร็กได้รับมอบหมายฟังก์ชันการปรับขนาด ซึ่งจะควบคุมความกว้างหรือความสูงของคอลัมน์หรือแถวที่อาจเติบโต และทำให้เส้นกริดที่ล้อมรอบอยู่ห่างกันมากเพียงใด
- เซลล์กริด ช่องว่างระหว่างสองแถวที่อยู่ติดกันและสองเส้นตารางของคอลัมน์ที่อยู่ติดกัน เป็นหน่วยที่เล็กที่สุดของกริดที่สามารถอ้างอิงได้เมื่อวางตำแหน่งรายการกริด
- ความยาวที่ยืดหยุ่นได้ มิติที่ระบุด้วยหน่วย
fr
ซึ่งแทนเศษส่วนของพื้นที่ว่างในคอนเทนเนอร์กริด
นี่คือมาร์กอัปทางเลือกที่เราสามารถใช้ได้หากเราใช้เลย์เอาต์ Grid:
<body class="layout-grid"> <header></header> <nav></nav> <aside></aside> <main></main> <footer></footer> </body>
โปรดทราบว่าด้วยเลย์เอาต์นี้ เรา ไม่ ต้องการแรปเปอร์เพิ่มเติมสำหรับพื้นที่เนื้อหาเหมือนที่เราทำกับ flexbox เนื่องจากเลย์เอาต์ประเภทนี้ช่วยให้เรากำหนดการกำหนดพื้นที่องค์ประกอบในทั้งสองทิศทางในคอนเทนเนอร์กริดเดียวกัน
มาเจาะลึกใน CSS กันตอนนี้:
.layout-grid { display: grid; grid-template-columns: auto 0 auto 1em 1fr; grid-template-rows: 5em 1em 1fr 1em 3em; }
เราได้กำหนด display: grid;
บนภาชนะของเรา คุณสมบัติ grid-template-columns
และ grid-template-rows
แต่ละคุณสมบัติถูกระบุเป็นรายการของช่องว่างระหว่างแทร็กกริด กล่าวอีกนัยหนึ่ง ค่าเหล่านั้นไม่ใช่ตำแหน่งของเส้นตาราง ค่อนข้างจะแทน ระยะห่าง ระหว่างสองแทร็ก
โปรดทราบว่าหน่วยการวัดสามารถระบุได้ดังนี้:
- ความยาว
- เปอร์เซ็นต์ของขนาดคอนเทนเนอร์กริด
- การวัดเนื้อหาที่ครอบครองคอลัมน์หรือแถวหรือ
- เศษของพื้นที่ว่างในกริด
ดังนั้นด้วย grid-template-columns: auto 0 auto 1em 1fr;
เราจะมี:
- 1 แทร็กที่กำหนดความกว้าง
auto
2 คอลัมน์ (#nav
space) - 1 รางน้ำเป็น 0 (ระยะขอบสำหรับ
#subnav
อยู่ที่ระดับองค์ประกอบ เนื่องจากจะมีหรือไม่ก็ได้ วิธีนี้จะทำให้เราไม่ให้มีรางน้ำคู่) - 1 แทร็กที่กำหนดความกว้าง
auto
2 คอลัมน์ (#subnav
space) - 1 รางน้ำ
1em
- 1 แทร็กใช้
1fr
สำหรับ#main
(จะใช้พื้นที่ที่เหลือทั้งหมด)
ที่นี่เราใช้ค่า auto
สำหรับแทร็กเป็นอย่างมาก ซึ่งช่วยให้เรามีคอลัมน์แบบไดนามิกที่ตำแหน่งและขนาดของเส้นกำหนดโดยเนื้อหาสูงสุด (ดังนั้น เราจะต้องระบุขนาดสำหรับองค์ประกอบ #nav
และ #subnav
ซึ่งเราจะดำเนินการในไม่ช้านี้)
ในทำนองเดียวกัน สำหรับบรรทัดของแถว เรามี grid-template-rows: 5em 1em 1fr 1em 3em;
ที่ตั้งค่า #header
และ #footer
ให้คงที่ และองค์ประกอบทั้งหมดระหว่างการใช้พื้นที่ว่างที่เหลือในขณะที่ใช้รางน้ำ 1em
ตอนนี้เรามาดูกันว่าเราวางองค์ประกอบจริงเพื่อวางตำแหน่งในตารางที่กำหนดไว้ได้อย่างไร:
#header { grid-column: 1 / 6; grid-row: 1 / 2; } #footer { grid-column: 1 / 6; grid-row: 5 / 6; } #main { grid-column: 5 / 6; grid-row: 3 / 4; overflow-y: auto; }
สิ่งนี้ระบุว่าเราต้องการให้ส่วนหัวอยู่ระหว่างเส้นตารางที่ 1 ถึง 6 (ความกว้างเต็ม) และระหว่างเส้นตารางที่ 1 และ 2 สำหรับแถวของเรา เหมือนกันสำหรับส่วนท้าย แต่ระหว่างสองบรรทัดสุดท้าย (แทนที่จะเป็นสองบรรทัดแรก) และพื้นที่หลักถูกจัดวางให้เหมาะสมกับพื้นที่ที่ควรจะเป็น
โปรดทราบว่าคุณสมบัติ grid-column
และ grid-row
เป็นชวเลขสำหรับการระบุ grid-column-start
/ grid-column-end
และ grid-row-start
/ grid-row-end
ตามลำดับ
ตกลง กลับไปที่ #nav
และ #subnav
เนื่องจากก่อนหน้านี้เราใส่ #nav
และ #subnav
ลงในแทร็กด้วยค่าอัตโนมัติ เราจึงต้องระบุความกว้างขององค์ประกอบเหล่านี้ (เช่นเดียวกันสำหรับโหมดขยาย เราเพียงแค่เปลี่ยนความกว้างและ Grid Layout จะดูแลส่วนที่เหลือ)
#nav { width: 5em; grid-column: 1 / 2; grid-row: 3 / 4; &.expanded { width: 10em; } } #subnav { grid-column: 3 / 4; grid-row: 3 / 4; width: 13em; /* track has gutter of 0, so add margin here */ margin-left: 1em; }
ตอนนี้เราสามารถสลับ #nav
และซ่อน/ลบ #subnav
และทำงานได้อย่างสมบูรณ์! เลย์เอาต์กริดยังช่วยให้เราใช้นามแฝงสำหรับบรรทัดของเรา ดังนั้นในที่สุดการเปลี่ยนกริดจะไม่แตกโค้ดออก เนื่องจากมันถูกแมปกับชื่อและไม่ใช่กริดไลน์ ตั้งตารอที่จะได้รับการสนับสนุนอย่างกว้างขวางจากเบราว์เซอร์มากขึ้นอย่างแน่นอน
บทสรุป
แม้จะมีเทคนิค CSS แบบคลาสสิก แต่ก็ยังมีอีกมากที่สามารถทำได้มากกว่าที่นักพัฒนาเว็บจำนวนมากตระหนักหรือใช้ประโยชน์จาก ที่กล่าวว่าสิ่งนี้ส่วนใหญ่ค่อนข้างน่าเบื่อและอาจเกี่ยวข้องกับฮาร์ดโค้ดของค่าซ้ำ ๆ กันตลอดทั้งสไตล์ชีต
CSS3 ได้เริ่มนำเสนอเทคนิคการจัดวางที่ซับซ้อนและยืดหยุ่นมากขึ้น ซึ่งง่ายต่อการตั้งโปรแกรมอย่างมาก และหลีกเลี่ยงความน่าเบื่อหน่ายกับข้อกำหนด CSS ก่อนหน้านี้
การเรียนรู้เทคนิคและกระบวนทัศน์เหล่านี้สำหรับ CSS2 และ CSS3 เป็นสิ่งจำเป็นในการใช้ประโยชน์จาก CSS ทั้งหมดที่มีเพื่อเพิ่มประสิทธิภาพทั้งประสบการณ์ของผู้ใช้และคุณภาพของโค้ดของคุณ บทความนี้เป็นเพียงส่วนเล็กสุดของภูเขาน้ำแข็งของทั้งหมดที่มีให้เรียนรู้และทุกสิ่งที่สามารถทำได้ด้วยพลังและความยืดหยุ่นของ CSS มีที่มัน!