Собственные переменные CSS не работают в медиа-запросах

140

Я пытаюсь использовать переменные CSS в медиа-запросе, и это не работает.

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

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

}

источник
Вы пробовали в нескольких браузерах? (Как Chrome и Firefox)
Cohars,
1
Без препроцессора @SandrinaPereira
Cohars
1
@SandrinaPereira Итак, вы можете использовать Firefox и Chrome 👍
Cohars
4
Просто чтобы прояснить для людей, которые находят это через Google: вы можете использовать настраиваемые свойства CSS внутри области медиа-запроса, вы просто не можете использовать их в объявлении медиа-запроса.
Дэвид Депрост

Ответы:

112

Из спецификации ,

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

Так что нет, вы не можете использовать его в медиа-запросах.

И в этом есть смысл. Потому что вы можете установить, --mobile-breakpointнапример :root, на <html>элемент, а оттуда унаследовать его другим элементам. Но медиа-запрос не является элементом, он не наследуется <html>, поэтому не может работать.

Это не то, чего пытаются добиться переменные CSS. Вместо этого вы можете использовать препроцессор CSS.

Ориоль
источник
78
Ответ правильный в том смысле, что спецификация в настоящее время не обрабатывает переменные CSS в медиа-запросах, но неверна в том смысле, что переменные CSS не пытаются этого достичь. Сокращение количества повторений и магических чисел - вот почему были созданы переменные CSS - см. W3.org/TR/css-variables-1/#intro
mikemaccana
69

Как ответил Ориол , в настоящее время CSS-переменные уровня 1 var()не могут использоваться в медиа-запросах . Однако в последнее время появились разработки, которые позволят решить эту проблему. Через несколько лет, когда уровень 1 модуля переменных среды CSS будет стандартизирован и реализован, мы сможем использовать env()переменные в медиа-запросах во всех современных браузерах.

Если вы прочитали спецификацию и у вас возникли сомнения, или если вы хотите выразить свою поддержку варианта использования медиа-запроса, вы все равно можете сделать это в GitHub w3c / csswg-drafts # 1693 или в любой проблеме CSS GitHub с префиксом «[ css-env-1] » .


Исходный ответ 09.11.2017 : Недавно рабочая группа CSS решила, что переменные CSS уровня 2 будут поддерживать использование переменных среды, определяемых пользователем env(), и попытаются сделать их действительными в медиа-запросах . Группа решила эту проблему после того, как Apple впервые предложила стандартные свойства пользовательского агента , незадолго до официального анонса iPhone X в сентябре 2017 года (см. Также WebKit: «Разработка веб-сайтов для iPhone X» Тимоти Хортона ). Затем другие представители браузеров согласились, что они будут в целом полезны на многих устройствах, например на телевизионных дисплеях и при печати чернилами с размытыми краями. ( env()раньше называлсяconstant(), но теперь это устарело. Вы все еще можете увидеть статьи, в которых упоминается старое название, например, эта статья Питера-Пола Коха .) Через несколько недель Кэмерон МакКормак из Mozilla понял, что эти переменные среды можно использовать в медиа-запросах, а Таб Аткинс младший затем компания Google поняла, что определяемые пользователем переменные среды будут особенно полезны в качестве глобальных непереопределяемых корневых переменных, используемых в медиа-запросах. Теперь декан «Дино» Джексон из Apple присоединится к Аткинсу для редактирования Уровня 2.

Вы можете подписаться на обновления по этому поводу в w3c/csswg-draftsвыпуске GitHub # 1693 . (Чтобы получить особенно важные исторические сведения, разверните журналы встреч, встроенные в решения CSSWG Meeting Bot, и выполните поиск по запросу «MQ», что означает «медиа-запросы».)

Я планирую обновить этот вопрос в будущем, когда появятся новые разработки. Будущее захватывающее.


Обновление 2018-02-08 : Safari Technology Preview 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 посвящены пользовательские переменные окружения в запросах медиа.

jschoi
источник
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;
  }
}
Cohars
источник
Мне непонятен смысл «поменять переменные в медиа-запросе», можно пример показать?
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) {}
pradeep1991singh
источник
4
Спасибо, но я пытался не использовать препроцессор.
и др. al: С postcss вы также можете использовать cssnext cssnext.io/features/#custom-media-queries
sebilasse
1
@sebilasse: custom-media- query не решает основную проблему невозможности использовать css-переменные в качестве точек останова для медиа-запросов
zhirzh
1
postcss - это не препроцессор
1

Как вы можете прочитать другие ответы, это все еще невозможно .

Кто-то упомянул пользовательские переменные окружения ( env()вместо них похожие на пользовательские переменные css var()), и принцип верен, хотя есть еще две основные проблемы:

  • слабая поддержка браузера
  • пока нет возможности их определить (но, вероятно, будет в будущем, так как это пока только неофициальный проект)
Войтисек
источник
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) {
  ...
}
Ich_73
источник