Встановлення правил псевдокласу CSS з JavaScript


125

Я шукаю спосіб зміни правил CSS для селекторів псевдокласів (таких як: link,: наведення курсора тощо) з JavaScript.

Отже, аналог коду CSS: a:hover { color: red }у JS.

Я не міг знайти відповіді ніде; якщо хтось знає, що це те, що браузери не підтримують, це також буде корисним результатом.

Відповіді:


192

Ви не можете стилізувати псевдоклас лише на певному елементі так само, як у атрибута inline style = "..." (як немає селектора).

Це можна зробити, змінивши таблицю стилів, наприклад, додавши правило:

#elid:hover { background: red; }

припускаючи, що кожен елемент, на який потрібно вплинути, має унікальний ідентифікатор, який дозволяє його вибирати.

Теоретично потрібний документ є http://www.w3.org/TR/DOM-Level-2-Style/Overview.html, що означає, що ви можете (з огляду на наявний вбудований або пов'язаний таблицю стилів), використовуючи синтаксис, як:

document.styleSheets[0].insertRule('#elid:hover { background-color: red; }', 0);
document.styleSheets[0].cssRules[0].style.backgroundColor= 'red';

IE, звичайно, вимагає власного синтаксису:

document.styleSheets[0].addRule('#elid:hover', 'background-color: red', 0);
document.styleSheets[0].rules[0].style.backgroundColor= 'red';

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


32
Чому це не було обрано як відповідь?
СЖ


2
Firefox: "Помилка: операція небезпечна."
8128

@fluteflute ця операція вважається небезпечною, якщо ви намагаєтесь маніпулювати файлом CSS з іншого домену (я думаю, це тип політики з аналогічним походженням). Сором! Проста функція перевірки відповідності політиці одного походження: function sameOrigin(url) { var loc = window.location, a = document.createElement('a'); a.href = url; return a.hostname === loc.hostname && a.port === loc.port && a.protocol === loc.protocol; }
WickyNilliams

3
Маніпулювання таблицею стилів лише для застосування стилів до певного елемента не рекомендується, оскільки це змушує браузер поповнювати весь документ щоразу, коли таблицю стилів змінюється. stubbornella.org/content/2009/03/27/…
Йоханнес Евальд

29

Я зібрав для цього невелику бібліотеку, оскільки я думаю, що в JS є справжні випадки використання для маніпулювання таблицями стилів. Причини:

  • Налаштування стилів, які необхідно обчислити або отримати, наприклад, встановити бажаний розмір шрифту у файлі cookie.
  • Налаштування поведінкових (не естетичних) стилів, особливо для розробників віджетів / плагінів інтерфейсу користувача. Вкладки, каруселі тощо часто потребують простого функціонування базового CSS - не слід вимагати таблиці стилів для основної функції.
  • Краще, ніж стилі вбудовування, оскільки правила CSS застосовуються до всіх поточних та майбутніх елементів, і не захаращуйте HTML під час перегляду в Firebug / Інструментах для розробників.

17

Функція, щоб впоратися з крос-браузерними речами:

addCssRule = function(/* string */ selector, /* string */ rule) {
  if (document.styleSheets) {
    if (!document.styleSheets.length) {
      var head = document.getElementsByTagName('head')[0];
      head.appendChild(bc.createEl('style'));
    }

    var i = document.styleSheets.length-1;
    var ss = document.styleSheets[i];

    var l=0;
    if (ss.cssRules) {
      l = ss.cssRules.length;
    } else if (ss.rules) {
      // IE
      l = ss.rules.length;
    }

    if (ss.insertRule) {
      ss.insertRule(selector + ' {' + rule + '}', l);
    } else if (ss.addRule) {
      // IE
      ss.addRule(selector, rule, l);
    }
  }
};

7

Просто помістіть css у рядок шаблону.

const cssTemplateString = `.foo:[psuedoSelector]{prop: value}`;

Потім створіть елемент стилю і помістіть рядок у тег стилю та приєднайте його до документа.

