บทช่วยสอน Flexbox และ Sass Grid: วิธีปรับปรุงการออกแบบที่ตอบสนองตามอุปกรณ์

เผยแพร่แล้ว: 2022-03-11

เมื่อเร็ว ๆ นี้ ฉันถูกท้าทายให้สร้างระบบกริดของตัวเอง และเนื่องจากการประดิษฐ์วงล้อใหม่นั้นมีประโยชน์เสมอในฐานะประสบการณ์การเรียนรู้ ฉันจึงลงมือทำ ฉันรู้ว่ามันจะเป็นความท้าทายที่น่าสนใจ แต่ฉันรู้สึกประหลาดใจที่มันกลายเป็นเรื่องง่าย!

กวดวิชา Sass และ Flexbox Grid

ในการทดลองนี้ เราจะพิจารณาเค้าโครงของ Flexbox และวิธีที่อนุญาตให้นำเค้าโครงไปใช้อย่างสง่างามโดยไม่ต้องทำการแฮ็กอย่างบ้าคลั่ง นอกจากนี้ หากคุณไม่คุ้นเคยกับ Sass เราจะมาดูกันว่ามันทำงานอย่างไรและใช้ยูทิลิตี้ Sass ที่มีประโยชน์ คุณอาจได้เรียนรู้สิ่งใหม่เกี่ยวกับกริด CSS เช่นเดียวกับที่เป็นส่วนหนึ่งของ Bootstrap

บทนำสั้นๆ ของ Sass และ Flexbox

โดยพื้นฐานแล้ว Sass เป็นเครื่องมือที่ช่วยให้คุณหลีกเลี่ยงข้อบกพร่องบางประการของ CSS ได้ มันคือภาษาสคริปต์ที่ตีความไปยัง CSS ไวยากรณ์ดูคุ้นเคยมากหากคุณกำลังเขียนสไตล์ CSS อยู่แล้ว แต่กล่องเครื่องมือของรูปแบบนั้นประกอบด้วยตัวแปร มิกซ์อินสำหรับการใช้งานซ้ำ และถ้า สำหรับ แต่ละรายการ และในขณะที่มีคำสั่งอื่นๆ สิ่งหนึ่งที่สะดวกที่สุดเกี่ยวกับ Sass คือโค้ด CSS ที่ถูกต้องคือ Sass ที่ถูกต้อง ดังนั้นคุณจึงสามารถแปลงฐานโค้ดของคุณไปเรื่อย ๆ

