2013-03-29 7 views
14

Używam wielu bibliotek (w tym własnych) do dynamicznego ładowania zasobów na podstawie zapytań o media, które opisałem w plikach CSS. Na przykład:Uzyskiwanie dostępu do reguł zapytań dotyczących nośników CSS za pomocą JavaScript/DOM

W CSS:

@media screen and (max-width: 480px) { 
    .foo { 
     display: none; 
    } 
    } 

I z wykorzystaniem ładowacza aktywów; require.js, modernizr.js etc lub wykorzystujące window.matchMedia i związane addListener() funkcje:

if (function("screen and (max-width: 480px)")){ 
    // Load several files 
    load(['mobile.js','mobile.css']); 
    } 

dwukrotnie Deklarowanie nich jest niewygodne/głupie i tak daleko, jak mogę znaleźć, wszystkie biblioteki pomocnicze i Aktywami ładowarki JS wymaga powtarzania zapytań o media zamiast Lokalizowanie ich programowo z JS/DOM.

Tak więc, badałem możliwość dostępu do wartości programowo przez document.stylesheets, ale nie jestem pewien, czy są one dostępne i wydaje się, że istnieje bardzo mało dokumentacji, która mogłaby sugerować, że są.

Najdalej szukałem CSSMediaRule i używam console.dir(document.stylesheets) do eksploracji obiektu arkusza stylów.

Nie ma żadnych odniesień (w zakresie document.stylesheets) do faktycznych reguł zapytań o media stosowanych w CSS - tylko klasy, które mają być stosowane w wyniku zapytań o media ... Co próbuję zlokalizować programowo, jest "ekran oraz (max-width: 480px)"

Czy istnieje sposób dostępu do takich zapytaniu CSS Nośniki zasady poprzez JavaScript/DOM?

+2

