CSS本机变量在媒体查询中不起作用


140

我正在尝试在媒体查询中使用CSS变量,但它不起作用。

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

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

}

您尝试过几种浏览器吗?(例如Chrome和Firefox)
Cohars,2016年

1
没有预处理程序@SandrinaPereira
Cohars 2016年

1
@SandrinaPereira因此,您可以使用Firefox和Chrome👍– Cohars
2016年


3
只是为了向人们表明通过Google发现这一点:您可以在媒体查询范围内使用CSS自定义属性,而不能在媒体查询声明中使用它们。
戴维·德普罗斯特

Answers:


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-env-1]”


原来的答复2017年11月9日:近日,CSS工作组决定CSS变量2级将使用支持用户自定义的环境变量env(),他们会尽量让他们在媒体查询有效在苹果公司首次提出标准的用户代理属性之后,即2017年9月iPhone X正式发布前不久,该小组解决了这一问题(另见WebKit:“为iPhone X设计网站”)。然后,其他浏览器代表同意,它们通常可用于许多设备,例如电视显示器和带有出血边缘的墨水打印。(env()以前称为constant(),但现在已弃用。您可能仍然会看到引用旧名称的文章,例如Peter-Paul Koch的这篇文章。)经过了几周,Mozilla的Cameron McCormack意识到这些环境变量可以在媒体查询中使用,而Tab Atkins,Jr.则认为。然后,Google的作者意识到用户定义的环境变量作为可用于媒体查询的全局,不可替代的根变量特别有用。现在,苹果公司的Dean“ Dino” Jackson将与Atkins一起编辑Level 2。

您可以在w3c/csswg-draftsGitHub第1693期中订阅有关此问题的更新。(有关特别相关的历史详细信息,请扩展嵌入CSSWG Meeting Bot决议中的会议日志,并搜索“ MQ”,代表“媒体查询”。)

我计划在将来出现更多发展时更新此问题。未来令人兴奋。


2018年2月8日更新: Safari Technology Preview 49增加了calc()对媒体查询中的解析的支持,这也可能是env()对它们的支持的前奏。


2018年4月27日更新:Google的Chromium团队已决定开始进行开发env()。作为回应,Atkins已经开始env()在一个单独的非正式草案标准中指定:CSS Environment Variables Module Level 1。(见他的GitHub的评论在W3C / csswg-起草#1693,并在他的评论W3C / csswg-起草#1817。)在媒体查询作为一个明确的使用情况下的呼叫草案出来变量:

由于环境变量不依赖于从特定元素中抽取的任何东西的值,因此可以在没有明显元素可借鉴的地方(例如在@media规则中,var()函数无效)使用它们。

如果您已阅读规范并有疑问,或者想要表达对媒体查询用例的支持,则仍可以在GitHub w3c / csswg-drafts#1693任何带有前缀“ [[ css-env-1]”


更新2019-07-06:规格方面的工作仍在继续。GitHub问题2627GitHub问题3578专门用于媒体查询中的自定义环境变量。


31

但是,您可以做的是@media查询您的:root语句!

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

截至本文发布时,至少可以在Chrome,Firefox和Edge上完全运行。


哇谢谢!这绝对应该是正确的答案。
SimplyComplexable

1
很高兴知道。一个限制:如果还需要以形式访问该值var,则可以在的其他位置进行计算时css,这仍然需要将“魔术值”(此处为479px)放在两个位置:媒体查询和var声明。
制造商

8

显然,不可能像这样使用本机CSS变量。这是局限性之一

一种聪明的使用方法是更改​​媒体查询中的变量,以影响所有样式。我推荐这篇文章

:root {
  --gutter: 4px;
}

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

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

我不理解“在media-query中更改变量”的含义,可以显示示例吗?

1
这不是我的意思。我询问了媒体查询值。

4
是的,只是做了,在我链接的文章中。我知道这不是您所期望的,但是CSS变量无法用于定义媒体查询
Cohars,2016年

8

实现您想要的一种方法是使用npm package 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:custom-media-queries不能解决不能将css变量用作媒体查询断点的主要问题
zhirzh

1
postcss不是预处理器

1

正如您可以阅读其他答案一样,仍然无法这样做。

有人提到了自定义环境变量(类似于自定义css变量,env()而不是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等。该方法适用于媒体查询withmin-widthmax-widthheightmin-heightmax-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) {
  ...
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.