Tutoriel Flexbox et Sass Grid : comment rationaliser la conception réactive

Publié: 2022-03-11

Récemment, j'ai été mis au défi de créer mon propre système de grille et, comme réinventer la roue est toujours utile comme expérience d'apprentissage, je me suis lancé. Je savais que ce serait un défi intéressant, mais j'ai été surpris de voir à quel point cela s'est avéré facile !

Tutoriel Sass et Flexbox Grid

Dans cette expérience, nous examinerons les mises en page Flexbox et comment elles permettent des implémentations gracieuses de mises en page sans faire de hacks fous. De plus, si vous n'êtes pas familier avec Sass, nous verrons comment cela fonctionne et utiliserons quelques utilitaires Sass pratiques. Vous pourriez même apprendre quelque chose de nouveau sur les grilles CSS comme celle qui fait partie de Bootstrap.

Une très courte introduction de Sass et Flexbox

Sass est essentiellement un outil qui vous permet d'éviter certaines des lacunes de CSS, c'est un langage de script qui est interprété en CSS. La syntaxe semble très familière si vous écrivez déjà des styles CSS, mais sa boîte à outils comprend des variables, des mixins pour la réutilisation et des directives if, for, each et while, entre autres. L'une des choses les plus pratiques à propos de Sass est que tout code CSS valide est un Sass valide, vous pouvez donc progressivement transformer votre base de code.

Un exemple simple de boucle for :

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

Cette boucle simple itère de 1 à 3 et crée des classes. L'index de l'itération sera facilement stocké dans $i . Nous pouvons également faire des calculs et imprimer le .a-numbered-class-X trois fois avec une largeur différente à chaque fois. Ce code affiche :

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

Comme nous pouvons le voir, nous pouvons résumer une grande partie du travail que vous auriez à faire en CSS. En CSS, il faudrait copier-coller et modifier manuellement, ce qui est évidemment plus sujet aux erreurs et moins élégant. Si vous ne l'avez pas encore essayé, ne perdez plus de temps !

Flexbox signifie Flexible Box, un système de mise en page CSS3 qui positionne et distribue les éléments de manière dynamique. C'est un outil très puissant qui permet des mises en page flexibles avec un minimum d'effort. Pour plus de détails sur la façon d'apprendre Flexbox, consultez le guide complet de Chris Coyier sur Flexbox.

La grille

Passons à la grille elle-même, commençons par ses éléments de base. Ils s'inspireront des éléments de grille de Bootstrap : conteneurs, lignes et colonnes, chacun contenu dans le premier.

Nous utiliserons les conventions de nommage BEM pour les noms des classes. Les conventions BEM sont assez simples à utiliser et ajoutent beaucoup d'informations sur l'élément et son contexte. Bref, vous avez :

  • Blocks , qui « encapsulent une entité autonome qui a du sens par elle-même » : .block .
  • Les éléments , qui sont des "parties d'un bloc et n'ont pas de signification autonome" qui sont indiqués par le nom du bloc, deux traits de soulignement et l'élément : .block__elem
  • Modificateurs , comme "Flags on blocks or elements", qui sont représentés par deux tirets : .block .block--mod .

Conteneurs, lignes et colonnes

Conteneurs

C'est l'élément le plus à l'extérieur de la grille, il contiendra nos éléments de ligne. Il existe deux types de conteneurs : .container et .container--fluid .

Le comportement de .container est défini comme étant 100 % de la largeur en dessous d'un certain point, ayant une largeur fixe maximale au-dessus et des marges égales à gauche et à droite :

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

Jouez avec ici en agrandissant et en contractant la fenêtre de "sortie"

Pour le conteneur de fluide, qui a toujours une largeur de 100 %, nous remplaçons simplement ces propriétés par un modificateur :

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

Jouez avec ici.

C'était facile! Nous avons maintenant les deux conteneurs implémentés. Passons à l'élément suivant.

Lignes

Les rangées seront les organisateurs horizontaux de notre contenu.

Nous utiliserons Flexbox pour positionner les éléments enfants d'une ligne, en les faisant s'enrouler pour qu'ils ne débordent pas et en leur donnant 100 % de largeur à l'intérieur de la ligne (afin que nous puissions les imbriquer plus tard).

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

