Natywne zmienne CSS nie działają w zapytaniach o media

140

Próbuję użyć zmiennych CSS w zapytaniu o media i to nie działa.

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

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

}

źródło
Czy próbowałeś w kilku przeglądarkach? (Podobnie jak Chrome i Firefox)
Cohars
1
Bez preprocesora @SandrinaPereira
Cohars
1
@SandrinaPereira Więc możesz w Firefoksie i Chrome 👍
Cohars
3
Po prostu do wyjaśnienia dla osób ze znalezieniem tego przez Google: Państwo może wykorzystywać właściwości CSS niestandardowych wewnątrz zakresu zapytania mediów, po prostu nie można ich używać w deklaracji media zapytania.
David Deprost

Odpowiedzi:

112

Ze specyfikacją ,

var()Funkcja może być używana zamiast dowolnej części wartości w każdej nieruchomości na elemencie. var()Funkcja nie może być używana jako nazwy własności, selektorów, czy cokolwiek innego oprócz wartości nieruchomości. (Takie postępowanie zwykle powoduje powstanie nieprawidłowej składni lub wartości, której znaczenie nie ma związku ze zmienną).

Więc nie, nie możesz go użyć w zapytaniu o media.

I to ma sens. Bo możesz ustawić --mobile-breakpointnp. Na :root, czyli <html>element, i stamtąd być dziedziczony do innych elementów. Ale zapytanie o media nie jest elementem, nie dziedziczy po nim <html>, więc nie może działać.

To nie jest to, co próbują osiągnąć zmienne CSS. Zamiast tego możesz użyć preprocesora CSS.

Oriol
źródło
77
Odpowiedź jest prawidłowa, ponieważ specyfikacja obecnie nie obsługuje zmiennych CSS w zapytaniach o media, ale nieprawidłowa, ponieważ nie jest to, co próbują osiągnąć zmienne CSS. Zmniejszenie liczby powtórzeń i magia jest dokładnie dlaczego zmienne CSS zostały stworzone - patrz w3.org/TR/css-variables-1/#intro
mikemaccana
69

Jak odpowiedział Oriol , obecnie w zapytaniach o media nie można używać zmiennych CSS poziomu 1var() . Jednak ostatnio nastąpiły zmiany, które pozwolą rozwiązać ten problem. Za kilka lat, po ustandaryzowaniu i wdrożeniu modułu zmiennych środowiskowych CSS na poziomie 1 , będziemy mogli używać env()zmiennych w zapytaniach o media we wszystkich nowoczesnych przeglądarkach.

Jeśli przeczytałeś specyfikację i masz obawy lub jeśli chcesz wyrazić swoje poparcie dla przypadku użycia zapytania o media, nadal możesz to zrobić w GitHub w3c / csswg-drafts # 1693 lub w jakimkolwiek numerze CSS GitHub poprzedzonym prefiksem „[ css-env-1] ” .


Oryginalna odpowiedź 09.11.2017 : Niedawno grupa robocza CSS zdecydowała, że zmienne CSS poziomu 2 będą obsługiwać zmienne środowiskowe zdefiniowane przez użytkownika przy użyciu env()i będą starać się, aby były one prawidłowe w zapytaniach o media . Grupa rozwiązała ten problem po tym, jak Apple po raz pierwszy zaproponował standardowe właściwości agenta użytkownika , na krótko przed oficjalnym ogłoszeniem iPhone'a X we wrześniu 2017 r. (Patrz także WebKit: „Projektowanie stron internetowych dla iPhone'a X” autorstwa Timothy'ego Hortona ). Inni przedstawiciele przeglądarek zgodzili się wtedy, że będą one ogólnie przydatne na wielu urządzeniach, takich jak wyświetlacze telewizyjne i druk atramentowy z krawędziami spadającymi. ( env()kiedyś nazywanoconstant(), ale teraz jest to przestarzałe. Nadal możesz zobaczyć artykuły, które odwołują się do starej nazwy, na przykład ten artykuł Petera-Paula Kocha .) Po kilku tygodniach Cameron McCormack z Mozilli zdał sobie sprawę, że te zmienne środowiskowe będą użyteczne w zapytaniach o media, a Tab Atkins, Jr. firmy Google zdał sobie wtedy sprawę, że zmienne środowiskowe zdefiniowane przez użytkownika byłyby szczególnie przydatne jako globalne, niepodlegające zastąpieniu zmienne główne, których można używać w zapytaniach o media. Teraz Dean „Dino” Jackson z Apple dołączy do Atkinsa w edycji poziomu 2.

Możesz zasubskrybować aktualizacje w tej sprawie w w3c/csswg-draftsnumerze 1693 na GitHubie . (Aby uzyskać szczególnie istotne szczegóły historyczne, rozwiń dzienniki spotkań osadzone w rozwiązaniach CSSWG Meeting Bot i wyszukaj „MQ”, co oznacza „zapytania o media”).

Planuję zaktualizować to pytanie w przyszłości, gdy nastąpi więcej zmian. Przyszłość jest ekscytująca.


