Samouczek Flexbox i Sass Grid: Jak usprawnić projektowanie responsywne

Opublikowany: 2022-03-11

Niedawno stanąłem przed wyzwaniem stworzenia własnego systemu siatki, a ponieważ ponowne wynalezienie koła jest zawsze przydatne jako nauka, zdecydowałem się na to. Wiedziałem, że to będzie ciekawe wyzwanie, ale byłem zaskoczony, jak łatwo się to okazało!

Samouczek dotyczący siatki Sass i Flexbox

W tym eksperymencie przyjrzymy się układom Flexbox i temu, jak umożliwiają one wdzięczną implementację układów bez robienia żadnych szalonych hacków. Ponadto, jeśli nie znasz Sassa, zobaczymy, jak to działa i użyjemy kilku przydatnych narzędzi Sass. Możesz nawet dowiedzieć się czegoś nowego o siatkach CSS, takich jak ta, która jest częścią Bootstrap.

Bardzo krótkie wprowadzenie Sass i Flexbox

Sass to w zasadzie narzędzie, które pozwala uniknąć niektórych niedociągnięć CSS, to język skryptowy, który jest interpretowany przez CSS. Składnia wygląda bardzo znajomo, jeśli już piszesz style CSS, ale jej zestaw narzędzi zawiera między innymi zmienne, domieszki do ponownego użycia oraz dyrektywy if, for, each i while. Jedną z najprzydatniejszych rzeczy w Sassie jest to, że każdy poprawny kod CSS jest poprawnym Sassem, więc możesz stopniowo przekształcać swoją bazę kodu.

Prosty przykład pętli for:

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

Ta prosta pętla iteruje od 1 do 3 i tworzy klasy. Indeks iteracji będzie łatwo przechowywany w $i . Możemy również wykonać matematykę i wydrukować .a-numbered-class-X trzy razy z inną szerokością za każdym razem. Ten kod wyprowadza:

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

Jak widać, możemy wyabstrahować wiele pracy, którą musiałbyś wykonać w CSS. W CSS musiałbyś kopiować, wklejać i modyfikować ręcznie, co jest oczywiście bardziej podatne na błędy i mniej eleganckie. Jeśli jeszcze tego nie próbowałeś, nie trać więcej czasu!

Flexbox oznacza Flexible Box, system układu CSS3, który dynamicznie pozycjonuje i dystrybuuje elementy. Jest to bardzo potężne narzędzie, które pozwala na elastyczne układy przy minimalnym wysiłku. Aby uzyskać więcej informacji o tym, jak nauczyć się Flexbox, zapoznaj się z Kompletnym przewodnikiem po Flexbox autorstwa Chrisa Coyiera.

Siatka

Przechodząc do samej siatki, zacznijmy od jej podstawowych elementów. Będą inspirowane elementami siatki Bootstrap: pojemnikami, rzędami i kolumnami, z których każdy zawiera się w pierwszym.

Będziemy używać konwencji nazewnictwa BEM dla nazw klas. Konwencje BEM są dość proste w użyciu i dodają wiele informacji o elemencie i jego kontekście. Krótko mówiąc, masz:

  • Bloki , które „hermetyzują samodzielną jednostkę, która sama w sobie ma znaczenie”: .block .
  • Elementy , które są „częściami bloku i nie mają samodzielnego znaczenia”, są oznaczone nazwą bloku, dwoma podkreśleniami i elementem: .block__elem
  • Modyfikatory , takie jak „Flagi na blokach lub elementach”, które są reprezentowane przez dwa myślniki: .block .block--mod .

Kontenery, wiersze i kolumny

Kontenery

To jest najbardziej zewnętrzny element siatki, będzie zawierał nasze elementy wiersza. Istnieją dwa typy kontenerów: .container i .container--fluid .

Zachowanie .container definiuje się jako 100% szerokości poniżej pewnego punktu, z maksymalną stałą szerokością nad nim i równymi marginesami po lewej i prawej stronie:

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

Pobaw się tym tutaj, rozszerzając i zawężając okno „wyjścia”

W przypadku pojemnika na płyn, który zawsze ma 100% szerokości, po prostu nadpisujemy te właściwości modyfikatorem:

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

Zagraj z tym tutaj.

To było łatwe! Mamy teraz zaimplementowane oba kontenery. Przejdźmy do następnego elementu.

Wydziwianie

Wiersze będą poziomymi organizatorami naszych treści.

