Las variables nativas de CSS no funcionan en consultas de medios


140

Estoy tratando de usar variables CSS en la consulta de medios y no funciona.

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

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

}

¿Has probado en varios navegadores? (Como Chrome y Firefox)
Cohars

1
Sin preprocesador @SandrinaPereira
Cohars

1
@SandrinaPereira Para que puedas en Firefox y Chrome 👍
Cohars


3
Solo para aclarar a las personas que encuentran esto a través de Google: puede usar propiedades personalizadas de CSS dentro del alcance de una consulta de medios, simplemente no puede usarlas en una declaración de consulta de medios.
David Deprost

Respuestas:


112

De la especificación ,

La var()función se puede usar en lugar de cualquier parte de un valor en cualquier propiedad de un elemento. La var()función no se puede usar como nombres de propiedad, selectores o cualquier otra cosa además de los valores de propiedad. (Hacerlo generalmente produce una sintaxis no válida, o bien un valor cuyo significado no tiene conexión con la variable).

Entonces no, no puede usarlo en una consulta de medios.

Y eso tiene sentido. Debido a que puede establecer, --mobile-breakpointpor ejemplo :root, en , es decir, el <html>elemento, y desde allí ser heredado a otros elementos. Pero una consulta de medios no es un elemento, no hereda <html>, por lo que no puede funcionar.

Esto no es lo que las variables CSS intentan lograr. Puede usar un preprocesador CSS en su lugar.


77
La respuesta es correcta porque la especificación no maneja actualmente las variables CSS en las consultas de medios, pero incorrecta en eso no es lo que las variables CSS están tratando de lograr. La reducción de la repetición y los números mágicos es exactamente la razón por la cual se crearon las variables CSS : consulte w3.org/TR/css-variables-1/#intro
mikemaccana el

69

Como Oriol ha respondido , actualmente, las Variables CSS Nivel 1 var()no se pueden usar en consultas de medios . Sin embargo, ha habido desarrollos recientes que abordarán este problema. En unos pocos años, una vez que el Módulo de Variables de Entorno CSS Nivel 1 esté estandarizado e implementado, podremos usar env()variables en consultas de medios en todos los navegadores modernos.

Si lee la especificación y tiene alguna inquietud, o si desea expresar su apoyo al caso de uso de consultas de medios, aún puede hacerlo en GitHub w3c / csswg-drafts # 1693 o en cualquier problema de CSS GitHub con el prefijo "[ css-env-1] " .


Respuesta original 09-11-2017 : Recientemente, el Grupo de trabajo CSS decidió que las Variables CSS Nivel 2 admitirán el uso de variables de entorno definidas por el usuario env()y tratarán de que sean válidas en las consultas de los medios . El Grupo resolvió esto después de que Apple propuso por primera vez las propiedades estándar de agente de usuario , poco antes del anuncio oficial del iPhone X en septiembre de 2017 (ver también WebKit: "Diseño de sitios web para iPhone X" por Timothy Horton ). Otros representantes del navegador acordaron que serían generalmente útiles en muchos dispositivos, como pantallas de televisión e impresión de tinta con bordes de sangrado. ( env()solía llamarseconstant(), pero eso ahora ha quedado en desuso. Es posible que aún vea artículos que se refieren al nombre anterior, como este artículo de Peter-Paul Koch .) Después de algunas semanas, Cameron McCormack de Mozilla se dio cuenta de que estas variables de entorno serían utilizables en consultas de medios, y Tab Atkins, Jr. Luego, Google se dio cuenta de que las variables de entorno definidas por el usuario serían especialmente útiles como variables raíz globales, no reemplazables y utilizables en consultas de medios. Ahora, Dean "Dino" Jackson de Apple se unirá a Atkins en la edición del Nivel 2.

Puede suscribirse a las actualizaciones sobre este asunto en la w3c/csswg-draftsedición # 1693 de GitHub . (Para obtener detalles históricos especialmente relevantes, expanda los registros de la reunión integrados en las resoluciones del CSSWG Meeting Bot y busque "MQ", que significa "consultas de medios".)

Planeo actualizar esta pregunta en el futuro cuando ocurran más desarrollos. El futuro es emocionante.


