Доступ к правилам запросов СМИ CSS через JavaScript/DOM - программирование
Подтвердить что ты не робот

Доступ к правилам запросов СМИ CSS через JavaScript/DOM

Я использовал несколько библиотек (включая мой собственный) для динамической загрузки активов на основе медиа-запросов, которые я описал в файлах CSS. Например:

В CSS:

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

И, используя загрузчик ресурсов; require.js, modernizr.js и т.д. или используя window.matchMedia и связанные с ним функции addListener():

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

Объявление их дважды неудобно/глупо, и, насколько я могу найти, все вспомогательные библиотеки JS и загрузчики ресурсов требуют повторения медиа-запросов, а не поиска их программно из JS/DOM.

Итак, я изучал возможность доступа к значениям программно с помощью document.stylesheets, но я не уверен, что они доступны, и кажется, что очень мало документации, чтобы предположить, что они есть.

Самое длинное, что у меня есть, ищет CSSMediaRule и используя console.dir(document.stylesheets) среди других, чтобы изучить объект таблицы стилей.

Но никаких ссылок не делается (в пределах document.stylesheets) на фактические правила медиа-запросов, используемые в CSS - только классы, которые будут применяться в результате медиа-запросов... Что я пытаюсь найти, программно, является:

"и (максимальная ширина: 480 пикселей)"

Есть ли способ доступа к таким запросам CSS через JavaScript/DOM?

4b9b3361

Ответ 1

Для получения правил используйте вариант кросс-браузера:

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

Для обнаружения объекта CSSMediaRule в списке правил используйте (не работает в IE <= 8, потому что класс "CSSMediaRule" доступен только в IE >= 9):

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 для него: https://jsfiddle.net/luisperezphd/hyentcqc/

Ответ 2

Вот как я это делаю:

В 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 в ваш файл script. Это устанавливает новый класс в теге 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>