Cela positionnera les éléments enfants côte à côte et les enveloppera dans de nouvelles lignes si la somme de leur largeur est supérieure à elle-même. Nous avons maintenant juste besoin d'ajouter quelques divs et cela ressemblera à ceci :

Éléments de ligne

Jouez avec ici en agrandissant et en contractant la fenêtre de "sortie".

Les choses commencent à prendre forme, mais ce n'est pas encore une grille CSS. Ça a disparu…

Colonnes

Les colonnes sont l'endroit où vit le contenu du site. Ils définissent en combien de parties la rangée est divisée et combien elles occupent. Nous allons faire une disposition en douze colonnes. Cela signifie que nous pouvons diviser la rangée en une ou jusqu'à douze parties.

Pour commencer, quelques mathématiques de base. Lorsque nous voulons avoir une colonne, sa largeur doit être de 100 %. Si nous voulons douze colonnes. Ensuite, chacun devrait occuper 8,333…% ou 100/12 de la largeur.

Avec Flexbox, pour distribuer le contenu de cette manière, nous pouvons utiliser flex-basis .

Afin de diviser en quatre colonnes, nous ajouterions maintenant quelque chose comme :

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

De cette façon, nous pouvons faire en sorte que chacun des éléments occupe 25 % de la largeur, ou le pourcentage souhaité.

Jouez avec ici.

Rendons cela plus dynamique. Puisque nous voulons que cela reflète nos classes possibles, appelons .col-1 , une classe pour une colonne div qui aura 8,333% de la largeur puisque douze d'entre elles devraient tenir avant de devoir passer à une nouvelle ligne. Le pourcentage augmentera tout du long jusqu'à .col-12 , qui occupera 100%.

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

Juste pour clarifier ce qui se passe, disons que nous voulons diviser la largeur en quatre parties égales. Nous aurions besoin .col-3 car il tient 4 fois sur 12, cela signifie que .col-3 devrait avoir une base flexible de 25 % :

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

Cela commence déjà à ressembler à une grille !

Ressemble à une grille!

Jouez avec ici.

Colonnes dépendant de la largeur de l'écran

On veut maintenant pouvoir avoir un élément qui a une certaine largeur sur mobile mais une autre sur tablettes et ainsi de suite. Nous utiliserons certains points d'arrêt en fonction de la largeur de la fenêtre. Notre interface utilisateur réagira à ces points d'arrêt et s'adaptera à une disposition idéale adaptée aux tailles d'écran des différents appareils. Nous nommerons les points d'arrêt par taille : petit (sm), moyen (md) et ainsi de suite, .col-sm-12 sera un élément qui occupera au moins 12 colonnes jusqu'au point d'arrêt sm .

Renommez la classe .col- .col-* en .col-sm-* . Étant donné que notre grille sera d'abord mobile, nous appliquerons ses propriétés à toutes les tailles d'écran. Pour ceux dont nous avons besoin pour se comporter différemment avec des écrans plus grands, nous ajouterons la classe : .col-md-* .

Imaginez un élément avec .col-sm-12 et .col-md-4 . Le comportement attendu sera qu'en dessous du point d'arrêt "md" (moyen), il aura une largeur de 100 % et au-dessus, il aura 33,333 %, ce qui est très courant, car sur mobile, vous devrez peut-être empiler des éléments au-dessus plutôt qu'à côté. l'autre lorsque votre largeur est beaucoup plus limitée.

Empiler des colonnes après avoir atteint un point d'arrêt

Pour cela, nous devrons ajouter une requête multimédia (une expression qui contient du code qui ne s'exécutera qu'au-dessus ou en dessous d'une certaine largeur ou sur un appareil spécifique) au point d'arrêt et créer nos colonnes md comme nous l'avons fait auparavant pour 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%; } } }

Jouez avec ici.

Cela se rapproche déjà de quelque chose d'utile. C'est un peu MOUILLÉ (compris ? Ce n'est pas SEC…), alors rendons-le plus abstrait.

Comme nous l'avons vu, nous allons avoir besoin d'une requête média pour chaque point d'arrêt, créons donc un mixin qui reçoit un point d'arrêt qui crée dynamiquement des requêtes média. Cela pourrait ressembler à ceci :

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

Maintenant, enveloppons simplement ce que nous avions pour créer les classes __col dans un mixin appelé create-col-classes et utilisons le mixin 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%; } } } }

