Verwenden von Sass-Variablen mit CSS3-Medienabfragen

119

Ich versuche, die Verwendung einer Sass-Variablen mit @ media-Abfragen wie folgt zu kombinieren:

$base_width:1160px;

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

$base_width wird dann an verschiedenen Stellen in den prozentualen Messungen der Stylesheet-Breite definiert, um Fluid-Layouts zu erstellen.

Wenn ich das mache, scheint die Variable richtig erkannt zu werden, die Bedingungen für die Medienabfrage jedoch nicht. Der obige Code erzeugt beispielsweise unabhängig von der Bildschirmbreite ein 1160px-Layout. Wenn ich die @ media-Anweisungen wie folgt umdrehe:

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

Es wird ein 960px-Layout erstellt, unabhängig von der Bildschirmbreite. Beachten Sie auch, dass beim Entfernen der ersten Zeile $base_width: 1160px;ein Fehler für eine undefinierte Variable zurückgegeben wird. Irgendwelche Ideen, was mir fehlt?

Jeremy S.
quelle
Duplizierte stackoverflow.com/questions/40739695/…
Serkan KONAKCI

Antworten:

96

Das ist einfach nicht möglich. Da der Trigger @media screen and (max-width: 1170px)auf der Clientseite erfolgt.

Das Erreichen Ihres erwarteten Ergebnisses wäre nur möglich, wenn SASS alle Regeln und Eigenschaften in Ihrem Stylesheet, das Ihre $base_widthVariable enthält, erfasst und entsprechend kopiert / geändert hat.

Da es nicht automatisch funktioniert, können Sie es wie folgt von Hand machen:

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

Dies ist nicht wirklich trocken, aber das Beste, was Sie tun können.

Wenn die Änderungen jedes Mal gleich sind, können Sie auch ein Mixin vorbereiten, das alle sich ändernden Werte enthält, sodass Sie es nicht wiederholen müssen. Außerdem können Sie versuchen, das Mixin mit bestimmten Änderungen zu kombinieren. Mögen:

@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

Und der Mixin würde so aussehen

=base_width_changes($base_width)
    #wrapper
        width: $base_width
woerndl
quelle
6
Ist es immer noch so, dass SASS nicht mit $ Variablen in @ media-Abfragen funktioniert?
HappyTorso
1
@HappyTorso wird es immer so sein, bis es so etwas wie einen clientseitigen Sass-Compiler (z. B. in JavaScript) gibt, der auf der Größe des Ansichtsfensters ausgeführt wird. Sass-Variablen werden zur Erstellungszeit auf statische Werte herunter kompiliert. Sie sind zur Laufzeit nicht mehr vorhanden. Medienabfragen werden zur Laufzeit ausgewertet, wenn sich die Medienattribute in der Abfrage ändern.
Ericsoco
25
@ericsoco Ich verstehe nicht, warum das ein Grund ist. SASS könnte einfach (?) Alle Verwendungen der Variablen verfolgen und Medienabfragen dort einfügen, wo sie verwendet werden. $foo: 1rem; @media (min-width: 10rem) {$foo: 2rem} .class {font-size: $foo} .class2 {padding: $foo}würde in.class {font-size: 1rem} .class2 {padding: 1rem} @media (min-width: 10rem) (.class {font-size: 2rem} .class2 {padding: 2rem}}
Powerbuoy
1
yep sass ist ein Präprozessor, es gibt keinen Grund für "Das ist einfach nicht möglich" ... Es könnte es tun, es ist einfach nicht implementiert.
Ini
54

Ähnlich wie bei Philipp Zedlers Antwort können Sie dies mit einem Mixin tun. So können Sie alles in einer einzigen Datei haben, wenn Sie möchten.

    @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);
    }
