Народні змінні CSS, які не працюють у медіа-запитах


140

Я намагаюся використовувати змінні CSS в медіа-запитах, і це не працює.

:root {
  --mobile-breakpoint: 642px;
}

@media (max-width: var(--mobile-breakpoint)) {

}

Ви пробували в декількох браузерах? (Як і Chrome та Firefox)
Кохар

1
Без препроцесора @SandrinaPereira
Cohars

1
@SandrinaPereira Отже, ви можете на Firefox та Chrome 👍
Cohars


3
Просто для уточнення для людей, які виявляють це через Google: ви можете використовувати власні властивості CSS у межах медіа-запиту, ви просто не можете використовувати їх у декларації медіа-запиту.
Девід Депрост

Відповіді:


112

З специфікації ,

var()Функція може бути використана замість будь-якій частині значення в будь-який власності на елементі. var()Функція не може бути використана в якості імен властивостей, селектор, або що - небудь ще , крім значень властивостей. (Так зазвичай утворюється недійсний синтаксис, або ж значення, значення якого не має зв'язку зі змінною.)

Тому ні, ви не можете використовувати його в медіа-запиті.

І це має сенс. Тому що ви можете встановити, --mobile-breakpointнаприклад :root, <html>елемент, тобто елемент, а звідти успадкувати інші елементи. Але медіа-запит не є елементом, він не успадковує <html>, тому він не може працювати.

Цього не намагаються виконати змінні CSS. Натомість ви можете використовувати препроцесор CSS.


77
Відповідь правильна тим, що специфікація в даний час не обробляє змінні CSS в медіа-запитах, але неправильна в тому, що це не те, що намагаються виконати змінні CSS. Зменшення числа повторень та магічних дій саме тому було створено змінні CSS - див. W3.org/TR/css-variables-1/#intro
mikemaccana

69

Як відповів Oriol , в даний час CSS змінних рівня 1 var()не можна використовувати в медіа-запитах . Однак останнім часом були розроблені проблеми, які вирішують цю проблему. Через кілька років, як тільки модуль CSS середовища змінних довкілля рівень 1 буде стандартизований та впроваджений, ми зможемо використовувати env()змінні в медіа-запитах у всіх сучасних браузерах.

Якщо ви читаєте специфікацію і маєте занепокоєння, або якщо ви хочете озвучити вашу підтримку випадку використання медіа-запитів, ви все одно можете зробити це в GitHub w3c / csswg-drafts # 1693 або в будь-якому випуску CSS GitHub з префіксом "[ css-env-1] ” .


Оригінальна відповідь 2017-11-09 : Нещодавно Робоча група CSS вирішила, що змінні CSS рівня 2 підтримуватимуть визначені користувачем змінні середовища з використанням env(), і вони намагатимуться зробити їх дійсними в запитах медіа . Група вирішила це після того, як Apple вперше запропонувала стандартні властивості агент-користувачів , незадовго до офіційного оголошення iPhone X у вересні 2017 року (див. Також WebKit: "Проектування веб-сайтів для iPhone X" Тімоті Хортона ). Інші представники веб-переглядачів погодилися, що вони можуть бути корисними для багатьох пристроїв, таких як телевізійні дисплеї та друк із чорнилом. ( env()раніше називалиconstant(), але це тепер застаріло. Ви могли б ще побачити статті , які відносяться до старої назви, наприклад, цієї статті Peter-Paul Koch .) Після того, як кілька тижнів пройшли, Камерон Маккормак з Mozilla зрозумів , що ці змінні оточення буде використовуватися в запитах медіа, і Tab Atkins, Jr. Тоді компанія Google зрозуміла, що визначені користувачем змінні середовища будуть особливо корисні як глобальні кореневі змінні, що не можна перезаписати, які можна використовувати в медіа-запитах. Тепер Дін "Діно" Джексон від Apple приєднається до Аткінса в редагуванні рівня 2.

Ви можете підписатися на оновлення з цього питання у w3c/csswg-draftsвипуску GitHub № 1693 . (Для особливо релевантних історичних деталей розгорніть журнали зустрічей, вбудовані в резолюції CSSWG Bot Meeting Bot, і знайдіть "MQ", що означає "медіа-запити".)

Планую оновити це питання в майбутньому, коли відбуватиметься більше подій. Майбутнє захоплююче.


Оновлення 2018-02-08 : Технологія попереднього перегляду Safari 49 додала підтримку для розбору calc()в медіа-запитах, що може бути передумовою для підтримки і env()в них.


Оновлення 2018-04-27 : Команда Chromium від Google вирішила розпочати роботу env(). У відповідь Аткінс почав конкретизувати env()в окремому, неофіційному проекті стандарту: модуль змінних середовищ CSS, рівень 1 . (Дивіться його коментар GitHub у w3c / csswg-drafts # 1693 та його коментар у w3c / csswg-drafts # 1817. ) Проект залучає змінні в медіа-запитах як виразний випадок використання:

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

Якщо ви читаєте специфікацію і маєте занепокоєння, або якщо ви хочете озвучити вашу підтримку випадку використання медіа-запитів, ви все одно можете зробити це в GitHub w3c / csswg-drafts # 1693 або в будь-якому випуску CSS GitHub з префіксом "[ css-env-1] ” .


Оновлення 2019-07-06 : Робота над технічними умовами продовжується. Випуск GitHub №2627 та випуск GitHub №3578 присвячені спеціальним змінним середовищам у медіа-запитах.


31

Що ви МОЖИТЕ зробити, це @media запитати ваш: root заява!

:root {
     /* desktop vars */
}
@media screen and (max-width: 479px) {
    :root {
        /* mobile vars */
    }
}

Цілком працює в Chrome, Firefox та Edge принаймні в останніх виробничих версіях станом на цю публікацію.


Нічого дякую! Це безумовно має бути правильною відповіддю.
SimplyComplexable

1
Добре знати. Одне обмеження: Якщо вам також потрібно отримати доступ до цього значення як а var, щоб його можна було використовувати в обчисленнях в іншому місці css, для цього все ж потрібно поставити "магічне значення" (тут, 479 пікселів) у двох місцях: медіа-запит та заява var.
ToolmakerSteve

8

Мабуть, просто не вдається використовувати подібні змінні CSS. Це одне з обмежень .

Розумний спосіб використовувати це - змінити свої змінні в медіа-запиті, щоб вплинути на весь ваш стиль. Я рекомендую цю статтю .

:root {
  --gutter: 4px;
}

section {
  margin: var(--gutter);
}

@media (min-width: 600px) {
  :root {
    --gutter: 16px;
  }
}

Я не розумію значення "зміни своїх змінних у медіа-запиті", ти можеш показати приклад?

1
Це не те, що я мав на увазі. Я запитав про значення медіа-запиту.

4
Так, щойно це зроблено, це в статті, яку я зв'язав. Я знаю, що це не те, чого ви очікували, але змінні CSS просто не можна використовувати для визначення медіа-запитів
Cohars

8

Один із способів досягти того, що ви хочете, - це використання пакету npm postcss-media-variables.

Якщо ви все добре використовуєте npm-пакети, тут ви можете ознайомитись із документальним документом для того ж

Приклад

/* input */
:root {
  --min-width: 1000px;
  --smallscreen: 480px;
}
@media (min-width: var(--min-width)) {}
@media (max-width: calc(var(--min-width) - 1px)) {}

@custom-media --small-device (max-width: var(--smallscreen));
@media (--small-device) {}

4
Дякую, але я намагався не використовувати жодного препроцесора.

та ін. al: За допомогою postcss ви також можете використовувати cssnext cssnext.io/features/#custom-media-queries
sebilasse

1
@sebilasse: користувацькі медіа-запити не вирішують основної проблеми неможливості використання змінних css як точок
перерви

1
postcss не є препроцесором

1

Як ви можете прочитати інші відповіді, досі це зробити неможливо .

Хтось згадав про власні змінні середовища (подібні до користувацьких змінних css env()замість var()), і принцип є здоровим, хоча все ж є 2 основні проблеми:

  • слабка підтримка браузера
  • поки що немає можливості їх визначити (але, мабуть, це буде в майбутньому, оскільки це поки що лише неофіційний проект)

1

Коротка відповідь

Ви можете використовувати JavaScript, щоб змінити значення медіа-запитів і встановити його на значення змінної css.

// get value of css variable
getComputedStyle(document.documentElement).getPropertyValue('--mobile-breakpoint'); // '642px'

// search for media rule
var mediaRule = document.styleSheets[i].cssRules[j];

// update media rule
mediaRule.media.mediaText = '..'


Довга відповідь

Я написав невеликий сценарій, який можна включити на свою сторінку. Він замінює все правила ЗМІ із значенням 1pxзі значенням змінної Css --replace-media-1px, правила зі значенням 2pxз --replace-media-2pxі так далі. Це працює для запитів ЗМІ with, min-width, max-width, height, min-heightі max-heightнавіть тоді , коли вони пов'язані з використанням and.

JavaScript:

function* visitCssRule(cssRule) {
    // visit imported stylesheet
    if (cssRule.type == cssRule.IMPORT_RULE)
        yield* visitStyleSheet(cssRule.styleSheet);

    // yield media rule
    if (cssRule.type == cssRule.MEDIA_RULE)
        yield cssRule;
}

function* visitStyleSheet(styleSheet) {
    try {
        // visit every rule in the stylesheet
        var cssRules = styleSheet.cssRules;
        for (var i = 0, cssRule; cssRule = cssRules[i]; i++)
            yield* visitCssRule(cssRule);
    } catch (ignored) {}
}

function* findAllMediaRules() {
    // visit all stylesheets
    var styleSheets = document.styleSheets;
    for (var i = 0, styleSheet; styleSheet = styleSheets[i]; i++)
        yield* visitStyleSheet(styleSheet);
}

// collect all media rules
const mediaRules = Array.from(findAllMediaRules());

// read replacement values
var style = getComputedStyle(document.documentElement);
var replacements = [];
for (var k = 1, value; value = style.getPropertyValue('--replace-media-' + k + 'px'); k++)
    replacements.push(value);

// update media rules
for (var i = 0, mediaRule; mediaRule = mediaRules[i]; i++) {
    for (var k = 0; k < replacements.length; k++) {
        var regex = RegExp('\\((width|min-width|max-width|height|min-height|max-height): ' + (k+1) + 'px\\)', 'g');
        var replacement = '($1: ' + replacements[k] + ')';
        mediaRule.media.mediaText = mediaRule.media.mediaText.replace(regex, replacement);
    }
}

CSS:

:root {
  --mobile-breakpoint: 642px;

  --replace-media-1px: var(--mobile-breakpoint);
  --replace-media-2px: ...;
}

@media (max-width: 1px) { /* replaced by 642px */
  ...
}

@media (max-width: 2px) {
  ...
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.