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

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

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

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

}

person Community    schedule 21.11.2016    source источник
comment
Вы пробовали в нескольких браузерах? (Как Chrome и Firefox)   -  person Cohars    schedule 21.11.2016
comment
Да, я использую последнюю версию Chrome   -  person    schedule 21.11.2016
comment
Какой препроцессор css вы используете? Что вы пытаетесь достичь?   -  person sandrina-p    schedule 21.11.2016
comment
Без препроцессора @SandrinaPereira   -  person Cohars    schedule 21.11.2016
comment
Без препроцессора нельзя использовать переменные. Не обошлось и без полной поддержки браузеров. Подробнее см. Здесь. developer.mozilla.org/en-US/docs/Web/CSS/ Using_CSS_variables   -  person sandrina-p    schedule 21.11.2016
comment
@SandrinaPereira Итак, вы можете использовать Firefox и Chrome ????   -  person Cohars    schedule 21.11.2016
comment
caniuse.com/#feat=css-variables   -  person    schedule 21.11.2016
comment
@ sandrina-p Не все хотят или имеют клиентов, готовых платить, полную поддержку в каждом браузере.   -  person mikemaccana    schedule 25.07.2018
comment
Просто чтобы прояснить для людей, которые находят это через Google: вы можете использовать настраиваемые свойства CSS внутри области медиа-запроса, вы просто не можете использовать их в объявлении медиа-запроса.   -  person David Deprost    schedule 10.06.2019


Ответы (7)


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

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

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

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

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

person Oriol    schedule 21.11.2016
comment
Ответ правильный в том смысле, что спецификация в настоящее время не обрабатывает переменные CSS в медиа-запросах, но неверна в том смысле, что переменные CSS не пытаются этого достичь. Сокращение повторений и магических чисел - вот почему были созданы переменные CSS - см. w3.org/TR/css-variables-1/#intro - person mikemaccana; 25.07.2018
comment
Кстати, как это НЕ значение свойства ?? Это значение свойства max-width! Он должен полностью работать! - person user9645; 09.12.2020
comment
@ user9645 Собственно, нет. Оно может выглядеть как свойство max-width, потому что вы пишете тот же текст, но оно выполняет нечто совершенно иное. Объявление свойства CSS действует как установщик, он устанавливает значение для элемента, а max-width в медиа-запросе является геттером: он запрашивает текущую ширину чего-либо (а затем сравнивает ее с предоставленным значением). Текст max-width: 1000px в качестве медиа-запроса (в форме НЕДЕЙСТВИТЕЛЬНОГО псевдокода) похож на viewport.getWidth() <= 1000px, а в качестве объявления свойства это будет element.setMaxWidth(1000px). - person Taederias; 29.05.2021

Как Ориоль ответил, в настоящее время var() Переменные CSS уровня 1 нельзя использовать в медиа-запросах. Однако в последнее время появились разработки, которые позволят решить эту проблему. Через несколько лет, когда уровень 1 модуля переменных среды CSS будет стандартизирован и реализовано, мы сможем использовать 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(), но теперь он устарел. Вы по-прежнему можете видеть статьи, относящиеся к старому имени, например эта статья Питера-Пола Коха.) Через несколько недель Кэмерон Маккормак из Mozilla понял, что эти переменные среды можно использовать в медиа-запросах, и Таб Аткинс, младший из Google, затем понял, что определяемые пользователем переменные среды будут особенно полезны как глобальные непереопределяемые корневые переменные, которые можно использовать в медиа-запросы. Теперь Дин «Дино» Джексон из Apple присоединится к Аткинсу в Редактирование Уровень 2.

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

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


Обновление 2018-02-08: Safari Technology Preview 49 добавил поддержку синтаксического анализа calc() в медиа-запросах, что может быть прелюдией к поддержке env() и в них.


Обновление 2018-04-27: команда Chromium в Google решила начать работу над env(). В ответ Аткинс начал указывать env() в отдельном неофициальном проекте стандарта: CSS Модуль переменных среды, уровень 1. (См. его комментарий GitHub в w3c / csswg-draft # 1693. и его комментарий в w3c / csswg-draft # 1817.) Черновик вызывает переменные в медиа-запросах в качестве явного варианта использования:

Поскольку переменные среды не зависят от значения чего-либо, извлеченного из определенного элемента, их можно использовать в местах, где нет очевидного элемента для извлечения, например, в правилах @media, где функция var() не действует.

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


Обновление 2019-07-06: работа над спецификациями продолжается. проблема GitHub № 2627 и GitHub issue # 3578 посвящены настраиваемым переменным среды в медиа-запросах.

person jschoi    schedule 09.11.2017

Однако вы МОЖЕТЕ сделать @media запросить ваш оператор: root!

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

Полностью работает в Chrome, Firefox и Edge, по крайней мере, в последних производственных версиях на момент публикации.

Одно ограничение: если вам нужно получить доступ к значению как к переменной - например, для использования в вычислениях в другом месте - вам понадобится переменная, и для этого потребуется определить переменную в двух местах: медиа-запрос и объявление переменной.

person Sean    schedule 26.01.2019

По-видимому, просто невозможно использовать такие собственные переменные CSS. Это одно из ограничений.

Умный способ использовать это - изменить ваши переменные в медиа-запросе, чтобы повлиять на весь ваш стиль. Я рекомендую эту статью.

:root {
  --gutter: 4px;
}

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

@media (min-width: 600px) {
  :root {
    --gutter: 16px;
  }
}
person Cohars    schedule 21.11.2016
comment
Я не понимаю смысла изменения ваших переменных в медиа-запросе, можете показать пример? - person ; 21.11.2016
comment
Я не это имел в виду. Я спросил о значении медиа-запроса. - person ; 21.11.2016
comment
Да, только что, это в статье, на которую я ссылался. Я знаю, что это не то, что вы ожидали, но переменные CSS просто не могут использоваться для определения медиа-запросов - person Cohars; 21.11.2016

Один из способов добиться желаемого - использовать пакет 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) {}
person pradeep1991singh    schedule 21.11.2016
comment
Спасибо, но я пытался не использовать препроцессор. - person ; 21.11.2016
comment
et. al: С postcss вы также можете использовать cssnext cssnext.io/features/#custom-media-queries - person sebilasse; 13.04.2018
comment
@sebilasse: custom-media-query не решает основную проблему невозможности использовать переменные css в качестве точек останова для медиа-запросов - person zhirzh; 16.09.2018
comment
postcss не препроцессор - person ; 08.12.2019

Короткий ответ

Вы можете использовать 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) {
  ...
}
person Ich_73    schedule 10.05.2020
comment
это похоже на интересное решение! - person Aurovrata; 21.10.2020

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

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

  • слабая поддержка браузера
  • пока нет возможности их определить (но, вероятно, будет в будущем, так как это пока только неофициальный проект)
person The Vojtisek    schedule 15.12.2018