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

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

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

}

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

使用它的一个聪明的方法是改变media-query中的变量,以影响你的所有风格。我推荐这篇文章。

:root {
  --gutter: 4px;
}

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

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

从说明书来看,

中的var()函数可用于替换值的任何部分 元素上的任何属性。var()函数不能作为 属性名、选择器或除属性值之外的任何东西。 (这样做通常会产生无效的语法,或者值为 含义与变量无关。)

你不能在媒体查询中使用它。

这是有道理的。因为你可以将——mobile-breakpoint设置为:root,即<html>元素,并从那里继承到其他元素。但是媒体查询不是一个元素,它不继承<html>,所以它不能工作。

这不是CSS变量想要实现的。你可以使用CSS预处理器。

实现你想要的一个方法是使用npm包postcss-media-variables。

如果你可以使用npm包,那么你可以在这里查看相同的文档:

postcss-media-variables

例子

/* 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) {}

正如Oriol所回答的,CSS变量级别1的var()目前不能在媒体查询中使用。然而,最近的事态发展将解决这一问题。一旦CSS环境变量模块第1级标准化并实现,我们将能够在所有现代浏览器的媒体查询中使用env()变量。

CSS工作组(CSSWG)在一个新标准中编纂了env()(目前处于草案阶段):CSS环境变量模块第1级(参见这条GitHub评论和这条评论了解更多信息)。草案将媒体查询中的变量作为一个显式用例:

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

如果你阅读了规范并有一个问题,或者如果你想表达你对媒体查询用例的支持,你可以在第2627期,第3578期,或任何标记为“CSS -env-1”的CSS GitHub问题中这样做。

GitHub issue #2627和GitHub issue #3578致力于媒体查询中的自定义环境变量。


Original answer from 2017-11-09: Recently, the CSS Working Group decided that CSS Variables Level 2 will support user-defined environment variables using env(), and they will try to make them be valid in media queries. The Group resolved this after Apple first proposed standard user-agent properties, shortly before the official announcement of iPhone X in September 2017 (see also WebKit: “Designing Websites for iPhone X” by Timothy Horton). Other browser representatives then agreed they would be generally useful across many devices, such as television displays and ink printing with bleed edges. (env() used to be called constant(), but that has now been deprecated. You might still see articles that refer to the old name, such as this article by Peter-Paul Koch.) After some weeks passed, Cameron McCormack of Mozilla realized that these environment variables would be usable in media queries, and Tab Atkins, Jr. of Google then realized that user-defined environment variables would be especially useful as global, non-overridable root variables usable in media queries. Now, Dean “Dino” Jackson of Apple will join Atkins in editing Level 2.

您可以在w3c/ CSSWG -drafts GitHub issue #1693中订阅有关此问题的更新(特别是相关的历史细节,扩展嵌入CSSWG会议机器人决议中的会议日志,并搜索“MQ”,即“媒体查询”)。

正如你可以阅读其他答案,仍然不可能这样做。

有人提到了自定义环境变量(类似于自定义css变量env()而不是var()),原理是合理的,尽管仍然有2个主要问题:

浏览器支持弱 到目前为止,还没有办法定义它们(但可能在未来会,因为到目前为止这只是一个非官方的草案)

你可以做的是@media查询你的:根语句!

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

完全适用于Chrome, Firefox和Edge,至少是最新的生产版本。

一个限制:如果您需要将值作为变量访问—例如在其他地方的计算中使用—您将需要有一个变量,并且需要在两个地方定义变量:媒体查询和变量声明。

简短的回答

您可以使用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,等等。这适用于,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) {
  ...
}

媒体查询的第5级规范定义了自定义媒体查询,它几乎可以满足您的需求。它允许您像定义CSS变量一样定义断点,然后在不同的地方使用它们。

示例来自规范:

@custom-media --narrow-window (max-width: 30em);

@media (--narrow-window) {
  /* narrow window styles */
}
@media (--narrow-window) and (script) {
  /* special styles for when script is allowed */
}

目前还没有对这个功能的支持,所以在使用这个功能之前,我们必须等待。

你可以使用matchMedia以编程方式构建一个媒体查询:

const mobile_breakpoint = "642px";
const media_query = window.matchMedia(`(max-width: ${mobile_breakpoint})`);
function toggle_mobile (e) {
  if (e.matches) {
    document.body.classList.add("mobile");
  } else {
    document.body.classList.remove("mobile");
  }
}
// call the function immediately to set the initial value:
toggle_mobile(media_query);
// watch for changes to update the value:
media_query.addEventListener("change", toggle_mobile);

然后,不是在CSS文件中使用媒体查询,而是在body有mobile类时应用所需的规则:

.my-div {
  /* large screen rules */
}

.mobile .my-div {
  /* mobile screen rules */
}