Я ищу способ изменить правила CSS для селекторов псевдоклассов (таких как: link,: hover и т. д.) Из JavaScript.
Итак, аналог кода CSS: a:hover { color: red } в JS.
Я нигде не мог найти ответа; если кто-то знает, что это то, что браузеры не поддерживают, это тоже будет полезным результатом.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы не можете стилизовать псевдокласс только для определенного элемента, точно так же, как вы не можете создать псевдокласс во встроенном атрибуте 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';
Старые и второстепенные браузеры, скорее всего, не поддерживают ни один из синтаксисов. Динамическая перестановка таблиц стилей выполняется редко, потому что это довольно раздражает, когда нужно делать правильно, редко требуется и исторически проблематично.
Более конкретные ссылочные URL: - <w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet> - <developer.mozilla.org/en/DOM/CSSStyleSheet/insertRule> - <developer.apple.com/library/safari/#documentation/…>
Firefox: «Ошибка: операция небезопасна».
@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; }
Манипулировать таблицей стилей только для применения стилей к определенному элементу не рекомендуется, поскольку это заставляет браузер перекомпоновывать весь документ при каждом изменении таблицы стилей. stubbornella.org/content/2009/03/27/…
Единственная проблема с этой опцией - наличие массива элементов таблиц стилей. Обязательно настройте цикл for для поиска нужного вам, как мне пришлось сделать.
Как уже говорилось, это не поддерживается браузерами.
Если вы не придумываете стили динамически (т. Е. Извлекаете их из базы данных или чего-то еще), вы сможете обойти это, добавив класс в тело страницы.
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 +=.
classList - более новая функция, и не похоже, что до недавнего времени у нее была хорошая поддержка (см. caniuse.com/classlist)
Функция, справляющаяся с кроссбраузерностью:
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);
}
}
};
Вместо того, чтобы напрямую устанавливать правила псевдокласса с помощью javascript, вы можете установить правила по-разному в разных файлах CSS, а затем использовать Javascript для отключения одной таблицы стилей и включения другой. Метод описан в Список отдельно (см. Подробнее).
Настройте файлы 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 не ...
Переключение таблиц стилей - способ сделать это. Вот библиотека для динамического создания таблиц стилей, поэтому вы можете устанавливать стили на лету:
http://www.4pmp.com/2009/11/dynamic-css-pseudo-class-styles-with-jquery/
Я собрал небольшая библиотека для этого, так как считаю, что существуют допустимые варианты использования для управления таблицами стилей в JS. Причины:
Есть еще одна альтернатива. Вместо того, чтобы напрямую манипулировать псевдоклассами, создайте реальные классы, моделирующие одни и те же вещи, такие как класс «зависания» или «посещаемый» класс. Стилизуйте классы обычным "." синтаксис, а затем вы можете использовать JavaScript для добавления или удаления классов из элемента при возникновении соответствующего события.
Это не работает для псевдоклассов: before и: after.
И это не применимо к изменению фонового изображения со значением, полученным через AJAX.
@jbyrd, :before и :after - это псевдоэлементы, а не классы.
@royling - да, спасибо за исправление! Не могу отредактировать свой комментарий.
Моя уловка заключается в использовании селектора атрибутов. Атрибуты легче настроить с помощью 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)"> ...
Это решение использует jQuery - введение зависимости размера jQuery для чего-то столь же простого, как это, когда спрашивающий просил чистый Javascript, плохо.
Хотя практически все веб-сайты в настоящее время ИСПОЛЬЗУЮТ jquery, я изменю его, чтобы использовать чистый javascript.
И как именно этот метод может изменить атрибуты CSS псевдоэлемента .class [special]: after, например, цвет фона или что-то еще?
В jquery вы можете легко установить псевдоклассы при наведении курсора.
$("p").hover(function(){
$(this).css("background-color", "yellow");
}, function(){
$(this).css("background-color", "pink");
});
Если вы используете REACT, есть что-то под названием радий. Здесь так полезно:
Add handlers to props if interactive styles are specified, e.g. onMouseEnter for :hover, wrapping existing handlers if necessary
If any of the handlers are triggered, e.g. by hovering, Radium calls setState to update a Radium-specific field on the components state object
On re-render, resolve any interactive styles that apply, e.g. :hover, by looking up the element's key or ref in the Radium-specific state
вот решение, включающее две функции: addCSSclass добавляет новый класс css в документ, а toggleClass включает его
В примере показано добавление настраиваемой полосы прокрутки в div.
// 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>Просто поместите 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), первый из которых устанавливает позицию относительно ссылочного элемента (глянь сюда). Это недавнее изменение? (К ответу добавлено слово beforeend).
Мне не нравится это решение. Ваш CSS не будет кэширован.
Один из вариантов, который вы могли бы рассмотреть, - это использование переменных CSS. Идея состоит в том, что вы устанавливаете свойство, которое хотите изменить, на переменную CSS. Затем в своем JS измените значение этой переменной.
См. Пример ниже
function changeColor(newColor) {
document.documentElement.style.setProperty("--anchor-hover-color", newColor);
// ^^^^^^^^^^^-- select the root
}:root {
--anchor-hover-color: red;
}
a:hover {
color: var(--anchor-hover-color);
}<a href = "#">Hover over me</a>
<button onclick = "changeColor('lime')">Change to lime</button>
<button onclick = "changeColor('red')">Change to red</button>
Почему это не было выбрано в качестве ответа?