17

CSS ファイルで概説したメディア クエリに基づいてアセットを動的に読み込むために、多数のライブラリ (自分のライブラリを含む) を使用してきました。例えば:

CSS で:

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

そして、アセットローダーを使用します。require.jsmodernizr.jsなど、またはwindow.matchMedia関連するaddListener()関数の使用:

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

それらを 2 回宣言するのは厄介でばかげています。私の知る限り、すべての JS ヘルパー ライブラリとアセット ローダーでは、JS/DOM からプログラムでメディア クエリを見つけるのではなく、メディア クエリを繰り返す必要があります。

そのため、 を介してプログラムで値にアクセスする機能を調査してきましたが、アクセスdocument.stylesheetsできるかどうかはわかりませんし、アクセス可能であることを示唆するドキュメントはほとんどないようです。

私が持っている最も遠いものは、スタイルシートオブジェクトを探索するために探してCSSMediaRule使用することです。console.dir(document.stylesheets)

しかし、CSS で使用される実際のメディア クエリ ルールへの参照は ( 内でdocument.stylesheets) 作成されません。メディア クエリの結果として適用されるクラスのみです。プログラムで見つけようとしているのは、次のとおりです。

「画面と (最大幅: 480px)」

JavaScript/DOM 経由でそのような CSS メディア クエリルールにアクセスする方法はありますか?

4

2 に答える 2

13

ルールを取得するには、クロス ブラウザ バリアントを使用します。

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

ルール リストで CSSMediaRule オブジェクトを検出するには (「CSSMediaRule」クラスは IE >= 9 でのみ使用できるため、IE <= 8 では機能しません):

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

現在の DOM からスタイルを取得するためのいくつかの関数 (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;
}

関数の使用例:

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

ここに JS Fiddle があります: https://jsfiddle.net/luisperezphd/hyentcqc/

于 2013-03-29T02:08:31.857 に答える
6

これは私がそれを行う方法です:

css で、さまざまなブレークポイントでコンテンツを公開または非表示にするクラスを作成します。とにかく便利なユーティリティです。これらは、たとえば Twitter Bootstrap で既に利用可能です。

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

すべてのドキュメントで、これらのクラスを使用して空のスパンを追加します。スパンをインラインのままにしておくと、ページに表示されません。

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

この短い jquery 拡張機能をスクリプト ファイルに追加します。これにより、現在のメディア クエリに一致する新しいクラスが body タグに設定されます。

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

これで、CSS メディア クエリの Modernizr スタイルとの自動統合が実現しました。

メディア クエリに基づいて条件付きの JavaScript (jquery) を記述できます。

<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>
于 2013-11-20T10:45:53.773 に答える