Изменение набора правил CSS из Javascript

Можно ли динамически вносить изменения в набор правил CSS (т. Е. Некоторые JS, которые могли бы изменить набор правил CSS, когда пользователь щелкает виджет)

Этот конкретный набор правил CSS применяется ко многим элементам (с помощью селектора классов) на странице, и я хочу изменить его, когда пользователь щелкает виджет, чтобы все элементы, имеющие класс, изменились.

9 ответов

Решение

Можно, но это довольно громоздко. Лучшая справка о том, как это сделать - следующая статья: Totally Pwn CSS с Javascript ( ссылка на веб-архив).

Мне удалось заставить его работать с Firefox и IE - Я не мог в Chrome, хотя кажется, что он поддерживает методы DOM. ricosrealm сообщает, что он работает и в Chrome.

Это современная версия, основанная на Totally Pwn CSS с Javascript. Это ES6, надеюсь, не против.

function getCSSRule(ruleName) {
    ruleName = ruleName.toLowerCase();
    var result = null;
    var find = Array.prototype.find;

    find.call(document.styleSheets, styleSheet => {
        result = find.call(styleSheet.cssRules, cssRule => {
            return cssRule instanceof CSSStyleRule 
                && cssRule.selectorText.toLowerCase() == ruleName;
        });
        return result != null;
    });
    return result;
}

Эта функция возвращает CSSStyleRule, который вы можете использовать следующим образом:

var header = getCSSRule('#header');
header.style.backgroundColor = 'red';

Также document.styleSheets перечисляет ссылки на объекты CSSStylesSheets. Другой способ получить доступ к определенному sytleSheet на странице - назначить идентификатор элементу style или link в HTML-коде и получить его в javascript с использованием document.getElementById('my-style'). Sheet. Это несколько полезных методов:

Основные браузеры и IE9 +: insertRule (), deleteRule (), removeProperty ().

Основные браузеры, Firefox? и IE9 +: setProperty ().

<stye id="my-style" ...
....
var myStyle = document.getElementById('my-style').sheet
myStyle.insertRule('#header { background: red; }', 0);

Также возможно динамически создавать новый элемент стиля для хранения динамически созданных стилей, я думаю, это должен быть способ избежать конфликтов.

Вы можете редактировать CLASS в таблицах стилей документа следующим образом

[...document.styleSheets[0].cssRules].find(x=> x.selectorText=='.box')
     .style.background= 'red';

function edit() {
  [...document.styleSheets[0].cssRules].find(x=> x.selectorText=='.box')
    .style.background= 'red';
}
.box {
  margin: 10px;
  padding: 10px;
  background: yellow;
}
<button onclick="edit()" >Click me</button>
<div class="box" >My box 1</div>
<div class="box" >My box 2</div>
<div class="box" >My box 3</div>

В зависимости от того, чего вы пытаетесь достичь, лучшим решением может быть изменение / добавление класса к содержащему элементу (тело будет делать!) И соответствующее определение классов.

.yourclass { color: black }
#wrapper.foo .yourclass { color: red }
#wrapper.bar .yourclass { color: blue }

тогда вы можете просто использовать

document.getElementById('wrapper').className='foo';

(или обертка выбранной вами js Framework для того же), чтобы изменить все с классом yourclass внутри чего бы то ни было wrapper Элемент

К сожалению, API для редактирования таблиц стилей с помощью JS не совместимы между браузерами. Утилита YUI Stylesheet Utility пытается сгладить эти различия, чтобы вы могли просто использовать это. Вы также можете посмотреть на исходный код, чтобы понять, как он работает, если вы не хотите использовать сам YUI.

Я попробовал код по ссылке из комментария @alex-gyoshev, но он не работает

  1. это не соответствует правилам CSS со шрифтами Google в Chrome
  2. он не проходит проверку безопасности FireFox

Так что я немного изменил, но удалил delete функциональность, так как она не была нужна для меня. Проверено в IE 11, FireFox 32, Chrome 37 и Opera 26.