ตัวอย่างง่ายๆ ของ for loop:

 @for $i from 1 through 3 { .a-numbered-class-#{$i} { width: (20 * $i) * 1px; } }

วนซ้ำแบบง่ายนี้วนซ้ำจาก 1 ถึง 3 และสร้างคลาส ดัชนีของการวนซ้ำจะถูกเก็บไว้ใน $i เรายังสามารถทำคณิตศาสตร์และพิมพ์ .a-numbered-class-X สามครั้งโดยมีความกว้างต่างกันในแต่ละครั้ง รหัสนี้ส่งออก:

 .a-numbered-class-1 { width: 20px; } .a-numbered-class-2 { width: 40px; } .a-numbered-class-3 { width: 60px; }

ดังที่เราเห็น เราสามารถสรุปงานจำนวนมากที่คุณต้องทำใน CSS ใน CSS คุณต้องคัดลอกและวางและแก้ไขด้วยตนเอง ซึ่งเห็นได้ชัดว่ามีแนวโน้มที่จะเกิดข้อผิดพลาดและสวยงามน้อยลง หากคุณยังไม่ได้ลอง อย่าเสียเวลาอีกเลย!

Flexbox ย่อมาจาก Flexible Box ซึ่งเป็นระบบเลย์เอาต์ CSS3 ที่วางตำแหน่งและกระจายองค์ประกอบแบบไดนามิก เป็นเครื่องมือที่ทรงพลังมากที่ช่วยให้สามารถจัดวางเลย์เอาต์ที่ยืดหยุ่นได้โดยใช้ความพยายามเพียงเล็กน้อย สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการเรียนรู้ Flexbox โปรดดูคู่มือฉบับสมบูรณ์ของ Chris Coyier สำหรับ Flexbox

ตาราง

มาเริ่มกันที่องค์ประกอบพื้นฐานของกริดกันก่อน สิ่งเหล่านี้จะได้รับแรงบันดาลใจจากองค์ประกอบกริดของ Bootstrap: Containers, Rows และ Columns ซึ่งแต่ละรายการมีอยู่ภายในอดีต

เราจะใช้แบบแผนการตั้งชื่อ BEM สำหรับชื่อของคลาส แบบแผน BEM นั้นค่อนข้างใช้งานง่ายและเพิ่มข้อมูลมากมายเกี่ยวกับองค์ประกอบและบริบทของมัน พูดสั้น ๆ คุณมี:

  • Blocks ซึ่ง "ห่อหุ้มเอนทิตีแบบสแตนด์อโลนที่มีความหมายในตัวมันเอง": .block
  • Elements ซึ่งเป็น "ส่วนหนึ่งของบล็อกและไม่มีความหมายแบบสแตนด์อโลน" ซึ่งแสดงด้วยชื่อบล็อก ขีดล่างสองตัว และองค์ประกอบ: .block__elem
  • ตัวดัดแปลง เช่น “ตั้งค่าสถานะบนบล็อกหรือองค์ประกอบ” ซึ่งแสดงด้วยขีดกลางสองอัน: .block .block--mod

คอนเทนเนอร์ แถว และคอลัมน์

ตู้คอนเทนเนอร์

นี่คือองค์ประกอบที่อยู่นอกสุดของกริด มันจะประกอบด้วยองค์ประกอบแถวของเรา คอนเทนเนอร์มีสองประเภท: .container และ .container--fluid

ลักษณะการทำงานของ .container ถูกกำหนดโดยความกว้าง 100% ต่ำกว่าจุดใดจุดหนึ่ง โดยมีความกว้างคงที่สูงสุดด้านบน และมีระยะขอบเท่ากันทั้งซ้ายและขวา:

 $grid__bp-md: 768; .container { max-width: $grid__bp-md * 1px; margin: 0 auto; }

เล่นที่นี่โดยขยายและย่อหน้าต่าง "เอาต์พุต"

สำหรับคอนเทนเนอร์ของเหลวซึ่งมีความกว้าง 100% เสมอ เราเพียงแค่แทนที่คุณสมบัติเหล่านั้นด้วยตัวปรับแต่ง:

 &--fluid { margin: 0; max-width: 100%; }

เล่นกับมันที่นี่

นั่นเป็นเรื่องง่าย! ขณะนี้มีการติดตั้งคอนเทนเนอร์ทั้งสองแบบแล้ว มาดูองค์ประกอบต่อไปกัน

แถว

แถวจะเป็นตัวจัดระเบียบเนื้อหาในแนวนอนของเรา

เราจะใช้ Flexbox เพื่อจัดตำแหน่งองค์ประกอบย่อยของแถว ทำให้พวกเขาห่อเพื่อไม่ให้ล้นและให้ความกว้าง 100% ภายในแถว (เพื่อให้เราสามารถซ้อนได้ในภายหลัง)

 &__row { display: flex; flex-wrap: wrap; width: 100%; }

สิ่งนี้จะวางองค์ประกอบย่อยไว้เคียงข้างกัน และรวมเข้าด้วยกันเป็นบรรทัดใหม่ หากผลรวมของความกว้างมากกว่าตัวมันเอง ตอนนี้เราเพียงแค่ต้องเพิ่ม div เข้าไปและมันจะมีลักษณะดังนี้:

องค์ประกอบแถว

เล่นกับมันที่นี่โดยขยายและย่อหน้าต่าง "เอาต์พุต"

สิ่งต่าง ๆ เริ่มเป็นรูปเป็นร่าง แต่นี่ไม่ใช่กริด CSS มันหายไป…

คอลัมน์

คอลัมน์คือที่ที่เนื้อหาของไซต์อาศัยอยู่ พวกเขากำหนดจำนวนส่วนของแถวที่ถูกแบ่งและจำนวนที่พวกเขาครอบครอง เราจะทำโครงร่างสิบสองคอลัมน์ ซึ่งหมายความว่าเราสามารถแบ่งแถวเป็นหนึ่งหรือมากถึงสิบสองส่วน

เริ่มต้นด้วยคณิตศาสตร์พื้นฐานบางอย่าง เมื่อเราต้องการมีหนึ่งคอลัมน์ ความกว้างควรเป็น 100% ถ้าเราต้องการสิบสองคอลัมน์ จากนั้นแต่ละส่วนควรครอบครอง 8.333…% หรือ 100/12 ของความกว้าง

ด้วย Flexbox เพื่อแจกจ่ายเนื้อหาในลักษณะนี้ เราสามารถใช้ flex-basis ได้

ในการแบ่งออกเป็นสี่คอลัมน์ ตอนนี้เราจะเพิ่มบางอย่างเช่น:

 flex-basis: (100 / 4 ) * 1%;

ด้วยวิธีนี้ เราจะได้รับองค์ประกอบแต่ละองค์ประกอบเพื่อครอบครอง 25% ของความกว้าง—หรือเปอร์เซ็นต์ที่เราต้องการ

เล่นกับมันที่นี่

มาทำให้ไดนามิกมากขึ้นกันเถอะ เนื่องจากเราต้องการให้สิ่งนี้สะท้อนถึงคลาสที่เป็นไปได้ของเรา ให้เรียก .col-1 คลาสสำหรับคอลัมน์ div ที่จะมี 8.333% ของความกว้าง เนื่องจากสิบสองคลาสควรพอดีก่อนที่จะตัดขึ้นบรรทัดใหม่ เปอร์เซ็นต์จะเพิ่มขึ้นทั้งหมดจนถึง . .col-12 ซึ่งจะครอบครอง 100%

 $grid__cols: 12; @for $i from 1 through $grid__cols { .col-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } }

