Mixins et listes Sass CSS24

Cet exercice consiste à utiliser le langage sass afin de créer diverses fonctions et mixins avec en utilisant des listes et des tableaux indexés (maps).

Consignes de l’exercice

Mise en place de l’exercice

Créez un dossier racine contenant une page HTML et un fichier SCSS.

Configurez le pré-processeur Sass afin de générer un fichier CSS lisible (non-compressé). La lisibilité de ce fichier est importante si vous souhaitez pouvoir vérifier le rendu de vos manipulations.

Largeur de colonnes

SCSS : Utilisez une boucle @for permettant de créer la série de quatre classes ci-dessous. Afin de rendre le code adaptable pour obtenir un nombre de classes différents sur le même principe, vous pouvez définir une variable pour le nombre de colonnes.

.col-1 {
    width: 25% ;
}
.col-2 {
    width: 50% ;
}
.col-3 {
    width: 75% ;
}
.col-4 {
    width: 100% ;
}
Syntaxe d’une boucle @for

La syntaxe d’une boucle for est la suivante. On répète l’opération avec la variable $i qui commence avec la valeur X jusqu’à ce que $i ait la valeur Y.

@for $i from X through Y {
    
}
Indice :

Pour calculer la largeur de la classe col-3, il suffit de diviser 100% par le nombre de colonnes (4), ce qui nous donne 25% et de multiplier ce pourcentage par 3.

Solution SCSS :

L’objectif est de créer 4 classes, il suffit donc d’utiliser une boucle @for qu’il faut répéter 4 fois. La variable $i d’itération de la boucle est alors utilisée pour nommer les classes avec #{ } et pour calculer la largeur des colonnes.

Je vous propose ici deux solutions, avec ou sans la variable $nbcol pour définir le nombre de colonnes à créer. Après avoir défini la variable, on l’utilise pour définir le nombre de répétition de la boucle et pour calculer la largeur de la colonne.

Cette seconde solution est un peu plus longue, mais elle deviendra plus intéressante pour la suite de l’exercice…

// Solution 1
@for $i from 1 through 4 {
    .col-#{$i} {
        width: (100% / 4) * $i;
    }
}

// Solution 2 avec une variable
$nbcol: 4;
@for $i from 1 through $nbcol{
    .col-#{$i} {
        width: (100% / $nbcol) * $i;
    }
}

SCSS : Créez un mixin correspond au code de la question précédente et testez-le. Vous passerez le nombre de colonnes comme argument du mixin.

Syntaxe d’un mixin

La création et l’utilisation d’un mixin respectent la syntaxe suivante :

// Déclaration du mixin
@mixin nomDuMixin( $argument ){

}

// Utilisation du mixin
@include nomDuMixin(x);

Solution SCSS :

Il suffit de reprendre le code de la solution précédente (avec la variable) et de l’intégrer dans un mixin.

La ligne @include cols(4); est ensuite utilisée pour exploiter le mixin et générer les 4 classes.

@mixin cols($nbcol){
  @for $i from 1 through $nbcol{
    .col-#{$i} {
        width: (100% / $nbcol) * $i;
    }
  }
}

// Test du mixin
@include cols(4);

Liste de fruits

SCSS : Créez une liste sass intitulée $fruits et contenant les éléments suivants : banane, cerise, ananas et pomme.

Solution SCSS :

Les trois solutions proposées ci-dessous sont équivalentes compte tenu de la permissivité du langage SCSS. Je vous recommande cependant de prendre de bonnes habitudes, d’être rigoureux et d’utiliser la première proposition.

// Les trois solutions suivantes sont équivalentes
$fruits: "banane", "cerise", "ananas", "pomme";
$fruits: banane, cerise, ananas, pomme;
$fruits: banane cerise ananas pomme;

SCSS : Utilisez une boucle permettant de créer une série de classes CSS pour chacun des fruits sous la forme suivante :

.fruit-banane {
  width: 50%;
}
.fruit-cerise {
  width: 50%;
}
.fruit-ananas {
  width: 50%;
}
.fruit-pomme {
  width: 50%;
}
Solution SCSS :

