Використання змінних Sass з CSS3 Media Queries


120

Я намагаюся поєднувати використання змінної 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 Потім визначається в різних точках вимірювання на основі процентної ширини таблиці стилів для створення макетів рідини.

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

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

Він створює 960px макет, знову ж таки незалежно від ширини екрана. Також зауважте, що якщо я видаляю перший рядок, $base_width: 1160px;він повертає помилку для невизначеної змінної. Якісь ідеї, чого мені не вистачає?


Відповіді:


96

Це просто неможливо. Оскільки тригер @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

6
Чи все ж таки так, що SASS не буде працювати з $ змінними всередині @media запитів?
HappyTorso

1
@HappyTorso завжди буде так, поки не з’явиться така річ, як клієнтський компілятор Sass (наприклад, у JavaScript), який працює на розмірі вікна перегляду. Змінні Sass компілюються до статичних значень під час збирання; вони більше не існують під час виконання. Медіа-запити оцінюються під час виконання, коли атрибути медіа у запиті змінюються.
ericsoco

26
@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}}
powerbuoy

1
yep sass є препроцесором, немає причин для "Це просто неможливо" ... Це могло б зробити, це просто не реалізовано.
Іні

54

Подібно до відповіді Філіпа Зедлера, ви можете це зробити за допомогою міксину. Це дозволяє вам мати все в одному файлі, якщо хочете.

    @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
рано чи пізно ви зіткнетеся з цією проблемою, tho: sitepoint.com/cross-media-query-extend-sass
InsOp

Цей краще, ніж моя відповідь!
Філіп Зедлер

+1 люблю це рішення. Поєднайте це з картою ( sass-lang.com/documentation/functions/map ), і ви маєте певну силу - я прийму окреме рішення тут, щоб пояснити. Редагування: зроблено. stackoverflow.com/a/56894640/385273
Бен

9

Редагувати: Не використовуйте це рішення. Відповідь Ронена набагато краща.

Як 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";
}

Ви визначаєте всі чуйні елементи у файлі, що входять до нього, використовуючи змінні, визначені в медіа-запиті. Отже, все, що вам потрібно повторити, - це заява про імпорт.


9

Це неможливо з SASS, але це можливо із змінними CSS (або спеціальними властивостями CSS ). Єдиним недоліком є ​​підтримка браузера - але насправді плагін PostCSS - postcss-css-змінні - це "згладжує" використання змінних 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;
  }
}

8

Завдяки чудовій відповіді @ 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/


Щоб розглянути це, мені знадобилося секунду, але це та сама техніка, що і відповідь @ ronen, просто використовуючи введення карти для підтримки відразу декількох змінних. Я не знижую її цінністю будь-якими способами, але важче було зрозуміти, поки я не зробив це з'єднання
Джон Нойгаус

5

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

$menu-widthМінлива повинна бути 240px на мобільний зору @media only screen and (max-width : 768px)і 340px на робочому столі зору.

Тому я просто створив дві змінні:

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

І ось як я ним користувався:

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

1

Дві рекомендації

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

Примітка:

Оскільки він матиме ширину 1160px, коли вікно має ширину 1170px, можливо, краще використовувати ширину 100% та max-ширину 1160px, а батьківський елемент може мати горизонтальну прокладку 5px, якщо властивість розміру коробки встановлена ​​на рамку box. Існує маса способів вирішити проблему. Якщо батько не є контейнером flex або grid, який ви можете використовувати .container { margin: auto }.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.