Actualización 08/02/2018 : Safari Technology Preview 49 ha agregado soporte para analizar calc()las consultas de medios, lo que también puede ser un preludio de soporte env()en ellas.


Actualización 27/04/2018 : el equipo de Chromium en Google ha decidido comenzar a trabajar env(). En respuesta, Atkins comenzó a especificar env()en un borrador de estándar no oficial separado: el Módulo de Variables de Entorno CSS Nivel 1 . (Consulte su comentario de GitHub en w3c / csswg-drafts # 1693 y su comentario en w3c / csswg-drafts # 1817. ) El borrador menciona las variables en las consultas de los medios como un caso de uso explícito:

Debido a que las variables de entorno no dependen del valor de nada extraído de un elemento en particular, se pueden usar en lugares donde no hay un elemento obvio del cual extraer, como en las @mediareglas, donde la var()función no sería válida.

Si lee la especificación y tiene alguna inquietud, o si desea expresar su apoyo al caso de uso de consultas de medios, aún puede hacerlo en GitHub w3c / csswg-drafts # 1693 o en cualquier problema de CSS GitHub con el prefijo "[ css-env-1] " .


Actualización 2019-07-06 : el trabajo continúa en las especificaciones. El número 2627 de GitHub y el número 3578 de GitHub están dedicados a variables de entorno personalizadas en consultas de medios.


31

Sin embargo, lo que PUEDE hacer es consultar a @media su: declaración raíz.

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

Totalmente funciona en Chrome, Firefox y Edge al menos las últimas versiones de producción a partir de esta publicación.


¡Wow gracias! Esta definitivamente debería ser la respuesta correcta.
SimplyComplexable el

1
Bueno saber. Una limitación: si también necesita acceder a ese valor como a var, por lo que puede usarlo en cálculos en otra parte del css, esto todavía requiere poner el "valor mágico" (aquí, 479 px) en dos lugares: la consulta de medios y una declaración var.
ToolmakerSteve

8

Aparentemente, simplemente no es posible usar variables CSS nativas como esa. Es una de las limitaciones .

Una forma inteligente de usarlo es cambiar sus variables en la consulta de medios, para impactar todo su estilo. Recomiendo este artículo .

:root {
  --gutter: 4px;
}

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

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

No entiendo el significado de "cambiar sus variables en la consulta de medios", ¿puede mostrar un ejemplo?

1
Esto no es lo que quise decir. Pregunté sobre el valor de la consulta de medios.

44
Sí, acabo de hacerlo, está en el artículo que vinculé. Sé que no es lo que esperaba, pero las variables CSS simplemente no se puede utilizar para definir las preguntas de los medios
Cohars

8

Una forma de lograr lo que desea es usar el paquete npm postcss-media-variables.

Si está de acuerdo con el uso de paquetes npm, puede consultar la documentación aquí.

Ejemplo

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

44
Gracias, pero estaba tratando de no usar ningún preprocesador.

et. al: Con postcss también puede usar cssnext cssnext.io/features/#custom-media-queries
sebilasse el

1
@sebilasse: personalizados-media-consultas no aborda el principal problema de no ser capaz de utilizar las variables css como puntos de corte para las consultas de los medios de comunicación
zhirzh

1
postcss no es un preprocesador

1

Como puede leer otras respuestas, aún no es posible hacerlo.

Alguien mencionó variables ambientales personalizadas (similares a las variables CSS personalizadas en env()lugar de var()), y el principio es sólido, aunque todavía hay 2 problemas principales:

  • soporte de navegador débil
  • hasta ahora no hay forma de definirlos (pero probablemente lo será en el futuro, ya que hasta ahora solo es un borrador no oficial)

1

Respuesta corta

Puede usar JavaScript para cambiar el valor de las consultas de medios y establecerlo en el valor de una variable 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 = '..'


Respuesta larga

Escribí un pequeño script que puedes incluir en tu página. Reemplaza cada regla de medios con un valor de 1pxcon el valor de la variable css --replace-media-1px, reglas con valor 2pxcon --replace-media-2pxy así sucesivamente. Esto funciona para las preguntas de los medios with, min-width, max-width, height, min-heighty max-heightaun cuando se conectan utilizando 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) {
  ...
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.