Il faut commencer par déclarer la liste, ce qui a normalement déjà été fait précédemment dans l’exercice.

Ensuite, il faut créer une boucle pour traiter tous les éléments de la liste. La boucle @each permet donc d’extraire une variable $fruit de la liste $fruits. À chaque tour de la boucle, la variable $fruit va donc correspondre à un fruit différent.

// Définition de la liste (tableau indexé)
$fruits: "banane", "cerise", "ananas", "pomme";

// Boucle sur la liste pour générer les classes
// Boucle pour chaque élément $fruit présents dans la liste $fruits
@each $fruit in $fruits {
    .fruit-#{$fruit} {
      width: 50%;
    }
}

SCSS : Créez un mixin correspond au code de la question précédente. La liste des fruits doit donc être un argument du mixin.

Solution SCSS :
// Création du mixin
@mixin listWidth($list){
  @each $element in $list {
    .fruit-#{$element} {
      width: 50%;
    }
  }
}

// Test du mixin
$fruits: "banane", "cerise", "ananas", "pomme";
@include listWidth('fruit',$fruits);

SCSS : Si ce n’est pas déjà fait, modifiez le mixin créé précédemment afin de passer le préfixe « fruit » comme un argument du mixin.

Solution SCSS :
// Création du mixin
@mixin listWidth($prefix, $list){
  @each $element in $list {
    .#{$prefix}-#{$element} {
      width: 50%;
    }
  }
}

// Test du mixin
$fruits: "banane", "cerise", "ananas", "pomme";
@include listWidth('fruit',$fruits);

// On peut maintenant générer d'autres classes CSS sur le même principe
$animaux: "chat", "chien", "rat", "souris";
@include listWidth('animal',$animaux);

SCSS : Créez une fonction sass permettant de renvoyer la valeur de la première entrée d’un tableau et testez-la sur le tableau $fruits.

La fonction doit renvoyer la valeur banane…

Syntaxe d’une fonction
// Déclaration d'une fonction
@function nomDeLaFonction( $argument ){
    @return "foo";
}
Solution SCSS :

Pour créer cette fonction, il suffit d’utiliser la fonction native nth() à laquelle vous passer en premier argument la liste et en second argument la valeur 1 puisque vous voulez le premier élément.

@function firstOfList($list){
  @return nth($list, 1);
}

$fruits: "banane", "cerise", "ananas", "pomme";
.fruit::before{
  content: firstOfList($fruits);
}

SCSS : Créez une fonction sass permettant de renvoyer la valeur de la dernière entrée d’un tableau et testez-la sur le tableau $fruits.

Solution SCSS :

Le principe de fonctionnement de cette fonction est le même que précédemment, mais pour déterminer l’index de la dernière valeur du tableau, on compte tout simplement le nombre d’éléments présents dans le tableau avec la fonction length().

@function lastOfList($list){
  @return nth($list, length($list));
}

$fruits: "banane", "cerise", "ananas", "pomme";
.fruit::before{
  content: lastOfList($fruits);
}

Liste de villes

SCSS : Créez une liste sass intitulée $villes et contenant les villes suivantes : Lyon, Paris, Marseille, Rouen et Bourg de Péage.

SCSS : Utilisez une boucle permettant de créer une série de classes CSS pour chacune des villes sous la forme suivante. Vous remarquerez que pour chaque ville, vous avez deux syntaxes différentes par exemple : Bourg de Péage et bourg-de-peage. Vous allez certainement devoir modifier votre liste.

.ville-lyon::before {
    display: block;
    content: 'Lyon';
}
.ville-paris::before {
    display: block;
    content: 'Paris';
}
.ville-marseille::before {
    display: block;
    content: 'Marseille';
}
.ville-rouen::before {
    display: block;
    content: 'Rouen';
}
.ville-bourg-de-peage::before {
    display: block;
    content: 'Bourg de Péage';
}
Solution de la liste :

Pour gérer les deux syntaxes, vous devez créer des listes imbriquées. Il s’agit donc d’une liste dont les différentes entrées sont également des listes.