Aktualizacja 2018-02-08 : Safari Technology Preview 49 dodała obsługę parsowania calc()w zapytaniach o media, co może być wstępem do env()ich obsługi.


Aktualizacja 2018-04-27 : Zespół Chromium w Google zdecydował się rozpocząć pracę env(). W odpowiedzi Atkins zaczął określać env()w oddzielnym, nieoficjalnym projekcie standardu: moduł zmiennych środowiskowych CSS Poziom 1 . (Zobacz jego komentarz GitHub w w3c / csswg-drafts # 1693 i jego komentarz w w3c / csswg-drafts # 1817 ). Wersja robocza przywołuje zmienne w zapytaniach o media jako jawny przypadek użycia:

Ponieważ zmienne środowiskowe nie zależą od wartości czegokolwiek narysowanego z określonego elementu, mogą być używane w miejscach, w których nie ma oczywistego elementu do narysowania, na przykład w @mediaregułach, w których var()funkcja byłaby nieprawidłowa.

Jeśli przeczytałeś specyfikację i masz obawy lub jeśli chcesz wyrazić swoje poparcie dla przypadku użycia zapytania o media, nadal możesz to zrobić w GitHub w3c / csswg-drafts # 1693 lub w dowolnym numerze CSS GitHub poprzedzonym prefiksem „[ css-env-1] ” .


Aktualizacja 06.07.2019 : Trwają prace nad specyfikacjami. GitHub numer 2627 i GitHub numer 3578 są poświęcone niestandardowym zmiennym środowiskowym w zapytaniach o media.

jschoi
źródło
31

MOŻESZ jednak zrobić zapytanie @media do instrukcji: root!

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

Całkowicie działa w Chrome, Firefox i Edge przynajmniej w najnowszych wersjach produkcyjnych na ten post.

Sean
źródło
Wow dzięki! To zdecydowanie powinna być poprawna odpowiedź.
SimplyComplexable
1
Dobrze wiedzieć. Jedno ograniczenie: jeśli trzeba również uzyskać dostęp do tej wartości jako a var, więc można jej użyć w obliczeniach w innym miejscu w css, nadal wymaga to umieszczenia „magicznej wartości” (tutaj 479px) w dwóch miejscach: zapytanie o media i deklaracja var.
ToolmakerSteve
8

Najwyraźniej po prostu nie jest możliwe użycie takich natywnych zmiennych CSS. To jedno z ograniczeń .

Sprytnym sposobem użycia tego jest zmiana zmiennych w zapytaniu o media, aby wpłynąć na cały Twój styl. Polecam ten artykuł .

:root {
  --gutter: 4px;
}

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

@media (min-width: 600px) {
  :root {
    --gutter: 16px;
  }
}
Cohars
źródło
Nie rozumiem znaczenia „zmień zmienne w zapytaniu o media”, możesz pokazać przykład?
1
Nie o to mi chodziło. Zapytałem o wartość zapytania o media.
4
Tak, właśnie to zrobiłem, to jest w artykule, do którego dołączyłem. Wiem, że to nie jest to, czego się spodziewałeś, ale zmiennych CSS po prostu nie można używać do definiowania zapytań o media
Cohars
8

Jednym ze sposobów osiągnięcia tego, co chcesz, jest użycie pakietu npm postcss-media-variables.

Jeśli nie masz nic przeciwko korzystaniu z pakietów npm, możesz zapoznać się z dokumentacją tego samego tutaj

Przykład

/* 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) {}
pradeep1991singh
źródło
4
Dzięki, ale próbowałem nie używać żadnego preprocesora.
et. al: Z postcss możesz także użyć cssnext cssnext.io/features/#custom-media-queries
sebilasse
1
@sebilasse: zapytania o media niestandardowe nie rozwiązują głównego problemu polegającego na niemożności użycia zmiennych css jako punktów przerwania dla zapytań o media
zhirzh
1
postcss nie jest preprocesorem
1

Jak możesz przeczytać inne odpowiedzi, nadal nie możesz tego zrobić.

Ktoś wspomniał o niestandardowych zmiennych środowiskowych (podobnych do niestandardowych zmiennych css env()zamiast var()) i zasada jest słuszna, chociaż nadal występują 2 główne problemy:

  • słaba obsługa przeglądarki
  • póki co nie ma sposobu, aby je zdefiniować (ale prawdopodobnie będzie w przyszłości, ponieważ jest to na razie tylko nieoficjalny projekt)
Vojtisek
źródło
1

Krótka odpowiedź

Możesz użyć JavaScript, aby zmienić wartość zapytań o media i ustawić ją na wartość zmiennej 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 = '..'


Długa odpowiedź

Napisałem mały skrypt, który możesz umieścić na swojej stronie. Zastępuje każdą regułę multimedialny o wartości 1pxo wartości zmiennej css --replace-media-1px, przepisy o wartości 2pxze --replace-media-2pxi tak dalej. Działa to dla zapytań medialnych with, min-width, max-width, height, min-heighti max-heightnawet wtedy, gdy są one połączone za pomocą 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) {
  ...
}
Ich_73
źródło