Użyjemy Flexbox do pozycjonowania elementów potomnych wiersza, sprawiając, że zawijają się tak, aby się nie przepełniły, i dając im 100% szerokości wewnątrz wiersza (abyśmy mogli później je zagnieździć).

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

Spowoduje to umieszczenie elementów potomnych obok siebie i zawinięcie ich w nowe wiersze, jeśli suma ich szerokości jest większa niż ona sama. Teraz wystarczy dodać kilka divów i będzie to wyglądać tak:

Elementy wierszy

Pobaw się tym tutaj, rozszerzając i zawężając okno „wyjścia”.

Wszystko zaczyna nabierać kształtu, ale to nie jest jeszcze siatka CSS. Brakuje…

Kolumny

Kolumny są miejscem, w którym znajduje się zawartość witryny. Określają na ile części jest podzielony rząd i ile zajmują. Zrobimy układ dwunastu kolumn. Oznacza to, że możemy podzielić rząd na jedną lub do dwunastu części.

Na początek podstawowa matematyka. Gdy chcemy mieć jedną kolumnę, jej szerokość powinna wynosić 100%. Jeśli chcemy mieć dwanaście kolumn. Wtedy każdy powinien zajmować 8.333…% lub 100/12 szerokości.

Z Flexbox, aby dystrybuować treści w ten sposób, możemy użyć flex-basis bass .

Aby podzielić na cztery kolumny, dodamy teraz coś takiego:

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

W ten sposób możemy sprawić, by każdy z elementów zajmował 25% szerokości — lub dowolny procent, jaki chcemy.

Zagraj z tym tutaj.

Zróbmy to bardziej dynamicznie. Ponieważ chcemy, aby odzwierciedlało to nasze możliwe klasy, nazwijmy .col-1 , klasą dla kolumny div, która będzie miała 8,333% szerokości, ponieważ dwanaście z nich powinno się zmieścić, zanim będą musiały zawinąć do nowej linii. Procent będzie się zwiększał przez cały czas, aż do .col-12 , który zajmie 100%.

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

Aby wyjaśnić, co się dzieje, powiedzmy, że chcemy podzielić szerokość na cztery równe części. .col-3 , ponieważ mieści się 4 razy w 12, co oznacza, że .col-3 powinna mieć 25% flex-base:

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

To już zaczyna wyglądać jak siatka!

Wygląda jak siatka!

Zagraj z tym tutaj.

Kolumny zależne od szerokości ekranu

Chcemy teraz mieć element, który ma określoną szerokość na urządzeniach mobilnych, ale inny na tabletach i tak dalej. Użyjemy pewnych punktów przerwania zależnych od szerokości okna. Nasz interfejs użytkownika zareaguje na te punkty przerwania i dostosuje się do idealnego układu dostosowanego do rozmiarów ekranu różnych urządzeń. Nazwiemy punkty przerwania według rozmiaru: mały (sm), średni (md) itd., .col-sm-12 będzie elementem zajmującym 12 kolumn przynajmniej do punktu przerwania sm .

Zmieńmy nazwę klasy .col- .col-* .col-sm-* . Ponieważ nasza siatka będzie najpierw mobilna, będziemy stosować jej właściwości do wszystkich rozmiarów ekranu. Dla tych, które musimy zachowywać inaczej na większych ekranach, dodamy klasę: .col-md-* .

Wyobraź sobie element z .col-sm-12 i .col-md-4 . Oczekiwane zachowanie będzie takie, że poniżej punktu przerwania „md” (średni) będzie miał 100% szerokości, a powyżej niego będzie miał 33,333% — bardzo częste zjawisko, ponieważ na urządzeniach mobilnych może być konieczne ułożenie elementów na górze, a nie obok się nawzajem, gdy twoja szerokość jest znacznie bardziej ograniczona.

Układanie kolumn po osiągnięciu punktu przerwania

W tym celu musimy dodać zapytanie o media (wyrażenie zawierające kod, który będzie wykonywany tylko powyżej lub poniżej określonej szerokości lub na określonym urządzeniu) w punkcie przerwania i utworzyć nasze kolumny md , tak jak robiliśmy to wcześniej dla 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%; } } }

Zagraj z tym tutaj.

To już zbliża się do czegoś użytecznego. To trochę MOKRE (rozumiesz? Nie jest SUCHE…), więc zróbmy to bardziej abstrakcyjnie.