$villes: (lyon,"Lyon"), 
         (paris,"Paris"), 
         (marseille,"Marseille"), 
         (rouen,"Rouen"), 
         (bourg-de-peage,"Bourg de Péage");
Solution SCSS :
$villes: (lyon,"Lyon"), 
         (paris,"Paris"), 
         (marseille,"Marseille"), 
         (rouen,"Rouen"), 
         (bourg-de-peage,"Bourg de Péage");
  
@each $ville in $villes {
  .ville-#{nth($ville,1)}::before {
    display: block;
    content: "#{nth($ville,2)}" ;
  }
}

SCSS : Créez un mixin permettant de reproduire le code précédent de manière générique.

Solution SCSS :
@mixin addText($list){
  @each $element in $list {
    .ville-#{nth($element,1)}::before {
      display: block;
      content: "#{nth($element,2)}" ;
    }
  }
}

// Test du mixin
$villes: (lyon,"Lyon"), 
         (paris,"Paris"), 
         (marseille,"Marseille"), 
         (rouen,"Rouen"), 
         (bourg-de-peage,"Bourg de Péage");

@include addText('ville',$villes);

SCSS : Si ce n’est pas déjà fait, modifiez le mixin créé précédemment afin de placer le préfixe « ville » comme argument du mixin.

Solution SCSS :
@mixin addText($prefix, $list){
  @each $element in $list {
    .#{$prefix}-#{nth($element,1)}::before {
      display: block;
      content: "#{nth($element,2)}" ;
    }
  }
}

// Test du mixin
$villes: (lyon,"Lyon"), 
         (paris,"Paris"), 
         (marseille,"Marseille"), 
         (rouen,"Rouen"), 
         (bourg-de-peage,"Bourg de Péage");

@include addText('ville',$villes);

SCSS : Modifiez le mixin créé à la question précédente pour lui ajouter un argument facultatif permettant d’utiliser au choix le pseudo-élément ::before ou le pseudo-élément ::after.

Solution SCSS :
@mixin addText($prefix,$list, $position:'before'){
  @each $element in $list {
    .#{$prefix}-#{nth($element,1)}::#{$position} {
      display: block;
      content: "#{nth($element,2)}" ;
    }
  }
}

// Test du mixin
$villes: (lyon,"Lyon"), 
         (paris,"Paris"), 
         (marseille,"Marseille"), 
         (rouen,"Rouen"), 
         (bourg-de-peage,"Bourg de Péage");

@include addText('ville',$villes);
@include addText('ville',$villes,'after');

Liste réseaux sociaux

SCSS : Créez une liste intitulée $social et contenant :

  • Une liste de réseau sociaux : facebook, flickr, linkedin, twitter, vimeo et youtube ;
  • Une couleur pour chaque service : #3b5998, #0063db, #007bb6, #00aced, #aad450, #bb0000.