เพื่อชี้แจงว่าเกิดอะไรขึ้น สมมติว่าเราต้องการแบ่งความกว้างออกเป็นสี่ส่วนเท่าๆ กัน เราต้องการ .col-3 เนื่องจากมันพอดีกับ 4 เท่าใน 12 ซึ่งหมายความว่า .col-3 ควรมีพื้นฐานแบบยืดหยุ่น 25%:

 100 / ($grid__cols / $i) 100 / (12 / 3) = 25

นี่เริ่มดูเหมือนกริดแล้ว!

ดูเหมือนกริด!

เล่นกับมันที่นี่

คอลัมน์ขึ้นอยู่กับความกว้างของหน้าจอ

ตอนนี้เราต้องการให้มีองค์ประกอบที่มีความกว้างที่แน่นอนบนมือถือ แต่ต่างกันบนแท็บเล็ตและอื่นๆ เราจะใช้เบรกพอยต์ขึ้นอยู่กับความกว้างของหน้าต่าง UI ของเราจะตอบสนองต่อเบรกพอยต์เหล่านั้นและปรับให้เข้ากับเลย์เอาต์ที่เหมาะสมกับขนาดหน้าจอของอุปกรณ์ต่างๆ เราจะตั้งชื่อเบรกพอยต์ตามขนาด: เล็ก (sm), กลาง (md) และอื่น ๆ . .col-sm-12 จะเป็นองค์ประกอบที่ครอบครอง 12 คอลัมน์อย่างน้อยก็จนกว่าเบรกพอยต์ sm

มาเปลี่ยนชื่อ .col-* class .col-sm-* เนื่องจากกริดของเราจะเป็นแบบเคลื่อนที่ก่อน เราจะใช้คุณสมบัติของกริดกับหน้าจอทุกขนาด เราจะเพิ่มคลาส: .col-md-* ให้กับหน้าจอที่ใหญ่กว่าเดิม

ลองนึกภาพองค์ประกอบที่มี .col-sm-12 และ .col-md-4 ลักษณะการทำงานที่คาดไว้คือด้านล่างเบรกพอยต์ “md” (ปานกลาง) จะมีความกว้าง 100% และสูงกว่านั้นจะมี 33.333% ซึ่งเป็นเหตุการณ์ที่เกิดขึ้นบ่อยมาก เนื่องจากในอุปกรณ์เคลื่อนที่ คุณอาจต้องซ้อนองค์ประกอบไว้ด้านบนแทนที่จะอยู่ถัดจาก กันเมื่อความกว้างของคุณมีจำกัดมากขึ้น

การซ้อนคอลัมน์หลังจากกดเบรกพอยต์