function getCSSRule(ruleName) { // Return requested style object
  ruleName = ruleName.toLowerCase(); // Convert test string to lower case.
  var styleSheet;
  var i, ii;
  var cssRule = false; // Initialize cssRule. 
  var cssRules;
  if (document.styleSheets) { // If browser can play with stylesheets
    for (i = 0; i < document.styleSheets.length; i++) { // For each stylesheet
      styleSheet = document.styleSheets[i];
      if (!styleSheet.href) {
        if (styleSheet.cssRules) { // Browser uses cssRules?
          cssRules = styleSheet.cssRules; // Yes --Mozilla Style
        } else { // Browser usses rules?
          cssRules = styleSheet.rules; // Yes IE style. 
        } // End IE check.
        if (cssRules) {
          for (ii = 0; ii < cssRules.length; ii++) {
            cssRule = cssRules[ii];
            if (cssRule) { // If we found a rule...
              // console.log(cssRule);
              if (cssRule.selectorText) {
                console.log(cssRule.selectorText);
                if (cssRule.selectorText.toLowerCase() == ruleName) { //  match ruleName?
                  return cssRule; // return the style object.
                }
              }
            }
          }
        }
      }
    }
  }
  return false; // we found NOTHING!
}

Присвойте тегу стиля идентификатор, например <style id="ssID">если кто-то делает ваши стили для вас, скажите ЭТОМУ человеку присвоить тегу стиля идентификатор - таким образом вы сможете получить к нему прямой доступ, не задумываясь о том, каков его индекс

// create a hash table
var cssHash = {};

// loop through and populate the hash table
for (let i in (r = ss0.sheet.rules)) {

    // selectorText is the name of the rule - set the value equal to the rule
    cssHash[r[i].selectorText] = r[i];

}

теперь у вас есть хеш-таблица для всего в таблице стилей - обратите внимание, что некоторые значения будут неопределенными, но не для каких-либо вещей, которые вас волнуют

если у вас есть, например, класс с именем #menuItem и вы хотите изменить его цвет на черный, сделайте это

cssHash['#menuItem'].style.color = #000;

в этой строке будет установлен цвет стиля правила, индекс которого был найден в хеш-таблице (cssHash) с именем '#menuItem'

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

скажем, у вас есть четыре разных класса, и вы хотите установить для всех их цветов фона одно и то же значение, которое какой-то пользователь выбрал из входных данных.

тег выбора цвета <input id="bColor" type="color">и правила класса, которые вы хотите изменить, называются#menuItem.homeAddr span и #vacuum:hover

// create a listener for that color selector
bColor.addEventListener('input', function (e) {

  // loop through a split list of the four class names
  '#menuItem .homeAddr span #vacuum:hover'.split(' ').forEach(function (obj) {

    // use the hash table to look up the index of each name
    // and set the background color equal to the color input's value
    cssHash[obj].style.backgroundColor = bColor.value;

  });

}, false); // false added here for the sake of non-brevity

Чтобы проверить все таблицы стилей на наличие правила и установить его:

Ваше правило:

      .aaa: {
  background-color: green
}
      [...document.styleSheets].flatMap(s=>[...s.cssRules])
  .find(i=>i.selectorText=='.aaa').style.backgroundColor = 'red';

Обратите внимание, что стили css при доступе через javascript не содержат тире. В приведенном выше примереbackground-colorстановитсяbackgroundColor

В то время как setAttribute Это хорошо, есть стандартный способ сделать это в большинстве браузеров:

htmlElement.className = 'someClass';

Чтобы сделать это со многими элементами, вам понадобится кросс-браузерное решение:

function getElementsByClassName( className, context, tagName ) {
  context = context || document;
  if ( typeof context.getElementsByClassName === 'function' )
    return context.getElementsByClassName( className );

  if ( typeof context.getElementsByTagName !== 'function' )
    return [];

  var elements = typeof tagName === 'string' ? context.getElementsByTagName( tagName ) :
    context.getElementsByTagName('*'),
  ret = [];
  for ( var i = 0, il = elements.length; i < il; i++ )
    if ( elements[ i ].className.match( className ) )
      ret.push( elements[ i ] );

  return ret;
}

var elements = getElementsByClassName('someClass');

for ( var i = 0, il = elements.length; i < il; i++ )
  elements[ i ].className = 'newClass';

Вы можете заменить строку:

if ( elements[ i ].className.match( className ) )

С некоторыми регулярными выражениями, но вам придется экранировать специальные символы в этом случае.

Другие вопросы по тегам