Использование переменных Sass с медиа-запросами CSS3

Я пытаюсь совместить использование переменной Sass с запросами @media следующим образом:

$base_width:1160px;

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

Затем $base_width определяется в различных точках измерения ширины таблицы стилей в процентах для создания гибких макетов.

Когда я это делаю, кажется, что переменная распознается правильно, а условия для медиа-запроса - нет. Например, приведенный выше код создает макет размером 1160 пикселей независимо от ширины экрана. Если я переверну утверждения @media следующим образом:

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

Он создает макет 960 пикселей, опять же, независимо от ширины экрана. Также обратите внимание, что если я удалю первую строку $base_width: 1160px;, она вернет ошибку для неопределенной переменной. Есть идеи, что мне не хватает?


person Jeremy S.    schedule 03.02.2012    source источник
comment
Дублированный stackoverflow.com/questions/40739695/   -  person Serkan KONAKCI    schedule 15.01.2019


Ответы (7)


Это просто невозможно. Поскольку триггер @media screen and (max-width: 1170px) происходит на стороне клиента.

Достичь ожидаемого результата можно было бы только в том случае, если бы SASS захватил все правила и свойства в вашей таблице стилей, содержащей вашу $base_width переменную, и скопировал / изменил их соответственно.

Поскольку это не будет работать автоматически, вы можете сделать это вручную следующим образом:

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

Это не совсем СУХОЕ, но лучшее, что вы можете сделать.

Если изменения одинаковы каждый раз, вы также можете подготовить миксин, содержащий все изменяющиеся значения, чтобы вам не нужно было его повторять. Дополнительно вы можете попробовать комбинировать миксин с конкретными изменениями. Нравиться:

@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

И миксин будет выглядеть так

=base_width_changes($base_width)
    #wrapper
        width: $base_width
person woerndl    schedule 03.02.2012
comment
По-прежнему ли SASS не работает с переменными $ внутри запросов @media? - person HappyTorso; 19.02.2014
comment
@HappyTorso так будет всегда, пока не появится такая вещь, как компилятор Sass на стороне клиента (например, в JavaScript), который работает при изменении размера области просмотра. Переменные Sass компилируются до статических значений во время сборки; они больше не существуют во время выполнения. Медиа-запросы оцениваются во время выполнения, когда медиа-атрибуты в запросе меняются. - person ericsoco; 14.04.2016
comment
@ericsoco Я не понимаю, почему это причина. SASS может легко (?) Просто отслеживать все использования переменной и вставлять медиа-запросы там, где они используются; $foo: 1rem; @media (min-width: 10rem) {$foo: 2rem} .class {font-size: $foo} .class2 {padding: $foo} приведет к .class {font-size: 1rem} .class2 {padding: 1rem} @media (min-width: 10rem) (.class {font-size: 2rem} .class2 {padding: 2rem}} - person powerbuoy; 13.09.2016
comment
да, sass - это препроцессор, для этого нет никаких причин. Это просто невозможно ... Он мог бы это сделать, это просто не реализовано. - person Ini; 12.11.2019

Подобно ответу Филиппа Зедлера, вы можете сделать это с помощью миксина. Это позволяет вам хранить все в одном файле, если хотите.

    @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);
    }
person ronen    schedule 11.03.2015
comment
рано или поздно вы столкнетесь с этой проблемой, хотя: sitepoint.com/cross-media -query-extend-sass - person InsOp; 23.07.2015
comment
Этот лучше, чем мой ответ! - person Philipp Zedler; 23.05.2017
comment
+1 люблю это решение. Совместите это с картой (sass-lang.com/documentation/functions/map) и у вас есть некоторая сила - я сделаю здесь отдельное решение, чтобы объяснить. Изменить: готово. stackoverflow.com/a/56894640/385273 - person Ben; 05.07.2019

Это невозможно с SASS, но возможно с переменными CSS (или Пользовательские свойства CSS). Единственный недостаток - поддержка браузера, но на самом деле есть плагин PostCSS - postcss-css-variables - это «сглаживает» использование переменных CSS (что также обеспечивает поддержку старых браузеров).

Следующий пример отлично работает с SASS (а с переменными postcss-css вы также получаете поддержку старых браузеров).

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

Это приведет к следующему CSS. Повторяющиеся медиа-запросы увеличивают размер файла, но я обнаружил, что это увеличение обычно незначительно, если веб-сервер применяет gzip (что обычно происходит автоматически).

.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;
  }
}
person fredrikekelund    schedule 22.03.2019

Изменить: пожалуйста, не используйте это решение. Ответ Ронена намного лучше.

В качестве решения DRY вы можете использовать оператор @import внутри медиа-запроса, например нравится.

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

Вы определяете все отзывчивые элементы в файле, включенном с помощью переменных, определенных в медиа-запросе. Итак, все, что вам нужно повторить, - это оператор импорта.

person Philipp Zedler    schedule 03.03.2015

С помощью отличного ответа @ ronen и карты есть реальная возможность:

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

Теперь возможно иметь намного больше DRY медиа-запросов, нацеленных на .myDiv с множеством разных значений.


Документы карты: https://sass-lang.com/documentation/functions/map

Пример использования карты: https://www.sitepoint.com/using-sass-maps/ < / а>

person Ben    schedule 04.07.2019
comment
Мне потребовалась секунда, чтобы увидеть это, но это тот же метод, что и в ответе @ronen, просто используя ввод карты для одновременной поддержки нескольких переменных. Я ни в коем случае не обесцениваю его ценность, но это было труднее понять, пока я не установил эту связь. - person John Neuhaus; 22.11.2019

У меня такая же проблема.

Переменная $menu-width должна иметь размер 240 пикселей для мобильной версии @media only screen and (max-width : 768px) и 340 пикселей для настольной версии.

Итак, я просто создал две переменные:

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

И вот как я это использовал:

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

Две рекомендации

1 Создайте операторы CSS по умолчанию для маленьких экранов и используйте медиа-запросы только для больших экранов. Обычно max-width медиа-запрос не нужен.

Пример (предполагается, что элемент имеет класс "контейнер")

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

.container {
  width: 960px;

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

2 Используйте переменные CSS для решения проблемы, если можно .

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

Примечание.

Поскольку его ширина будет 1160 пикселей, когда ширина окна 1170 пикселей, может быть лучше использовать ширину 100% и максимальную ширину 1160 пикселей, а у родительского элемента может быть горизонтальный отступ 5 пикселей, пока для свойства box-sizing установлено значение border-box. Есть много способов решить проблему. Если родительский элемент не является гибким или сеточным контейнером, вы можете использовать .container { margin: auto }.

person Stephen    schedule 19.03.2020
comment
стандартные переменные CSS - самый чистый путь. - person Rocky Kev; 14.12.2020