บทช่วยสอนเค้าโครง 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 แบบคลาสสิก

กวดวิชา CSS

สำหรับผู้เริ่มต้น นี่คือมาร์กอัป 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 แบบคลาสสิก

ข้อกำหนดระบุว่าโดยค่าเริ่มต้นเมนูการนำทางของเราจะแสดงเฉพาะไอคอน แต่จะสามารถขยายเพื่อแสดงข้อความได้เช่นกัน (และจากนั้นสามารถยุบเพื่อแสดงเฉพาะไอคอนอีกครั้งได้อีกครั้ง)

บทช่วยสอน CSS2 และ CSS3

เริ่มต้นด้วยการเพิ่ม 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 แบบคลาสสิก

ตอนนี้ มาดูข้อกำหนดของการมีบางหน้าที่ซ่อนเมนูนำทางย่อย โดยเฉพาะอย่างยิ่ง เราต้องการซ่อนเมนูการนำทางย่อยเมื่อผู้ใช้คลิกไอคอน "ผู้ใช้" ในพื้นที่การนำทางหลัก

CSS layour กวดวิชา

ก่อนอื่น เราจะสร้างคลาสใหม่ "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: ระบุขนาดเริ่มต้นของไอเท็ม (เช่น ก่อนที่มันจะย่อหรือขยาย)

คอนเทนเนอร์แบบยืดหยุ่น CSS: ข้ามกับ main

การตั้งค่า 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 ซึ่งแทนเศษส่วนของพื้นที่ว่างในคอนเทนเนอร์กริด

ร่างเค้าโครงตาราง CSS

นี่คือมาร์กอัปทางเลือกที่เราสามารถใช้ได้หากเราใช้เลย์เอาต์ 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 มีที่มัน!

ที่เกี่ยวข้อง: *การสำรวจ SMACSS: สถาปัตยกรรมที่ปรับขนาดได้และโมดูลาร์สำหรับ CSS*