Jak widzieliśmy, będziemy potrzebować zapytania o media dla każdego punktu przerwania, więc stwórzmy mixin, który otrzyma punkt przerwania, który dynamicznie tworzy zapytania o media. Mogłoby to wyglądać mniej więcej tak:

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

Teraz zapakujmy to, co mieliśmy do tworzenia klas __col w domieszce o nazwie create-col-classes i użyjmy mixinu create-mq .

 @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%; } } } }

I to wszystko. Aby z niego skorzystać, definiujemy teraz nasze punkty przerwania na mapie Sass i powtarzamy je.

 $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); }

Nasz system sieciowy jest w zasadzie gotowy! Zdefiniowaliśmy .container__col-sm-* , która będzie domyślna i możemy zmodyfikować jej zachowanie na większych ekranach za pomocą container__col-md-* i container__col-lg-* .

Możemy nawet zagnieździć rzędy! Zagraj z tym tutaj.

Fajną rzeczą w tym jest to, że gdybyśmy teraz chcieli mieć te same punkty przerwania, co Bootstrap v4, musielibyśmy po prostu zrobić:

 $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 );

I to wszystko! Zagraj z tym tutaj.

Zwróć uwagę, że Bootstrap przyjmuje bardziej kompletne podejście z myślą o urządzeniach mobilnych niż początkowo omawialiśmy. Najmniejsze rozmiary okien nie mają takiego przyrostka jak sm lub md , ponieważ klasa równoważna .container__col-X zostanie zastosowana nie tylko od szerokości okna od 0 do 576px; jeśli nie nadpiszemy go jawnie, będzie to ta liczba kolumn w każdym rozmiarze okna. W przeciwnym razie moglibyśmy dodać klasę .container__col-sm-Y , aby miała szerokość Y kolumn między punktami przerwania sm .

Przesunięcia

Przesunięcia dodadzą margines pozostały w stosunku do poprzedniej kolumny. .container__col-offset-4 doda margin-left: 33.333% na wszystkich rozmiarach ekranu. .container__col-md-offset-4 zrobi to samo, ale powyżej punktu przerwania md .

Wdrożenie jest teraz trywialne; dodajemy właściwość -offset w tej samej pętli, w której tworzymy klasy, ale zamiast flex-bases piszemy właściwość margin-left . Musimy też zrobić dodatkowy dla -offset-0 , ponieważ możemy chcieć usunąć margines na większych ekranach:

 @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%; } } } }

Mamy teraz w pełni funkcjonalne offsety! Zagraj z tym tutaj.

Możliwość wyświetlania

Czasami chcemy wyświetlić/ukryć element poniżej lub powyżej określonego punktu. W tym celu możemy udostępnić klasy takie jak w Bootstrap v4.

Na przykład klasa .hidden-md-up ukryje każdy element z tą klasą od punktu przerwania md w górę; odwrotnie, .hidden-md-down ukryje go przed punktem przerwania w dół.

Kod do tego jest znowu prosty: po prostu iterujemy nasze punkty przerwania i tworzymy klasę .hidden-* z for each punktem przerwania. Zmodyfikowaliśmy jednak klasę create-mq , aby była nieco bardziej abstrakcyjna:

 @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; } } }

Na marginesie, czy nie jest to jedno z niewielu dobrych zastosowań !important ? Zauważ, że element może mieć dowolnie większą szczegółowość z regułą display: block , ale nadal chcielibyśmy go ukryć poniżej lub powyżej punktu przerwania. Jeśli nie zgadzasz się z takim podejściem, daj znać w komentarzach!

A więc to wszystko: mamy teraz system wyświetlania.

Zagraj z tym tutaj.

Wniosek

Chociaż ten „framework” nie jest gotowy do produkcji, pokazuje, jak potężne mogą być układy Flexbox i jak poręczny jest Sass. Za pomocą zaledwie kilku linijek kodu zaimplementowaliśmy podstawową funkcjonalność frameworka/siatki CSS.

Niech będzie to również lekcja, że ​​podstawową wersję praktycznie każdego oprogramowania można bardzo łatwo zaimplementować. To konkretne problemy realnego świata zaczynają się sumować i utrudniają.

Stworzyłem repozytorium GitHub, w którym możesz zgłaszać problemy lub pull requesty.

Jakie funkcje chciałbyś zobaczyć wdrożone? Czy wdrożenie może być uproszczone lub bardziej eleganckie?

Zapraszam do podzielenia się swoją opinią na temat poniższych komentarzy.