CSS本机变量不适用于媒体查询

95 css media-queries css-variables

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

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

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

}
Run Code Online (Sandbox Code Playgroud)

Ori*_*iol 81

规格来看,

var()函数可用于代替元素上任何属性中值的任何部分.该var()函数不能用作属性名称,选择器或属性值之外的任何其他内容.(这样做通常会产生无效的语法,或者其含义与变量无关的值.)

所以不,你不能在媒体查询中使用它.

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

这不是CSS变量试图完成的.您可以使用CSS预处理器.

  • 答案是正确的,因为规范目前不处理媒体查询中的CSS变量,但不正确的是CSS变量试图完成的.**减少重复和幻数正是创建CSS变量的原因** - 请参阅https://www.w3.org/TR/css-variables-1/#intro (43认同)
  • 顺便说一句,这*不是*属性值怎么办?这是`max-width`的属性值!它应该完全有效! (10认同)
  • @user9645 事实上,没有。它可能看起来像“max-width”属性,因为您编写相同的文本,但它完成的事情完全不同。CSS 属性声明充当“setter”,它为元素设置一个值,而媒体查询中的“max-width”是一个“getter”:它请求某些内容的当前宽度(然后将其与提供的值)。作为媒体查询的文本“max-width: 1000px”(以某种无效伪代码的形式)类似于“viewport.getWidth() &lt;= 1000px”,而作为属性声明,它将是“element.setMaxWidth” (1000 像素)`。 (2认同)

jsc*_*hoi 53

正如Oriol已经回答的那样,目前,CSS Variables Level 1 var()不能用于媒体查询.但是,最近的一些发展将解决这个问题.几年后,一旦CSS环境变量模块1级标准化并实现,我们就可以env()在所有现代浏览器中使用媒体查询中的变量.

如果您阅读规范并有疑虑,或者您想表达对媒体查询用例的支持,您仍然可以在GitHub w3c/csswg-drafts#1693任何带有"[前缀"的CSS GitHub问题中执行此操作. css-env-1]".


原来的答复2017年11月9日:近日,CSS工作组决定CSS变量2级将使用支持用户自定义的环境变量env(),他们会尽量让他们在媒体查询有效.在2017年9月iPhone X官方发布之前不久,该集团在Apple首次提出标准用户代理属性后解决了这一问题(另请参阅WebKit:Timothy Horton为"设计iPhone X网站").其他浏览器代表随后同意它们通常可用于许多设备,例如电视显示器和带有出血边缘的墨水打印.(env()曾经被称为constant(),但现在已被弃用.你可能仍会看到引用旧名称的文章,例如Peter-Paul Koch撰写的这篇文章.)几周后,Mozilla的Cameron McCormack意识到这些环境变量可以在媒体查询中使用,然后Google的Tab Atkins,Jr.意识到用户定义的环境变量作为媒体查询中可用的全局,不可覆盖的根变量特别有用.现在,Apple的Dean"Dino"Jackson将加入Atkins编辑Level 2.

您可以在w3c/csswg-draftsGitHub问题#1693中订阅有关此问题的更新.(有关特别相关的历史详细信息,请展开CSSWG Meeting Bot解决方案中嵌入的会议日志,并搜索"MQ",它代表"媒体查询".)

我计划在将来发生更多事态发展时更新这个问题.未来是令人兴奋的.


更新2018-02-08: Safari Technology Preview 49增加了calc()对媒体查询中解析的支持,这也可能是支持env()它们的前奏.


更新2018-04-27:Google的Chromium团队已决定开始工作env().作为回应,Atkins已开始env()在单独的非官方草案标准中指定:CSS环境变量模块1级.(参见他在W3c/csswg-drafts#1693中的GitHub评论他在w3c/csswg-drafts#1817中的评论.)草案将媒体查询中的变量称为明确的用例:

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

如果您阅读规范并有疑虑,或者您想表达对媒体查询用例的支持,您仍然可以在GitHub w3c/csswg-drafts#1693任何带有"[前缀"的CSS GitHub问题中执行此操作. css-env-1]".


Tem*_*fif 24

媒体查询的第 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 */
}
Run Code Online (Sandbox Code Playgroud)

实际上仍然不支持此功能,因此我们必须等待才能使用此功能。


小智 13

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

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

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

  • 我不完全确定你的建议是什么?这意味着没有支持对吗? (2认同)

pra*_*ngh 7

实现您想要的一种方法是使用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) {}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,但是我试图不使用任何预处理器。 (3认同)

Coh*_*ars 6

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

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

:root {
  --gutter: 4px;
}

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

@media (min-width: 600px) {
  :root {
    --gutter: 16px;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,只是做了,在我链接的文章中。我知道这不是您所期望的,但是CSS变量**只是不能用来定义媒体查询** (3认同)

小智 5

简答

您可以使用 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 = '..'
Run Code Online (Sandbox Code Playgroud)


长答案

我写了一个小脚本,您可以将其包含在您的页面中。它将每个媒体规则的值替换1px为 css 变量的值--replace-media-1px,规则的值2px替换为 with--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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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) {
  ...
}
Run Code Online (Sandbox Code Playgroud)