167 votes

Utilisation des variables Sass avec les requêtes multimédias CSS3

J'essaie de combiner l'utilisation d'une variable Sass avec des requêtes @media comme suit :

$base_width:1160px;

@media screen and (max-width: 1170px) {$base_width: 960px;}
@media screen and (min-width: 1171px) {$base_width: 1160px;}

$base_width est ensuite définie à différents endroits de la feuille de style ; les mesures en pourcentage de la largeur permettent de produire des mises en page fluides.

Lorsque je fais cela, la variable semble être reconnue correctement mais les conditions de la requête média ne le sont pas. Par exemple, le code ci-dessus produit une mise en page de 1160px quelle que soit la largeur de l'écran. Si je permute les déclarations @media comme suit :

@media screen and (min-width: 1171px) {$base_width: 1160px;}
@media screen and (max-width: 1170px) {$base_width: 960px;}

Il produit une mise en page de 960px, là encore indépendamment de la largeur de l'écran. Notez également que si je supprime la première ligne de l'élément $base_width: 1160px; il renvoie une erreur pour une variable non définie. Une idée de ce que j'ai raté ?

118voto

awenro Points 468

Ce n'est tout simplement pas possible. Puisque le déclencheur @media screen and (max-width: 1170px) se passe du côté du client.

Le résultat escompté ne serait possible que si SASS saisissait toutes les règles et propriétés de votre feuille de style contenant l'élément $base_width et les a copiés/changés en conséquence.

Comme cela ne fonctionnera pas automatiquement, vous pouvez le faire à la main comme ceci :

@media screen and (max-width: 1170px)
      $base_width: 960px // you need to indent it to (re)set it just within this media-query
      // now you copy all the css rules/properties that contain or are relative to $base_width e.g.
      #wrapper
          width: $base_width
          ...

@media screen and (min-width: 1171px)
    $base_width: 1160px
      #wrapper
          width: $base_width
          ...

Ce n'est pas vraiment DRY mais c'est le mieux que vous puissiez faire.

Si les modifications sont les mêmes à chaque fois, vous pourriez également préparer un mixin contenant toutes les valeurs modifiées, ce qui vous éviterait d'avoir à le répéter. En outre, vous pouvez essayer de combiner le mixin avec des changements spécifiques. Par exemple :

@media screen and (min-width: 1171px)
    +base_width_changes(1160px)
    #width-1171-specific-element // additional specific changes, that aren't in the mixin
        display: block

Et le Mixin ressemblerait à ceci

=base_width_changes($base_width)
    #wrapper
        width: $base_width

82voto

ronen Points 583

Comme la réponse de Philipp Zedler, vous pouvez le faire avec un mixin. Cela vous permet d'avoir tout dans un seul fichier si vous le souhaitez.

    @mixin styling($base-width) {
        // your SCSS here, e.g.
        #Contents {
            width: $base-width;
        }
    }

    @media screen and (max-width: 1170px) {
        @include styling($base-width: 960px);
    }
    @media screen and (min-width: 1171px) {
        @include styling($base-width: 1160px);
    }

31voto

fredrikekelund Points 434

Ce n'est pas possible avec SASS, mais c'est possible avec des variables CSS (ou Propriétés personnalisées CSS ). Le seul inconvénient est le support des navigateurs, mais il existe un plugin PostCSS. postcss-css-variables - qui "aplatit" l'utilisation des variables CSS (ce qui permet également de prendre en charge les navigateurs plus anciens).

L'exemple suivant fonctionne parfaitement avec SASS (et avec postcss-css-variables, vous bénéficiez également de la prise en charge des anciens navigateurs).

$mq-laptop: 1440px;
$mq-desktop: 1680px;

:root {
    --font-size-regular: 14px;
    --gutter: 1rem;
}

// The fact that we have to use a `max-width` media query here, so as to not
// overlap with the next media query, is a quirk of postcss-css-variables
@media (min-width: $mq-laptop) and (max-width: $mq-desktop - 1px) {
    :root {
        --font-size-regular: 16px;
        --gutter: 1.5rem;
    }
}

@media (min-width: $mq-desktop) {
    :root {
        --font-size-regular: 18px;
        --gutter: 1.75rem;
    }
}

.my-element {
    font-size: var(--font-size-regular);
    padding: 0 calc(var(--gutter) / 2);
}

Il en résulterait le CSS suivant. Les media queries répétitives augmenteront la taille du fichier, mais j'ai constaté que l'augmentation est généralement négligeable une fois que le serveur web applique les règles suivantes gzip (ce qu'il fait généralement automatiquement).

.my-element {
  font-size: 14px;
  padding: 0 calc(1rem / 2);
}
@media (min-width: 1680px) {
  .my-element {
  padding: 0 calc(1.75rem / 2);
  }
}
@media (min-width: 1440px) and (max-width: 1679px) {
  .my-element {
  padding: 0 calc(1.5rem / 2);
  }
}
@media (min-width: 1680px) {
  .my-element {
  font-size: 18px;
  }
}
@media (min-width: 1440px) and (max-width: 1679px) {
  .my-element {
  font-size: 16px;
  }
}

10voto

Philipp Zedler Points 401

Editar: Veuillez ne pas utiliser cette solution. La réponse de ronen est bien meilleure.

En tant que solution DRY, vous pouvez utiliser la fonction @import à l'intérieur d'une requête média, par exemple comme ceci.

@media screen and (max-width: 1170px) {
    $base_width: 960px;
    @import "responsive_elements";
}
@media screen and (min-width: 1171px) {
    $base_width: 1160px;
    @import "responsive_elements";
}

Vous définissez tous les éléments réactifs dans le fichier inclus à l'aide des variables définies dans la requête média. Ainsi, tout ce que vous devez répéter est l'instruction d'importation.

10voto

Steve Points 10623

Avec @ronen's excellente réponse et une carte, il y a une vraie puissance disponible :

    @mixin styling($map) {
        .myDiv {
            background: map-get($map, 'foo');
            font-size: map-get($map, 'bar');
        }
    }

    @media (min-height: 500px) {
        @include styling((
            foo: green,
            bar: 50px
        ));
    }

    @media (min-height: 1000px) {
        @include styling((
            foo: red,
            bar: 100px
        ));
    }

Il est maintenant possible d'avoir beaucoup plus de requêtes média DRY ciblant .myDiv avec un tas de valeurs différentes.


Docs de la carte : https://sass-lang.com/documentation/functions/map

Exemple d'utilisation de la carte : https://www.sitepoint.com/using-sass-maps/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X