2013-03-29 3 views
14

Ich habe eine Reihe von Bibliotheken (einschließlich meiner eigenen) verwendet, um Assets basierend auf Medienabfragen, die ich in CSS-Dateien beschrieben habe, dynamisch zu laden. Zum Beispiel:Zugriff auf CSS-Medienabfrageregeln über JavaScript/DOM

In CSS:

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

Und mit einem Asset-Loader; require.js, modernizr.js usw. oder mit window.matchMedia und addListener() Funktionen zugeordnet:

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

sie zweimal Deklarieren ist umständlich/albern und so weit wie ich finden kann, werden alle JS Helfer Bibliotheken und Asset Lader benötigen Sie die Medien-Anfragen zu wiederholen, anstatt Lokalisieren sie programmgesteuert von JS/DOM.

Also habe ich die Möglichkeit untersucht, die Werte programmgesteuert über document.stylesheets zuzugreifen, aber ich bin mir nicht sicher, ob sie zugänglich sind und es scheint sehr wenig Dokumentation zu suggerieren, dass sie sind.

Am weitesten entfernt bin ich auf der Suche nach CSSMediaRule und unter Verwendung console.dir(document.stylesheets) unter anderem das Stylesheet-Objekt zu erkunden.

Es werden jedoch keine Referenzen (innerhalb document.stylesheets) zu den tatsächlichen Medienabfrageregeln in CSS verwendet - nur die Klassen, die als Ergebnis der Medienabfragen angewendet werden ... Was ich programmatisch zu finden versuche, ist :

"-Bildschirm und (max-width: 480px)"

gibt es eine Möglichkeit, solche CSS-Medienabfrage Regeln über JavaScript/DOM zugreifen?

+2

Hoppla, falschen Link, [hier ist der Artikel, den ich bei coderwall suchen] (https: // coderwall. com/p/_ldtkg) – steveax

+2

Gute Frage. Für meine Zwecke habe ich immer überprüft, ob bestimmte Elemente sichtbar waren oder nicht, da meine JavaScript-Interaktion für diese Elemente gelten würde. Es sollte jedoch eine bessere, allgemeinere Lösung geben. – Brad

+0

Hey, überprüfen Sie es. Es kann eine Lösung sein. https://github.com/natansmith/adapt/blob/master/assets/js/adapt.js –

Antwort

11

Für get Regeln verwenden Cross-Browser-Variante:

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

Für CSSMediaRule Objekt in Regelliste Verwendung erkennt (nicht im IE funktioniert < = 8, weil "CSSMediaRule" Klasse nur im IE> = 9):

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

Einige Funktionen für get Arten von aktuellem DOM (nicht funktioniert in 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; 
} 

Funktionen Anwendungsbeispiel:

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

ist hier ein JS Fiddle für sie: https://jsfiddle.net/luisperezphd/hyentcqc/

+0

Diese Funktion sucht nach der genauen Übereinstimmung, z. "screen und (max ..." und nicht für eine teilweise Übereinstimmung zB "screen", richtig? Ich versuche, Klassen für den Bildschirm zu klonen, zu löschen und neu zu erstellen (egal welche Dimensionen) "all" (da kann ich 't nur die Medien für bestehende Regeln ändern) Denkst du, dass dies für das verwendet werden könnte? danke. – sergio

5

Dies ist, wie ich es tun:

in CSS erstellen Klassen Inhalt an verschiedenen Haltepunkten zu belichten oder ausblenden. Dies ist ein nützliches Dienstprogramm. Diese sind zum Beispiel bereits in Twitter Bootstrap verfügbar.

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

Fügen Sie in allen Ihren Dokumenten leere Bereiche mit diesen Klassen hinzu. Sie werden nicht auf der Seite angezeigt, wenn Sie die Spannen inline halten.

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

Fügen Sie diese kurze jquery-Erweiterung Ihrer Skriptdatei hinzu. Dies legt eine neue Klasse im body-Tag fest, die der aktuellen Medienabfrage entspricht.

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

Jetzt haben Sie eine automatische Integration mit Ihrem CSS Media Abfragen Modernizr Stil.

Sie Javascript (jQuery) schreiben, die auf auf der Grundlage Ihrer Medien-Anfragen bedingt ist:

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