Solution :
$social: (facebook,#3b5998), 
         (flickr,#0063db), 
         (linkedin,#007bb6), 
         (twitter,#00aced), 
         (vimeo,#aad450),
         (youtube,#bb0000);

SCSS : Utilisez la liste créée à la question précédente pour générer une série de classes sous la forme suivante :

.social-nom-du-service {
    color: couleur-associee ;
    background-color: couleur-associee-10-pourcent-plus-claire ;
}

Voici le résultat attendu :

.social-facebook {
  color: #3b5998;
  background-color: #4c70ba;
}

.social-flickr {
  color: #0063db;
  background-color: #0f7bff;
}

// etc
Indice :

Pour avoir une couleur plus claire, vous pouvez utiliser la fonction lighten().

Solution SCSS :
$social: (facebook,#3b5998), 
         (flickr,#0063db), 
         (linkedin,#007bb6), 
         (twitter,#00aced), 
         (vimeo,#aad450),
         (youtube,#bb0000);

@each $service in $social {
    .social-#{nth($service,1)} {
      color: #{nth($service,2)};
      background-color: #{lighten(nth($service,2),10%)};
    }
}

SCSS : Créez un mixin permettant de reproduire le code précédent de manière générique. Le préfixe « social » et le pourcentage d’éclaircissement doivent être des arguments du mixin.

Solution SCSS :
@mixin colors($prefix,$list,$percent:30%){
  @each $element in $list {
    .#{$prefix}-#{nth($element,1)} {
      color: #{nth($element,2)};
      background-color: #{lighten(nth($element,2),$percent)};
    }
  }
}

// Test du mixin
$social: (facebook,#3b5998), 
         (flickr,#0063db), 
         (linkedin,#007bb6), 
         (twitter,#00aced), 
         (vimeo,#aad450),
         (youtube,#bb0000);

@include colors('social',$social,30%);

Modifiez le mixin créé à la question précédente afin d’ajouter une option permettant de choisir d’éclaircir ou au contraire d’assombrir la couleur secondaire. L’option doit pouvoir avoir deux valeurs : light ou dark.

Solution SCSS :
@mixin colors($prefix,$list,$type:"light",$percent:30%){
  @each $element in $list {
    .#{$prefix}-#{nth($element,1)} {
      color: #{nth($element,2)};
      @if($type == "light") {
        background-color: #{lighten(nth($element,2),$percent)};
      } 
      @else {
        background-color: #{darken(nth($element,2),$percent)};
      }
    }
  }
}

// Test du mixin
$social: (facebook,#3b5998), 
         (flickr,#0063db), 
         (linkedin,#007bb6), 
         (twitter,#00aced), 
         (vimeo,#aad450),
         (youtube,#bb0000);

@include colors('social',$social,'light',30%);

SCSS : Créez un tableau associatif (map) intitulée $social2 contenant les mêmes informations que $social, puis créez une série de classes sous la même forme que précédemment.

Solution SCSS :
@mixin colorsMap($prefix,$map,$type:"lighten",$percent:30%){
  @each $name, $color in $map {
    .#{$prefix}-#{$name} {
      color: #{$color};
      @if($type == "lighten") {
        background-color: #{lighten($color,$percent)};
      } 
      @else {
        background-color: #{darken($color,$percent)};
      }
    }
  }
}

$social2: (facebook : #3b5998,
           flickr : #0063db,
           linkedin : #007bb6, 
           twitter : #00aced,
           vimeo : #aad450,
           youtube : #bb0000);
@include colorsMap('social',$social2,'lighten',30%);

Signes du zodiaque

SCSS : Créez une map (tableau associatif) contenant les signes du zodiac. L’index doit être le nom du signe sans accent (ex : « belier ») et la valeur est le signe avec accent et une majuscule en début de mot (ex: « Bélier »).

Liste des signes : Bélier, Taureau, Gémeaux, Cancer, Lion, Vierge, Balance, Scorpion, Sagittaire, Capricorne, Verseau, Poissons.

Solution SCSS :
$zodiac: (
  "belier": "Bélier",
  "taureau": "Taureau",
  "gemeaux": "Gémeaux",
  "cancer": "Cancer",
  "lion": "Lion",
  "vierge": "Vierge",
  "balance": "Balance",
  "scorpion": "Scorpion",
  "sagittaire": "Sagittaire",
  "capricorne": "Capricorne",
  "verseau": "Verseau",
  "poissons": "Poissons"
);

SCSS : À partir de la map de la question précédente, créez une série de classes sous la forme suivante :

.zodiac-belier {
    background-image: url("belier.svg");
}
.zodiac-belier::after {
    content: "Bélier";
}
Solution SCSS :
$zodiac: (
  "belier": "Bélier",
  "taureau": "Taureau",
  "gemeaux": "Gémeaux",
  "cancer": "Cancer",
  "lion": "Lion",
  "vierge": "Vierge",
  "balance": "Balance",
  "scorpion": "Scorpion",
  "sagittaire": "Sagittaire",
  "capricorne": "Capricorne",
  "verseau": "Verseau",
  "poissons": "Poissons"
);

@each $signe, $label in $zodiac {
  .zodiac-#{$signe} {
    background-image: url('#{$signe}.svg');
  }
  .zodiac-#{$signe}::after {
    content: '#{$label}' ;
  }
}

SCSS : Créez une map (tableau associatif) à deux niveaux intitulé $zodiac2 contenant la liste des signes du zodiaque (sans accents) au premier niveau et les informations du signe (libellé, date début et date fin) sur un deuxième niveau.

Signes du zodiaque :
  • Bélier : 21/03 – 20/04
  • Taureau : 21/04 – 21/05
  • Gémeaux : 22/05 – 21/06
  • Cancer : 22/06 – 22/07
  • Lion : 23/07 – 22/08
  • Vierge : 23/08 – 22/09
  • Balance : 23/09 – 22/10
  • Scorpion : 23/10 – 22/11
  • Sagittaire : 23/11 – 21/12
  • Capricorne : 22/12 – 20/01
  • Verseau : 21/01 – 19/02
  • Poissons : 20/02 – 20/03
Solution SCSS :

Pour chaque signe du zodiaque, nous avons donc une map dont l’index correspond au signe sans caractère spéciaux ou accents. Cet index permet de stocker une autre map avec les index label, debut et fin.

Prenez l’habitude d’avoir des index sans caractères spéciaux pour éviter les erreurs d’encodage.

$zodiac2: (
  "belier": ("label" : "Bélier", "debut" : "21/03", "fin" : "20/04"),
  "taureau": ("label" : "Taureau", "debut" : "21/04", "fin" : "21/05"),
  "gemeaux": ("label" : "Gémeaux", "debut" : "22/05", "fin" : "21/06"),
  "cancer": ("label" : "Cancer", "debut" : "2206", "fin" : "22/07"),
  "lion": ("label" : "Lion", "debut" : "2307", "fin" : "22/08"),
  "vierge": ("label" : "Vierge", "debut" : "23/08", "fin" : "22/09"),
  "balance": ("label" : "Balance", "debut" : "23/09", "fin" : "22/10"),
  "scorpion": ("label" : "Scorpion", "debut" : "23/10", "fin" : "22/11"),
  "sagittaire": ("label" : "Sagittaire","debut" : "23/11", "fin" : "21/12"),
  "capricorne" : ("label" : "Capricorne", "debut" : "22/12", "fin" : "20/01"),
  "verseau": ("label" : "Verseau", "debut" : "21/01", "fin" : "19/02"),
  "poisson": ("label" : "Poissons", "debut" : "20/02", "fin" : "20/03")
 );

// Seconde présentation possible plus lisible :
$zodiac2: (
  "belier": (
    "label": "Bélier",
    "debut": "21/03",
    "fin": "20/04"
  ),
  "taureau": (
    "label": "Taureau",
    "debut": "21/04",
    "fin": "21/05"
  ),
  "gemeaux": (
    "label": "Gémeaux",
    "debut": "22/05",
    "fin": "21/06"
  ),
  "cancer": (
    "Cancer": "",
    "debut": "2206",
    "fin": "22/07"
  ),
  "lion": (
    "label": "Lion",
    "debut": "2307",
    "fin": "22/08"
  ),
  "vierge": (
    "label": "Vierge",
    "debut": "23/08",
    "fin": "22/09"
  ),
  "balance": (
    "label": "Balance",
    "debut": "23/09",
    "fin": "22/10"
  ),
  "scorpion": (
    "label": "Scorpion",
    "debut": "23/10",
    "fin": "22/11"
  ),
  "sagittaire": (
    "label": "Sagittaire",
    "debut": "23/11",
    "fin": "21/12"
  ),
  "capricorne": (
    "label": "Capricorne",
    "debut": "22/12",
    "fin": "20/01"
  ),
  "verseau": (
    "label": "Verseau",
    "debut": "21/01",
    "fin": "19/02"
  ),
  "poisson": (
    "label": "Poissons",
    "debut": "20/02",
    "fin": "20/03"
  )
);

SCSS : À partir du tableau de la question précédente, créez une série de classes sous la forme suivante :

.zodiac-belier::before {
  content: "Bélier";
}
.zodiac-belier::after {
  content: "Du 21/03 au 19/04";
}
Solution SCSS :
$zodiac2: (
  "belier" : ("label" : "Bélier", "debut" : "21/03", "fin" : "20/04"),
  "taureau" : ("label" : "Taureau", "debut" : "21/04", "fin" : "21/05"),
  "gemeaux" : ("label" : "Gémeaux", "debut" : "22/05", "fin" : "21/06"),
  "cancer" : ("Cancer" : "", "debut" : "2206", "fin" : "22/07"),
  "lion" : ("label" : "Lion", "debut" : "2307", "fin" : "22/08"),
  "vierge" : ("label" : "Vierge", "debut" : "23/08", "fin" : "22/09"),
  "balance" : ("label" : "Balance", "debut" : "23/09", "fin" : "22/10"),
  "scorpion" : ("label" : "Scorpion", "debut" : "23/10", "fin" : "22/11"),
  "sagittaire" : ("label" : "Sagittaire","debut" : "23/11", "fin" : "21/12"),
  "capricorne" : ("label" : "Capricorne", "debut" : "22/12", "fin" : "20/01"),
  "verseau" : ("label" : "Verseau", "debut" : "21/01", "fin" : "19/02"),
  "poisson" : ("label" : "Poissons", "debut" : "20/02", "fin" : "20/03")
 );

@each $signe, $infos in $zodiac2 {
  .zodiac-#{$signe}::before {
    content: map-get($infos, "label"); 
  }
  .zodiac-#{$signe}::after {
    content: 'Du #{map-get($infos, "debut")} au #{map-get($infos, "fin")}'; 
  }
}

Mixins divers

SCSS : Créez un mixin permettant de positionner un élément en absolu en utilisant un paramètre d’emplacement et une distance qui devra avoir une valeur par défaut.

Solution SCSS :
@mixin position($position, $value:10px){
  position: absolute;
  @if($position=="tr"){
    top: $value;
    right: $value;
  } 
  @if($position=="tl"){
    top: $value;
    left: $value;
  } 
  @if($position=="br"){
    bottom: $value;
    right: $value;
  } 
  @if($position=="bl"){
    bottom: $value;
    left: $value;
  } 
}

Une autre possibilité consiste à distinguer les deux axes x et y.

@mixin position($x, $y, $value:10px){
  position: absolute;
  @if($x=="l"){
    left: $value;
  } @else {
    right: $value;
  }
  @if($y=="t"){
    top: $value;
  } @else {
    bottom: $value;
  }
}

SCSS : Créez un mixin permettant de créer un triangle rectangle isocèle à partir de trois paramètres : la direction (haut, bas, gauche, droite), la taille et la couleur.

Exemple mixin triangle
Solution SCSS :
@mixin triangle($size, $direction , $color){
    width: 0;
    height: 0;
    border: $size solid transparent;
  @if($direction == 'top'){
    border-top-width: 0 ;
    border-bottom-color: $color;
  }
  @if($direction == 'bottom'){
    border-bottom-width: 0 ;
    border-top-color: $color ;
  }
  @if($direction == 'left'){
    border-right-width: 0 ;
    border-left-color: $color ;
  }
  @if($direction == 'right'){
    border-left-width: 0 ;
    border-right-color: $color ;
  }
}


// Exemples d'utilisation du mixin
.triangle-top {
    @include triangle(150px, 'top', darken(#A51F86,10%));
}
.triangle-bottom {
    @include triangle(100px, 'bottom', #A51F86 );
}
.triangle-left {
    @include triangle(80px, 'left', lighten(#A51F86,10%));
}
.triangle-right {
    @include triangle(60px, 'right', lighten(#A51F86,20%));
}

S’abonner
Notification pour
guest

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

4 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Yacineo
Yacineo
2 années il y a

Un grand merci pour ces exercices bien détaillé en explications !!

Emir T
Emir T
6 mois il y a

J’adore ces exercices ! Merci beaucoup pour votre contenu !