สำหรับสิ่งนี้ เราจะต้องเพิ่มการสืบค้นสื่อ (นิพจน์ที่มีโค้ดที่จะรันเฉพาะด้านบนหรือด้านล่างของความกว้างหรืออุปกรณ์เฉพาะ) ที่จุดพักและสร้างคอลัมน์ md ของเราเหมือนที่เราทำก่อนหน้านี้สำหรับ sm :

 @media screen and (min-width: $grid__bp-md * 1px) { @for $i from 1 through $grid__cols { &__col-md-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } } }

เล่นกับมันที่นี่

มันใกล้จะมีประโยชน์แล้ว ค่อนข้างเปียก (เข้าใจไหม มันไม่แห้ง…) เรามาทำให้มันเป็นนามธรรมกันดีกว่า

ตามที่เราเห็น เราจำเป็นต้องมีการสืบค้นสื่อสำหรับเบรกพอยต์แต่ละจุด ดังนั้น เรามาสร้างมิกซ์อินที่ได้รับเบรกพอยต์ที่สร้างคิวรีสื่อแบบไดนามิกกัน อาจมีลักษณะดังนี้:

 @mixin create-mq($breakpoint) { @if($breakpoint == 0) { @content; } @else { @media screen and (min-width: $breakpoint *1px) { @content; } } }