ronen
quelle
1
Früher oder später werden Sie auf dieses Problem stoßen, tho: sitepoint.com/cross-media-query-extend-sass
InsOp
Dieser besser als meine Antwort!
Philipp Zedler
+1 liebe diese Lösung. Kombinieren Sie dies mit einer Karte ( sass-lang.com/documentation/functions/map ) und Sie haben etwas Leistung - ich werde hier eine separate Lösung erstellen , um dies zu erklären. Bearbeiten: fertig. stackoverflow.com/a/56894640/385273
Ben
9

Bearbeiten: Bitte verwenden Sie diese Lösung nicht. Die Antwort von Ronen ist viel besser.

Als DRY-Lösung können Sie die @importAnweisung in einer Medienabfrage verwenden, z. B. wie folgt.

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

Sie definieren alle reaktionsfähigen Elemente in der enthaltenen Datei mithilfe der in der Medienabfrage definierten Variablen. Alles, was Sie wiederholen müssen, ist die Importanweisung.

Philipp Zedler
quelle
9

Dies ist mit SASS nicht möglich, aber mit CSS-Variablen (oder benutzerdefinierten CSS-Eigenschaften ). Der einzige Nachteil ist die Browserunterstützung - aber es gibt tatsächlich ein PostCSS-Plugin - postcss-css-variables -, das die Verwendung von CSS-Variablen "abflacht" (wodurch Sie auch ältere Browser unterstützen).

Das folgende Beispiel funktioniert hervorragend mit SASS (und mit postcss-css-Variablen erhalten Sie auch Unterstützung für ältere Browser).

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

Dies würde zu folgendem CSS führen. Die sich wiederholenden Medienabfragen erhöhen die Dateigröße, aber ich habe festgestellt, dass die Erhöhung normalerweise vernachlässigbar ist, sobald der Webserver angewendet wird gzip(was normalerweise automatisch geschieht ).

.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;
  }
}
fredrikekelund
quelle
8

Mit der großartigen Antwort von @ ronen und einer Karte steht echte Leistung zur Verfügung:

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

Es ist jetzt möglich, viel mehr DRY-Medienabfragen .myDivmit einer Reihe unterschiedlicher Werte durchzuführen.


Kartendokumente: https://sass-lang.com/documentation/functions/map

Beispiel für eine Kartenverwendung: https://www.sitepoint.com/using-sass-maps/

Ben
quelle
Ich habe eine Sekunde gebraucht, um es zu sehen, aber dies ist die gleiche Technik wie die Antwort von @ ronen, bei der nur eine Karteneingabe verwendet wird, um mehrere Variablen gleichzeitig zu unterstützen. Ich schätze den Wert keineswegs ein, aber es war schwieriger zu verstehen, bis ich diese Verbindung herstellte
John Neuhaus
5

Ich hatte das gleiche Problem.

Die $menu-widthVariable sollte in der mobilen Ansicht @media only screen and (max-width : 768px)240 Pixel und in der Desktopansicht 340 Pixel betragen .

Also habe ich einfach zwei Variablen erstellt:

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

Und so habe ich es benutzt:

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

Zwei Empfehlungen

1 Schreiben Sie Ihre "Standard" -CSS-Anweisungen für kleine Bildschirme und verwenden Sie Medienabfragen nur für größere Bildschirme. Eine max-widthMedienabfrage ist normalerweise nicht erforderlich .

Beispiel (vorausgesetzt, das Element hat die Klasse "container")

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

.container {
  width: 960px;

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

2 Verwenden Sie CSS-Variablen, um das Problem zu lösen, wenn Sie können .

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

Hinweis:

Da das Fenster eine Breite von 1160 Pixel hat, wenn das Fenster eine Breite von 1170 Pixel hat, ist es möglicherweise besser, eine Breite von 100% und eine maximale Breite von 1160 Pixel zu verwenden, und das übergeordnete Element hat möglicherweise eine horizontale Auffüllung von 5 Pixel, solange Die Box-Sizing-Eigenschaft ist auf Border-Box festgelegt. Es gibt viele Möglichkeiten, das Problem zu lösen. Wenn das übergeordnete Element kein Flex- oder Grid-Container ist, können Sie es verwenden .container { margin: auto }.

Stephen
quelle