Et c'est tout. Pour l'utiliser, nous définissons maintenant nos points d'arrêt dans une carte Sass, et les itérons.

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

Notre système de grille est pratiquement terminé ! Nous avons défini une .container__col-sm-* qui sera la classe par défaut et nous pouvons modifier son comportement sur des écrans plus grands avec container__col-md-* et container__col-lg-* .

On peut même imbriquer des rangées ! Jouez avec ici.

La bonne chose à ce sujet est que si nous voulions maintenant qu'il ait tous les mêmes points d'arrêt que Bootstrap v4, nous n'aurions qu'à faire :

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

Et c'est tout! Jouez avec ici.

Remarquez comment Bootstrap adopte une approche mobile d'abord plus complète que celle dont nous avions initialement parlé. Les plus petites tailles de fenêtre n'ont pas de suffixe comme sm ou md , le raisonnement étant que la classe équivalente à .container__col-X ne sera pas seulement appliquée à partir d'une largeur de fenêtre de 0 à 576px ; si nous ne l'écrasons pas explicitement, ce sera ce nombre de colonnes à chaque taille de fenêtre. Sinon, nous pourrions ajouter la classe .container__col-sm-Y pour en faire une largeur de Y colonnes entre les sm points d'arrêt.

Décalages

Les décalages ajouteront une marge à gauche par rapport à la colonne précédente. Un .container__col-offset-4 ajoutera une margin-left: 33.333% sur toutes les tailles d'écran. .container__col-md-offset-4 fera la même chose mais au-dessus du point d'arrêt md .

La mise en œuvre est désormais triviale ; nous ajoutons une propriété -offset sur la même boucle que nous créons les classes, mais au lieu de flex-bases , nous écrivons la propriété margin-left . Nous devons également en faire un supplémentaire pour -offset-0 , car nous souhaitons peut-être effacer la marge sur les écrans plus grands :

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

Nous avons maintenant des compensations entièrement fonctionnelles ! Jouez avec ici.

Affichage

On veut parfois afficher/masquer un élément en dessous ou au dessus d'un certain point. Pour cela, nous pouvons mettre à disposition des classes comme celles de Bootstrap v4.

Par exemple, la classe .hidden-md-up tout élément avec cette classe à partir du point d'arrêt md ; à l'inverse, .hidden-md-down le cachera du point d'arrêt vers le bas.

Le code pour cela est encore une fois simple : nous itérons simplement nos points d'arrêt et créons une classe .hidden-* avec un for each point d'arrêt. Nous avons cependant modifié la classe create-mq pour qu'elle soit un peu plus abstraite :

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

En passant, n'est-ce pas l'un des rares bons usages de !important ? Notez que l'élément peut avoir une spécificité arbitrairement plus grande avec une règle display: block , mais nous voudrions toujours le cacher en dessous ou au-dessus du point d'arrêt. Si vous n'êtes pas d'accord avec cette approche, faites-le moi savoir dans les commentaires !

Alors c'est tout : nous avons maintenant un système d'affichage.

Jouez avec ici.

Conclusion

Bien que ce «cadre» ne soit pas prêt pour la production, il montre à quel point les mises en page Flexbox peuvent être puissantes et à quel point Sass est pratique. Avec seulement quelques lignes de code, nous avons implémenté la fonctionnalité de base d'un framework/grid CSS.

Puisse-t-il également servir de leçon qu'une version de base de pratiquement n'importe quel logiciel peut être implémentée très facilement. Ce sont les problèmes concrets du monde réel qui commencent à s'additionner et à le rendre difficile.

J'ai créé un référentiel GitHub où vous pouvez soumettre des problèmes ou des demandes d'extraction.

Quelles fonctionnalités souhaiteriez-vous voir implémenter ? La mise en œuvre pourrait-elle être simplifiée ou plus élégante ?

N'hésitez pas à me donner votre avis dans les commentaires ci-dessous.