Flexbox- und Sass-Grid-Tutorial: Responsive Design optimieren
Veröffentlicht: 2022-03-11Kürzlich wurde ich herausgefordert, mein eigenes Rastersystem zu erstellen, und da es immer nützlich ist, das Rad neu zu erfinden, um zu lernen, habe ich mich dafür entschieden. Ich wusste, dass es eine interessante Herausforderung werden würde, aber ich war überrascht, wie einfach es sich herausstellte!
In diesem Experiment sehen wir uns Flexbox-Layouts an und wie sie elegante Implementierungen von Layouts ermöglichen, ohne irgendwelche verrückten Hacks zu machen. Wenn Sie mit Sass nicht vertraut sind, werden wir sehen, wie es funktioniert, und einige praktische Sass-Dienstprogramme verwenden. Vielleicht lernen Sie sogar etwas Neues über CSS-Grids wie das, das Teil von Bootstrap ist.
Eine sehr kurze Einführung in Sass und Flexbox
Sass ist im Grunde ein Tool, mit dem Sie einige der Mängel von CSS vermeiden können, es ist eine Skriptsprache, die in CSS interpretiert wird. Die Syntax sieht sehr vertraut aus, wenn Sie bereits CSS-Stile schreiben, aber ihre Toolbox enthält unter anderem Variablen, Mixins für die Wiederverwendbarkeit und if-, for-, each- und while-Anweisungen. Eines der praktischsten Dinge an Sass ist, dass jeder gültige CSS-Code gültiges Sass ist, sodass Sie Ihre Codebasis schrittweise umwandeln können.
Ein einfaches Beispiel für eine for-Schleife:
@for $i from 1 through 3 { .a-numbered-class-#{$i} { width: (20 * $i) * 1px; } }
Diese einfache Schleife iteriert von 1 bis 3 und erstellt Klassen. Der Index der Iteration wird bequem in $i
gespeichert. Wir können auch rechnen und das .a-numbered-class-X
dreimal mit jeweils unterschiedlicher Breite drucken. Dieser Code gibt aus:
.a-numbered-class-1 { width: 20px; } .a-numbered-class-2 { width: 40px; } .a-numbered-class-3 { width: 60px; }
Wie wir sehen können, können wir einen Großteil der Arbeit abstrahieren, die Sie in CSS erledigen müssten. In CSS müssten Sie manuell kopieren und einfügen und ändern, was offensichtlich fehleranfälliger und weniger elegant ist. Wenn Sie es noch nicht ausprobiert haben, verschwenden Sie keine Zeit mehr!
Flexbox steht für Flexible Box, ein CSS3-Layoutsystem, das Elemente dynamisch positioniert und verteilt. Es ist ein sehr leistungsfähiges Werkzeug, das flexible Layouts mit minimalem Aufwand ermöglicht. Weitere Informationen zum Erlernen von Flexbox finden Sie in Chris Coyiers Complete Guide to Flexbox.
Das Gitter
Kommen wir zum Raster selbst und beginnen wir mit seinen Grundelementen. Sie werden von den Rasterelementen von Bootstrap inspiriert: Container, Zeilen und Spalten, die jeweils in ersterem enthalten sind.
Wir verwenden die BEM-Namenskonventionen für die Namen der Klassen. BEM-Konventionen sind ziemlich einfach zu verwenden und fügen viele Informationen über das Element und seinen Kontext hinzu. Kurz gesagt, Sie haben:
- Blöcke , die „eine eigenständige Entität kapseln, die für sich genommen sinnvoll ist“:
.block
. - Elemente , die „Teile eines Blocks sind und keine eigenständige Bedeutung haben“, die durch den Blocknamen, zwei Unterstriche und das Element gekennzeichnet sind:
.block__elem
- Modifikatoren wie „Flags auf Blöcken oder Elementen“, die durch zwei Bindestriche dargestellt werden:
.block .block--mod
.
Behälter
Dies ist das äußerste Element des Rasters, es enthält unsere Zeilenelemente. Es gibt zwei Arten von Containern: .container
und .container--fluid
.
Das Verhalten von .container
wird dadurch definiert, dass 100 % der Breite unter einem bestimmten Punkt liegt, eine maximale feste Breite darüber hat und gleiche Ränder links und rechts hat:
$grid__bp-md: 768; .container { max-width: $grid__bp-md * 1px; margin: 0 auto; }
Spielen Sie hier damit, indem Sie das „Ausgabe“-Fenster erweitern und verkleinern
Für den Flüssigkeitsbehälter, der immer 100 % Breite hat, überschreiben wir diese Eigenschaften einfach mit einem Modifikator:
&--fluid { margin: 0; max-width: 100%; }
Spielen Sie hier damit.
Das war einfach! Wir haben jetzt beide Container implementiert. Kommen wir zum nächsten Element.
Reihen
Zeilen werden die horizontalen Organisatoren unserer Inhalte sein.
Wir werden Flexbox verwenden, um die untergeordneten Elemente einer Zeile zu positionieren, sie umbrechen, damit sie nicht überlaufen, und ihnen 100 % Breite innerhalb der Zeile geben (damit wir sie später verschachteln können).
&__row { display: flex; flex-wrap: wrap; width: 100%; }
Dadurch werden die untergeordneten Elemente nebeneinander positioniert und in neue Zeilen umbrochen, wenn die Summe ihrer Breite größer als sie selbst ist. Jetzt müssen wir nur noch ein paar Divs hinzufügen und es sieht so aus:
Spielen Sie hier damit, indem Sie das „Ausgabe“-Fenster erweitern und verkleinern.
Die Dinge nehmen Gestalt an, aber das ist noch kein CSS-Raster. Es fehlt…
Säulen
In Spalten befindet sich der Inhalt der Website. Sie definieren, in wie viele Teile die Reihe unterteilt ist und wie viel sie einnehmen. Wir werden ein zwölfspaltiges Layout erstellen. Das bedeutet, dass wir die Reihe in einen oder bis zu zwölf Teile teilen können.
Zu Beginn etwas grundlegende Mathematik. Wenn wir eine Spalte haben wollen, sollte ihre Breite 100 % betragen. Wenn wir zwölf Spalten wollen. Dann sollte jeder 8,333…% oder 100/12 der Breite einnehmen.
Mit Flexbox können wir zum Verteilen von Inhalten auf diese Weise flex-basis
verwenden.
Um in vier Spalten zu unterteilen, würden wir jetzt so etwas hinzufügen wie:
flex-basis: (100 / 4 ) * 1%;
Auf diese Weise können wir erreichen, dass die Elemente jeweils 25 % der Breite einnehmen – oder welchen Prozentsatz wir wollen.
Spielen Sie hier damit.
Machen wir das dynamischer. Da wir möchten, dass dies unsere möglichen Klassen widerspiegelt, rufen .col-1
auf, eine Klasse für ein Spalten-Div, das 8,333 % der Breite hat, da zwölf von ihnen passen sollten, bevor sie in eine neue Zeile umgebrochen werden müssen. Der Prozentsatz wird durchgehend erhöht, bis .col-12
, das 100% belegt.
$grid__cols: 12; @for $i from 1 through $grid__cols { .col-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } }
Nur um zu verdeutlichen, was los ist, sagen wir, wir wollen die Breite in vier gleiche Teile teilen. Wir würden .col-3
brauchen, da es 4 mal in 12 passt, das heißt, dass .col-3
25% Flex-Basis haben sollte:
100 / ($grid__cols / $i) 100 / (12 / 3) = 25
Das fängt schon an, wie ein Raster auszusehen!
Spielen Sie hier damit.
Bildschirmbreitenabhängige Spalten
Wir wollen jetzt in der Lage sein, ein Element zu haben, das auf Mobilgeräten eine bestimmte Breite hat, aber auf Tablets eine andere und so weiter. Abhängig von der Breite des Fensters verwenden wir bestimmte Haltepunkte. Unsere Benutzeroberfläche reagiert auf diese Haltepunkte und passt sich an ein ideales Layout an, das an die Bildschirmgrößen verschiedener Geräte angepasst ist. Wir benennen die Haltepunkte nach Größe: klein (sm), mittel (md) und so weiter, .col-sm-12
ist ein Element, das mindestens 12 Spalten bis zum sm
-Haltepunkt belegt.