const styleTag = document.createElement("style");
styleTag.innerHTML = cssTemplateString;
document.head.insertAdjacentElement('beforeend', styleTag);

Специфіка подбає про відпочинок. Потім ви можете динамічно видаляти та додавати теги стилів. Це проста альтернатива бібліотекам і возитися з масивом таблиць стилів у DOM. Щасливе кодування!


insertAdjacentElementпотрібні 2 аргументи в основних браузерах (Chrome, Firefox, Edge), перший з яких встановлює положення відносно еталонного елемента ( див. тут ). Це нещодавня зміна? (До відповіді додано "попередньо").
колапс

6

Моя хитрість полягає у використанні селектора атрибутів. Атрибути простіше налаштувати за допомогою JavaScript.

css

.class{ /*normal css... */}
.class[special]:after{ content: 'what you want'}

javascript

  function setSpecial(id){ document.getElementById(id).setAttribute('special', '1'); }

html

<element id='x' onclick="setSpecial(this.id)"> ...  

4
Це рішення використовує jQuery - введення залежності розміру jQuery для чогось такого простого, як це, коли запитуючий запитував чистий Javascript, погано.
Том Ешворт

Хоча в практичному відношенні всі веб-сайти в даний час застосовують jquery, я зміню його для використання чистого JavaScript.
Серхіо Абреу

1
І як саме цей метод отримує можливість змінити атрибути CSS .class [special]: після псевдоелемента, наприклад, кольору фону або чого-небудь іншого?
andreszs

5

Є ще одна альтернатива. Замість того, щоб безпосередньо маніпулювати псевдокласами, створюйте реальні класи, які моделюють ті самі речі, як клас "наведення" або "відвідуваний" клас. Класируйте класи звичайним "". синтаксис, а потім ви можете використовувати JavaScript для додавання або видалення класів з елемента, коли спрацьовує відповідна подія.


2
Це не працює для: до та після псевдокласів.
jbyrd

І це не застосовується для зміни фонового зображення зі значенням, отриманим через AJAX.
andreszs

1
@jbyrd, :before& :afterє псевдоелементами, а не класами.
Рой Лінг

@royling - так, дякую за виправлення! Не можу редагувати мій коментар.
jbyrd

4

Замість того, щоб безпосередньо встановлювати правила псевдокласу за допомогою javascript, ви можете встановити правила по-різному в різних файлах CSS, а потім використовувати Javascript для вимкнення однієї таблиці стилів і включення іншого. Метод описаний у A List Apart (детальніше).

Налаштуйте файли CSS як:

<link rel="stylesheet" href="always_on.css">
<link rel="stylesheet" title="usual" href="preferred.css"> <!-- on by default -->
<link rel="alternate stylesheet" title="strange" href="alternate.css"> <!-- off by default -->

А потім перемикайтеся між ними за допомогою javascript:

function setActiveStyleSheet(title) {
   var i, a, main;
   for(i=0; (a = document.getElementsByTagName("link")<i>); i++) {
     if(a.getAttribute("rel").indexOf("style") != -1
        && a.getAttribute("title")) {
       a.disabled = true;
       if(a.getAttribute("title") == title) a.disabled = false;
     }
   }
}

Що робити, якщо вам потрібно динамічно змінити клас на значення, отримане за запитом AJAX? Зараз ви не можете створити файл CSS ...
andreszs

2

Як уже було сказано, браузери не підтримують це.

Якщо ви не підходите до стилів динамічно (тобто витягаючи їх із бази даних чи чогось іншого), вам слід мати змогу обійтися цим шляхом додавання класу до тіла сторінки.

CSS виглядатиме приблизно так:

a:hover { background: red; }
.theme1 a:hover { background: blue; }

І javascript для зміни цього буде чимось на кшталт:

// Look up some good add/remove className code if you want to do this
// This is really simplified

document.body.className += " theme1";  

З цікавості, це element.classList.addне добре підтримується? Я постійно бачу, як люди роблять element.className +=.
Джоель Корнетт

2
classList - це новіша функція і не схоже, що вона мала добру підтримку ще зовсім недавно (див. caniuse.com/classlist )
Nathaniel Reinhart