Ups, zły link [oto artykuł Szukałem na coderwall] (https: // coderwall. com/p/_ldtkg) – steveax

+2

Dobre pytanie. Dla moich celów zawsze sprawdzałem, czy określone elementy były widoczne, czy nie, ponieważ moja interakcja JavaScriptu dotyczyłaby tych elementów. Powinno jednak istnieć lepsze, bardziej ogólne rozwiązanie. – Brad

+0

Hej, sprawdź to. To może być rozwiązanie. https://github.com/nathansmith/adapt/blob/master/assets/js/adapt.js –

Odpowiedz

11

Do zasad get używać przekrój wariantu przeglądarki:

var styleSheet = document.styleSheets[0]; 
var rules = styleSheet.cssRules || styleSheet.rules; // IE <= 8 use "rules" property 

Do wykrycia obiektu CSSMediaRule w wykazie reguł użytkowania (nie działa w IE < = 8, ponieważ klasa "CSSMediaRule" dostępny tylko w IE> = 9):

var i = 0; 
if (rules[i].type == 4) 
{ 
    // Do something 
} 

Niektóre funkcje stylów uzyskać od obecnego DOM (nie działa w IE < = 8):

function getCssRulesFromDocumentStyleSheets(media) 
{ 
    var resultCssRules = ''; 
    for (var i = 0; i < document.styleSheets.length; i++) 
    { 
     var styleSheet = document.styleSheets[i]; 

     if (isRuleFromMedia(styleSheet, media)) 
      resultCssRules += getCssRulesFromRuleList(styleSheet.cssRules || styleSheet.rules, media); 
    } 

    return resultCssRules; 
} 

function getCssRulesFromRuleList(rules, media) 
{ 
    var resultCssRules = ''; 
    for (var i = 0; i < rules.length; i++) 
    { 
     var rule = rules[i]; 
     if (rule.type == 1) // CSSStyleRule 
     { 
      resultCssRules += rule.cssText + "\r\n"; 
     } 
     else if (rule.type == 3) // CSSImportRule 
     { 
      if (isRuleFromMedia(rule, media)) 
       resultCssRules += getCssRulesFromRuleList(rule.styleSheet.cssRules || rule.styleSheet.rules, media); 
     } 
     else if (rule.type == 4) // CSSMediaRule 
     { 
      if (isRuleFromMedia(rule, media)) 
       resultCssRules += getCssRulesFromRuleList(rule.cssRules || rule.rules, media); 
     } 
    } 

    return resultCssRules; 
} 

function isRuleFromMedia(ruleOrStyleSheet, media) 
{ 
    while (ruleOrStyleSheet) 
    { 
     var mediaList = ruleOrStyleSheet.media; 
     if (mediaList) 
     { 
      if (!isMediaListContainsValue(mediaList, media) && !isMediaListContainsValue(mediaList, 'all') && mediaList.length > 0) 
       return false; 
     } 

     ruleOrStyleSheet = ruleOrStyleSheet.ownerRule || ruleOrStyleSheet.parentRule || ruleOrStyleSheet.parentStyleSheet; 
    } 

    return true; 
} 

function isMediaListContainsValue(mediaList, media) 
{ 
    media = String(media).toLowerCase(); 

    for (var i = 0; i < mediaList.length; i++) 
    { 
     // Access to mediaList by "[index]" notation now work in IE (tested in versions 7, 8, 9) 
     if (String(mediaList.item(i)).toLowerCase() == media) 
      return true; 
    } 

    return false; 
} 

Funkcje Przykład użycia:

<style type="text/css"> 
    @media screen and (max-width: 480px) { 
     p { margin: 10px; } 
    } 

    @media screen and (max-width: 500px) { 
     p { margin: 15px; } 
    } 

    @media print { 
     p { margin: 20px; } 
    } 
</style> 

<!-- ... --> 

<script type="text/javascript"> 
    alert(getCssRulesFromDocumentStyleSheets('print')); 
    alert(getCssRulesFromDocumentStyleSheets('screen and (max-width: 480px)')); 
    // For IE (no space after colon), you can add fix to "isMediaListContainsValue" function 
    alert(getCssRulesFromDocumentStyleSheets('screen and (max-width:480px)')); 
</script> 

Oto JS Fiddle do niego: https://jsfiddle.net/luisperezphd/hyentcqc/

+0

funkcja ta szuka dokładnego dopasowania, np. "screen i (max ..." a nie dla częściowego dopasowania np. "screen", prawda? Próbuję sklonować, usunąć i ponownie utworzyć klasy dla ekranu (bez względu na wymiary) na "wszystkie" (ponieważ mogę po prostu zmień nośnik dla istniejących reguł) Czy uważasz, że można do tego użyć? dzięki. – sergio

5

Oto jak to zrobić:

w CSS tworzenia klas, aby odsłonić lub ukryć zawartość w różnych pułapki. To i tak przydatne narzędzie. Są one już dostępne na przykład w Bootstrapie na Twitterze.

<style type="text/css"> 
    .visible-sm, .visible-md, .visible-lg{ 
    display:none; 
    } 
    @media (max-width: 480px) { 
    .visible-sm{ 
     display: block; 
    } 
    } 
    @media (min-width: 481px) and (max-width: 960px) { 
    .visible-md{ 
     display: block; 
    } 
    } 
    @media (min-width: 961px) { 
    .visible-lg{ 
     display: block; 
    } 
    } 
</style> 

We wszystkich dokumentach dodaj puste zakresy z tymi klasami. Nie pojawią się na stronie, jeśli zachowasz liniowość w linii.

<span id="media_test"> 
    <span class="visible-sm"></span> 
    <span class="visible-md"></span> 
    <span class="visible-lg"></span> 
</span> 

Dodaj to krótkie rozszerzenie jquery do pliku skryptu. Powoduje ustawienie nowej klasy w tagu treści, która jest zgodna z bieżącym zapytaniem o media.

(function ($) { 
    $.fn.media_size = function() { 
    //the default port size 
    var size = 'lg'; 
    //the sizes used in the css 
    var sizes = ['sm','md','lg']; 
    //loop over to find which is not hidden 
    for (var i = sizes.length - 1; i >= 0; i--) { 
    if($('#media_test .visible-'+sizes[i]).css("display").indexOf('none') == -1){ 
     size = sizes[i]; 
     break; 
    }; 
    }; 
    //add a new class to the body tag 
    $('body').removeClass(sizes.join(' ')).addClass(size); 
    } 
}(jQuery)); 
$(document).media_size(); 

Teraz masz automatyczną integrację z zapytaniami o media CSS Modernizr style.

Możesz napisać JavaScript (jQuery), które jest uwarunkowane na podstawie zapytań mediów:

<a href="#">how big is this viewport?</a> 

<script type="text/javascript"> 
    $('.sm a').click(function(e){ alert('Media queries say I\'m a small viewport');}); 
    $('.lg a').click(function(e){ alert('Media queries say I\'m a large viewport');}); 
</script> 
Powiązane problemy