Lassen Sie uns die Klasse .col- .col-*
.col-sm-*
. Da unser Grid zuerst mobil sein wird, werden wir seine Eigenschaften auf alle Bildschirmgrößen anwenden. Für diejenigen, die sich bei größeren Bildschirmen anders verhalten müssen, fügen wir die Klasse hinzu: .col-md-*
.
Stellen Sie sich ein Element mit .col-sm-12
und .col-md-4
. Das erwartete Verhalten ist, dass es unterhalb des Haltepunkts „md“ (mittel) 100 % Breite hat und darüber 33,333 % – ein sehr häufiges Vorkommen, da Sie auf Mobilgeräten möglicherweise Elemente darüber und nicht daneben stapeln müssen einander, wenn Ihre Breite viel begrenzter ist.
Dazu müssen wir am Haltepunkt eine Medienabfrage (ein Ausdruck, der Code enthält, der nur oberhalb oder unterhalb einer bestimmten Breite oder auf einem bestimmten Gerät ausgeführt wird) hinzufügen und unsere md
-Spalten so erstellen, wie wir es zuvor für sm
getan haben:
@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%; } } }
Spielen Sie hier damit.
Das kommt schon etwas Nützlichem nahe. Das ist ziemlich nass (Verstanden? Es ist nicht TROCKEN …), also machen wir es abstrakter.
Wie wir gesehen haben, benötigen wir für jeden Haltepunkt eine Medienabfrage. Erstellen wir also ein Mixin, das einen Haltepunkt empfängt, der dynamisch Medienabfragen erstellt. Es könnte etwa so aussehen:
@mixin create-mq($breakpoint) { @if($breakpoint == 0) { @content; } @else { @media screen and (min-width: $breakpoint *1px) { @content; } } }
Lassen Sie uns nun einfach das, was wir zum Erstellen der __col
-Klassen hatten, in ein Mixin namens create-col-classes
einpacken und das Mixin create-mq
verwenden.
@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%; } } } }
Und das ist es. Um es zu verwenden, definieren wir jetzt unsere Breakpoints in einer Sass-Map und iterieren sie.
$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); }
Unser Grid-System ist im Grunde fertig! Wir haben eine Klasse .container__col-sm-*
definiert, die der Standard sein wird, und wir können ihr Verhalten auf größeren Bildschirmen mit container__col-md-*
und container__col-lg-*
.
Wir können sogar Reihen verschachteln! Spielen Sie hier damit.
Das Schöne daran ist, dass wir, wenn wir jetzt wollten, dass es dieselben Haltepunkte wie Bootstrap v4 hat, nur Folgendes tun müssten:
$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 );
Und das ist es! Spielen Sie hier damit.
Beachten Sie, dass Bootstrap einen vollständigeren Mobile-First-Ansatz verfolgt, als wir ursprünglich besprochen haben. Die kleinsten Fenstergrößen haben kein Suffix wie sm
oder md
, da das Klassenäquivalent zu .container__col-X
nicht erst ab einer Fensterbreite von 0 bis 576px angewendet wird; Wenn wir es nicht explizit überschreiben, wird es diese Anzahl von Spalten bei jeder Fenstergröße sein. Andernfalls könnten wir die Klasse .container__col-sm-Y
hinzufügen, um eine Breite von Y Spalten zwischen den sm
-Haltepunkten zu erreichen.
Offsets
Offsets fügen einen linken Rand in Bezug auf die vorherige Spalte hinzu. Ein .container__col-offset-4
fügt einen margin-left: 33.333%
auf allen Bildschirmgrößen. .container__col-md-offset-4
macht dasselbe, aber über dem md
-Haltepunkt.
Die Implementierung ist jetzt trivial; Wir fügen eine Eigenschaft -offset
in derselben Schleife hinzu, in der wir die Klassen erstellen, aber anstelle von flex-bases
schreiben wir die Eigenschaft margin-left
. Wir müssen auch einen zusätzlichen für -offset-0
, da wir vielleicht den Rand auf größeren Bildschirmen löschen möchten:
@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%; } } } }
Wir haben jetzt voll funktionsfähige Offsets! Spielen Sie hier damit.
Darstellbarkeit
Manchmal möchten wir ein Element unter oder über einem bestimmten Punkt anzeigen/verbergen. Dafür können wir Klassen wie die von Bootstrap v4 zur Verfügung stellen.
Beispielsweise wird die Klasse .hidden-md-up
jedes Element mit dieser Klasse ab dem Haltepunkt md
aufwärts verbergen; Umgekehrt wird .hidden-md-down
es vor dem Haltepunkt nach unten verstecken.
Der Code dafür ist wieder einmal einfach: Wir iterieren einfach unsere Breakpoints und erstellen eine .hidden-*
Klasse mit einem for each
Breakpoint. Wir haben die Klasse create-mq
allerdings etwas abstrakter gestaltet:
@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; } } }
Nebenbei bemerkt, ist dies nicht eine der wenigen guten Verwendungen für !important
? Beachten Sie, dass das Element mit einer display: block
Regel eine beliebig höhere Spezifität haben kann, aber wir möchten es trotzdem unter oder über dem Haltepunkt verstecken. Wenn Sie mit diesem Ansatz nicht einverstanden sind, lassen Sie es mich in den Kommentaren wissen!
Das war's also: Wir haben jetzt ein Displayability-System.
Spielen Sie hier damit.
Fazit
Obwohl dieses „Framework“ noch nicht produktionsreif ist, zeigt es, wie leistungsfähig Flexbox-Layouts sein können und wie praktisch Sass ist. Mit nur wenigen Codezeilen haben wir die Kernfunktionalität eines CSS-Frameworks/Grids implementiert.
Möge es auch als Lehre dienen, dass eine Basisversion von praktisch jeder Software sehr einfach implementiert werden kann. Es sind die konkreten Probleme der realen Welt, die sich summieren und es schwierig machen.
Ich habe ein GitHub-Repo erstellt, in dem Sie Probleme einreichen oder Anfragen abrufen können.
Welche Funktionen würden Sie gerne implementiert sehen? Könnte die Implementierung vereinfacht oder eleganter sein?
Zögern Sie nicht, mir Ihre Meinung zu den Kommentaren unten mitzuteilen.