ตอนนี้ เรามาห่อสิ่งที่เรามีเพื่อสร้างคลาส __col ในมิกซ์อินที่เรียกว่า create-col-classes และใช้ create-mq mq mixin

 @mixin create-col-classes($modifier, $grid__cols, $breakpoint) { @include create-mq($breakpoint) { @for $i from 1 through $grid__cols { &__col#{$modifier}-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } } } }

และนั่นแหล่ะ ในการใช้งาน ตอนนี้เรากำหนดเบรกพอยต์ของเราในแผนที่ Sass และทำซ้ำ

 $map-grid-props: ('-sm': 0, '-md': $grid__bp-md, '-lg': $grid__bp-lg); @each $modifier , $breakpoint in $map-grid-props { @include create-col-classes($modifier, $grid__cols, $breakpoint); }

ระบบกริดของเราเสร็จสิ้นโดยพื้นฐานแล้ว! เราได้กำหนด .container__col-sm-* ที่จะเป็นค่าเริ่มต้น และเราสามารถปรับเปลี่ยนพฤติกรรมของมันบนหน้าจอที่ใหญ่ขึ้นด้วย container__col-md-* และ container__col-lg-*

เราสามารถซ้อนแถวได้! เล่นกับมันที่นี่

สิ่งที่ดีเกี่ยวกับสิ่งนี้คือถ้าตอนนี้เราต้องการให้มีเบรกพอยต์แบบเดียวกับ Bootstrap v4 เราก็ต้องทำ:

 $grid__bp-sm: 576; $grid__bp-md: 768; $grid__bp-lg: 992; $grid__bp-xl: 1200; $map-grid-props: ( '': 0, '-sm': $grid__bp-sm, '-md': $grid__bp-md, '-lg': $grid__bp-lg, '-xl': $grid__bp-xl );

และนั่นแหล่ะ! เล่นกับมันที่นี่

สังเกตว่า Bootstrap ใช้แนวทางมือถือเป็นอันดับแรกอย่างสมบูรณ์กว่าที่เราพูดถึงในตอนแรกอย่างไร ขนาดหน้าต่างที่เล็กที่สุดไม่มีส่วนต่อท้ายเช่น sm หรือ md เหตุผลก็คือคลาสที่เทียบเท่ากับ .container__col-X จะไม่ถูกนำไปใช้จากความกว้างหน้าต่าง 0 ถึง 576px เท่านั้น ถ้าเราไม่เขียนทับอย่างชัดแจ้ง จะเป็นจำนวนคอลัมน์นั้นในทุกขนาดหน้าต่าง มิฉะนั้น เราสามารถเพิ่มคลาส .container__col-sm-Y เพื่อทำให้เป็นความกว้างของคอลัมน์ Y ระหว่างจุดสั่งหยุด sm

ออฟเซ็ต

ออฟเซ็ตจะเพิ่มระยะขอบด้านซ้ายโดยคำนึงถึงคอลัมน์ก่อนหน้า .container__col-offset-4 จะเพิ่ม margin-left: 33.333% ในทุกขนาดหน้าจอ .container__col-md-offset-4 จะทำเช่นเดียวกัน แต่อยู่เหนือเบรกพอยต์ md

การดำเนินการนี้เป็นเรื่องเล็กน้อย เราเพิ่มคุณสมบัติ -offset ในลูปเดียวกันที่เราสร้างคลาส แต่แทนที่จะเป็น flex-bases เราเขียนคุณสมบัติ margin-left เราต้องทำสิ่งเพิ่มเติมสำหรับ -offset-0 ด้วย เนื่องจากเราอาจต้องการล้างระยะขอบบนหน้าจอที่ใหญ่ขึ้น:

 @mixin create-col-classes($modifier, $grid-cols, $breakpoint) { @include create-mq($breakpoint) { &__col#{$modifier}-offset-0 { margin-left: 0; } @for $i from 1 through $grid-cols { &__col#{$modifier}-#{$i} { flex-basis: (100 / ($grid-cols / $i) ) * 1%; } &__col#{$modifier}-offset-#{$i} { margin-left: (100 / ($grid-cols / $i) ) * 1%; } } } }

ตอนนี้เรามีออฟเซ็ตที่ใช้งานได้เต็มรูปแบบแล้ว! เล่นกับมันที่นี่

ความสามารถในการแสดงผล

บางครั้งเราต้องการแสดง/ซ่อนองค์ประกอบที่อยู่ด้านล่างหรือเหนือจุดใดจุดหนึ่ง สำหรับสิ่งนี้ เราสามารถทำให้คลาสใช้งานได้เหมือนกับ Bootstrap v4

ตัวอย่างเช่น คลาส .hidden-md-up จะซ่อนองค์ประกอบใดๆ ที่มีคลาสนี้จากเบรกพอยต์ md ขึ้นไป ในทางกลับกัน . .hidden-md-down จะซ่อนมันจากจุดพัก

โค้ดสำหรับสิ่งนี้นั้นเรียบง่ายอีกครั้ง: เราแค่วนซ้ำจุดสั่งหยุดของเราและสร้าง .hidden-* ด้วย a for each เบรกพอยต์ เราแก้ไขคลาส create-mq ให้เป็นนามธรรมมากขึ้นเล็กน้อย:

 @each $modifier , $breakpoint in $map-grid-props { @if($modifier == '') { $modifier: '-xs'; } @include create-mq($breakpoint - 1, 'max') { .hidden#{$modifier}-down { display: none !important; } } @include create-mq($breakpoint, 'min') { .hidden#{$modifier}-up { display: none !important; } } }

อย่างที่ทราบกันดีอยู่แล้ว ว่านี่เป็นหนึ่งในประโยชน์ไม่กี่อย่างสำหรับ !important ใช่ไหม โปรดสังเกตว่าองค์ประกอบอาจมีความจำเพาะเจาะจงมากขึ้นตามอำเภอใจกับ display: block rule แต่เรายังคงต้องการซ่อนไว้ด้านล่างหรือเหนือเบรกพอยต์ หากคุณไม่เห็นด้วยกับแนวทางนี้ แจ้งให้เราทราบในความคิดเห็น!

แค่นั้นแหละ: ขณะนี้เรามีระบบการแสดงผลได้

เล่นกับมันที่นี่

บทสรุป

แม้ว่า "กรอบงาน" นี้จะไม่พร้อมสำหรับการผลิตจริง แต่ก็แสดงให้เห็นว่าเลย์เอาต์ Flexbox มีประสิทธิภาพเพียงใดและ Sass มีประโยชน์เพียงใด ด้วยโค้ดเพียงไม่กี่บรรทัด เราได้นำฟังก์ชันการทำงานหลักของ CSS framework/grid มาใช้

นอกจากนี้ยังสามารถใช้เป็นบทเรียนว่าซอฟต์แวร์รุ่นพื้นฐานแทบทุกชนิดสามารถนำไปใช้งานได้อย่างง่ายดายมาก เป็นปัญหาที่เป็นรูปธรรมของโลกแห่งความเป็นจริงที่เริ่มต้นและทำให้มันยากขึ้น

ฉันสร้าง repo GitHub ซึ่งคุณสามารถส่งปัญหาหรือดึงคำขอได้

คุณลักษณะใดที่คุณต้องการนำไปใช้ การใช้งานสามารถทำให้ง่ายขึ้นหรือสวยงามขึ้นได้หรือไม่?

อย่าลังเลที่จะแจ้งให้เราทราบความคิดเห็นของคุณเกี่ยวกับความคิดเห็นด้านล่าง