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

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

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


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


}
123354 次浏览

显然,像这样使用原生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包,那么你可以在这里查看相同的文档:

例子

/* 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 GitHub问题标记为“CSS -env-1”中这样做。

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


原文来自2017-11-09: 最近,CSS变量级别2将使用env()支持用户定义的环境变量,并将尝试使它们在媒体查询中有效CSS工作组决定。该小组在2017年9月iPhone X正式发布前不久解决了这个在苹果首次提出标准用户代理属性之后(另见WebKit: Timothy Horton的《为iPhone X设计网站》)。其他浏览器代表随后也同意,它们将在许多设备上普遍有用,比如电视显示器和带出血边的墨水打印。(env()以前被称为constant(),但现在已弃用。你可能仍然会看到引用旧名称的文章,例如本文作者:Peter-Paul Koch。)几周后,Mozilla的Cameron McCormack意识到发现这些环境变量可以在媒体查询中使用,而谷歌的小Tab Atkins意识到发现用户定义的环境变量可以作为全局的、不可覆盖的根变量在媒体查询中使用。现在,env()0在编辑Level 2.

你可以在w3c/csswg-drafts GitHub issue #1693中订阅关于这个问题的更新(特别是相关的历史细节,展开嵌入在CSSWG会议机器人的决议中的会议日志并搜索“MQ”,它代表“媒体查询”)。

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

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

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

<强> < / >强能所做的是@media查询你的:root语句!

: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 = '..'

< br >

长回答

我写了一个小脚本,你可以把它放在你的页面上。它将每个值为1px的媒体规则替换为css变量--replace-media-1px的值,将值为2px的规则替换为--replace-media-2px,等等。这适用于媒体查询withmin-widthmax-widthheightmin-heightmax-height,即使它们使用--replace-media-1px0连接。

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);

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

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


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