-1

У jquery ви можете легко встановити курси наведення псевдо.

$("p").hover(function(){
$(this).css("background-color", "yellow");
}, function(){
$(this).css("background-color", "pink");
});

-1

ось рішення, що включає дві функції: addCSSclass додає в документ новий клас css, а toggleClass вмикає його

На прикладі показано додавання спеціальної смуги прокрутки до діва

// If newState is provided add/remove theClass accordingly, otherwise toggle theClass
function toggleClass(elem, theClass, newState) {
  var matchRegExp = new RegExp('(?:^|\\s)' + theClass + '(?!\\S)', 'g');
  var add = (arguments.length > 2 ? newState : (elem.className.match(matchRegExp) === null));

  elem.className = elem.className.replace(matchRegExp, ''); // clear all
  if (add) elem.className += ' ' + theClass;
}

function addCSSclass(rules) {
  var style = document.createElement("style");
  style.appendChild(document.createTextNode("")); // WebKit hack :(
  document.head.appendChild(style);
  var sheet = style.sheet;

  rules.forEach((rule, index) => {
    try {
      if ("insertRule" in sheet) {
        sheet.insertRule(rule.selector + "{" + rule.rule + "}", index);
      } else if ("addRule" in sheet) {
        sheet.addRule(rule.selector, rule.rule, index);
      }
    } catch (e) {
      // firefox can break here          
    }
    
  })
}

let div = document.getElementById('mydiv');
addCSSclass([{
    selector: '.narrowScrollbar::-webkit-scrollbar',
    rule: 'width: 5px'
  },
  {
    selector: '.narrowScrollbar::-webkit-scrollbar-thumb',
    rule: 'background-color:#808080;border-radius:100px'
  }
]);
toggleClass(div, 'narrowScrollbar', true);
<div id="mydiv" style="height:300px;width:300px;border:solid;overflow-y:scroll">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a eros metus. Nunc dui felis, accumsan nec aliquam quis, fringilla quis tellus. Nulla cursus mauris nibh, at faucibus justo tincidunt eget. Sed sodales eget erat consectetur consectetur. Vivamus
  a diam volutpat, ullamcorper justo eu, dignissim ante. Aenean turpis tortor, fringilla quis efficitur eleifend, iaculis id quam. Quisque non turpis in lacus finibus auctor. Morbi ullamcorper felis ut nulla venenatis fringilla. Praesent imperdiet velit
  nec sodales sodales. Etiam eget dui sollicitudin, tempus tortor non, porta nibh. Quisque eu efficitur velit. Nulla facilisi. Sed varius a erat ac volutpat. Sed accumsan maximus feugiat. Mauris id malesuada dui. Lorem ipsum dolor sit amet, consectetur
  adipiscing elit. Sed a eros metus. Nunc dui felis, accumsan nec aliquam quis, fringilla quis tellus. Nulla cursus mauris nibh, at faucibus justo tincidunt eget. Sed sodales eget erat consectetur consectetur. Vivamus a diam volutpat, ullamcorper justo
  eu, dignissim ante. Aenean turpis tortor, fringilla quis efficitur eleifend, iaculis id quam. Quisque non turpis in lacus finibus auctor. Morbi ullamcorper felis ut nulla venenatis fringilla. Praesent imperdiet velit nec sodales sodales. Etiam eget
  dui sollicitudin, tempus tortor non, porta nibh. Quisque eu efficitur velit. Nulla facilisi. Sed varius a erat ac volutpat. Sed accumsan maximus feugiat. Mauris id malesuada dui.
</div>


-2

Якщо ви використовуєте REACT, є щось, що називається радієм . Тут так корисно:

  • Додайте обробників до реквізиту, якщо вказані інтерактивні стилі, наприклад, onMouseEnter для: наведіть курсор, при необхідності загорнувши існуючі обробники

  • Якщо будь-який з обробників спрацьовує, наприклад, наведення курсору, Radium викликає setState для оновлення специфічного для Radium поля на об'єкті стану компонентів

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.