Utilizzo delle variabili Sass con le query multimediali CSS3


121

Sto cercando di combinare l'uso di una variabile Sass con le query @media come segue:

$base_width:1160px;

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

$base_width viene quindi definito in vari punti nelle misurazioni basate sulla percentuale di larghezza del foglio di stile per produrre layout fluidi.

Quando lo faccio, la variabile sembra essere riconosciuta correttamente ma le condizioni per la media query non lo sono. Ad esempio, il codice precedente produce un layout di 1160 px indipendentemente dalla larghezza dello schermo. Se capovolgo le istruzioni @media in questo modo:

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

Produce un layout di 960 px, ancora una volta indipendentemente dalla larghezza dello schermo. Si noti inoltre che se rimuovo la prima riga $base_width: 1160px;restituisce un errore per una variabile non definita. Qualche idea su cosa mi manca?


Risposte:


97

Questo semplicemente non è possibile. Poiché il trigger si @media screen and (max-width: 1170px)verifica sul lato client.

Il raggiungimento del risultato atteso sarebbe possibile solo se SASS acquisisse tutte le regole e le proprietà nel foglio di stile contenente la $base_widthvariabile e le copiasse / le modificasse di conseguenza.

Dato che non funzionerà automaticamente, potresti farlo a mano in questo modo:

@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
          ...

Questo non è veramente ASCIUTTO ma il meglio che puoi fare.

Se le modifiche sono le stesse ogni volta potresti anche preparare un mixin contenente tutti i valori che cambiano, quindi non avrai bisogno di ripeterlo. Inoltre puoi provare a combinare il mixin con modifiche specifiche. Piace:

@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

E il Mixin sarebbe simile a questo

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

6
È ancora vero che SASS non funziona con $ variabili all'interno di query @media?
HappyTorso

1
@HappyTorso sarà sempre così, fino a quando non ci sarà un compilatore Sass lato client (ad esempio in JavaScript) che gira su viewport resize. Le variabili Sass vengono compilate fino a valori statici in fase di compilazione; non esistono più in fase di esecuzione. Le media query vengono valutate in fase di runtime, quando gli attributi media nella query cambiano.
ericsoco

26
@ericsoco Non vedo perché questo è un motivo. SASS potrebbe facilmente (?) Tenere traccia di tutti gli usi della variabile e inserire query multimediali dove vengono utilizzate; $foo: 1rem; @media (min-width: 10rem) {$foo: 2rem} .class {font-size: $foo} .class2 {padding: $foo}risulterebbe in.class {font-size: 1rem} .class2 {padding: 1rem} @media (min-width: 10rem) (.class {font-size: 2rem} .class2 {padding: 2rem}}
powerbuoy

1
sì sass è un preprocessore, non c'è motivo per "Questo semplicemente non è possibile" ... Potrebbe farlo, semplicemente non è implementato.
Ini

54

Simile alla risposta di Philipp Zedler, puoi farlo con un mixin. Ciò ti consente di avere tutto in un unico file, se lo desideri.

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

1
prima o poi incontrerai questo problema, anche se: sitepoint.com/cross-media-query-extend-sass
InsOp

Questa è meglio della mia risposta!
Philipp Zedler

+1 adoro questa soluzione. Combina questo con una mappa ( sass-lang.com/documentation/functions/map ) e hai un po 'di potere - Farò una soluzione separata qui per spiegare. Modifica: fatto. stackoverflow.com/a/56894640/385273
Ben

9

Modifica: non utilizzare questa soluzione. La risposta di Ronen è molto migliore.

Come soluzione DRY, puoi usare l' @importistruzione all'interno di una media query, ad esempio in questo modo.

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

Puoi definire tutti gli elementi reattivi nel file incluso utilizzando le variabili definite nella media query. Quindi, tutto ciò che devi ripetere è l'istruzione import.


9

Questo non è possibile con SASS, ma è possibile con le variabili CSS (o le proprietà personalizzate CSS ). L'unico svantaggio è il supporto del browser - ma in realtà c'è un plugin PostCSS - postcss-css-variables - che "appiattisce" l'uso delle variabili CSS (che ti dà il supporto anche per i browser meno recenti).

Il seguente esempio funziona alla grande con SASS (e con postcss-css-variables ottieni supporto anche per i browser meno recenti).

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

Ciò risulterebbe nel seguente CSS. Le query multimediali ripetitive aumenteranno la dimensione del file, ma ho scoperto che l'aumento è solitamente trascurabile una volta che il server web si applica gzip(cosa che di solito fa automaticamente).

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

8

Con l' ottima risposta di @ ronen e una mappa, c'è del vero potere disponibile:

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

È ora possibile avere molte più query multimediali DRY indirizzate .myDiva una serie di valori diversi.


Documenti mappa: https://sass-lang.com/documentation/functions/map

Esempio di utilizzo della mappa: https://www.sitepoint.com/using-sass-maps/


Mi ci è voluto un secondo per vederlo, ma questa è la stessa tecnica della risposta di @ ronen, utilizzando solo un input di mappa per supportare più variabili contemporaneamente. Non sto scontando il suo valore in alcun modo, ma era più difficile da capire fino a quando non ho stabilito quel collegamento
John Neuhaus,

5

Ho avuto lo stesso problema.

La $menu-widthvariabile dovrebbe essere 240 px nella visualizzazione mobile@media only screen and (max-width : 768px) e 340 px nella visualizzazione desktop .

Quindi ho semplicemente creato due variabili:

$menu-width: 340px;
$menu-mobile-width: 240px;

Ed ecco come l'ho usato:

.menu {
    width: $menu-width;
    @media only screen and (max-width : 768px) {
      width: $menu-mobile-width;
    }
}

1

Due raccomandazioni

1 Scrivi le tue istruzioni CSS "predefinite" per gli schermi piccoli e utilizza solo le media query per gli schermi più grandi. Di solito non è necessaria una max-widthmedia query.

Esempio (supponendo che l'elemento abbia la classe "container")

@mixin min-width($width) {
  @media screen and (max-width: $width) {
    @content;
  }
}

.container {
  width: 960px;

  @include min-width(1170px) {
    width: 1160px;
  }
}

2 Usa le variabili CSS per risolvere il problema, se puoi .

@mixin min-width($width) {
  @media screen and (max-width: $width) {
    @content;
  }
}

:root {
  --container-width: 960px;
  @include min-width(1170px) {
    --container-width: 1160px;
  }
}

.container {
  width: var(--container-width);
}

Nota:

Poiché avrà la larghezza di 1160 px quando la finestra ha una larghezza di 1170 px, potrebbe essere meglio usare una larghezza del 100% e una larghezza massima di 1160 px e l'elemento genitore potrebbe avere una spaziatura orizzontale di 5 px, purché la proprietà box-sizing è impostata su border-box. Esistono molti modi per risolvere il problema. Se il genitore non è un contenitore flessibile o griglia potresti usare .container { margin: auto }.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.