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

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

Итак, аналог кода CSS: a:hover { color: red } в JS.

Я нигде не мог найти ответа; если кто-то знает, что это то, что браузеры не поддерживают, это тоже будет полезным результатом.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
133
0
102 088
13

Ответы 13

Вы не можете стилизовать псевдокласс только для определенного элемента, точно так же, как вы не можете создать псевдокласс во встроенном атрибуте 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';

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

Почему это не было выбрано в качестве ответа?

SZH 25.03.2011 02:26

Firefox: «Ошибка: операция небезопасна».

8128 14.07.2012 20:14

@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 07.11.2012 18:43

Манипулировать таблицей стилей только для применения стилей к определенному элементу не рекомендуется, поскольку это заставляет браузер перекомпоновывать весь документ при каждом изменении таблицы стилей. stubbornella.org/content/2009/03/27/…

Johannes Ewald 23.08.2013 14:07

Единственная проблема с этой опцией - наличие массива элементов таблиц стилей. Обязательно настройте цикл for для поиска нужного вам, как мне пришлось сделать.

Jester 15.06.2020 20:35

Как уже говорилось, это не поддерживается браузерами.

Если вы не придумываете стили динамически (т. Е. Извлекаете их из базы данных или чего-то еще), вы сможете обойти это, добавив класс в тело страницы.

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 +=.

Joel Cornett 13.03.2014 11:41

classList - более новая функция, и не похоже, что до недавнего времени у нее была хорошая поддержка (см. caniuse.com/classlist)

Nathaniel Reinhart 11.04.2014 22:26

Функция, справляющаяся с кроссбраузерностью:

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 не ...

andreszs 21.12.2014 04:51

Переключение таблиц стилей - способ сделать это. Вот библиотека для динамического создания таблиц стилей, поэтому вы можете устанавливать стили на лету:

http://www.4pmp.com/2009/11/dynamic-css-pseudo-class-styles-with-jquery/

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

  • Установка стилей, которые должны быть вычислены или получены - например, установка предпочтительного размера шрифта пользователя из файла cookie.
  • Установка поведенческих (не эстетических) стилей, особенно для разработчиков UI-виджетов / плагинов. Вкладки, карусели и т. д. Часто требуют некоторого базового CSS просто для работы - не следует потребность таблица стилей для основной функции.
  • Лучше, чем встроенные стили, поскольку правила CSS применяются ко всем текущим и будущим элементам и не загромождают HTML при просмотре в Firebug / Developer Tools.

Есть еще одна альтернатива. Вместо того, чтобы напрямую манипулировать псевдоклассами, создайте реальные классы, моделирующие одни и те же вещи, такие как класс «зависания» или «посещаемый» класс. Стилизуйте классы обычным "." синтаксис, а затем вы можете использовать JavaScript для добавления или удаления классов из элемента при возникновении соответствующего события.

Это не работает для псевдоклассов: before и: after.

jbyrd 01.11.2014 02:04

И это не применимо к изменению фонового изображения со значением, полученным через AJAX.

andreszs 21.12.2014 04:52

@jbyrd, :before и :after - это псевдоэлементы, а не классы.

Roy Ling 08.10.2015 09:59

@royling - да, спасибо за исправление! Не могу отредактировать свой комментарий.

jbyrd 09.10.2015 02:07

Моя уловка заключается в использовании селектора атрибутов. Атрибуты легче настроить с помощью 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, плохо.

Tom Ashworth 20.03.2013 18:55

Хотя практически все веб-сайты в настоящее время ИСПОЛЬЗУЮТ jquery, я изменю его, чтобы использовать чистый javascript.

Sergio Abreu 02.05.2013 05:48

И как именно этот метод может изменить атрибуты CSS псевдоэлемента .class [special]: after, например, цвет фона или что-то еще?

andreszs 21.12.2014 05:01

В 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).
collapsar 16.07.2018 17:24

Мне не нравится это решение. Ваш CSS не будет кэширован.

StackSlave 06.11.2020 05:00

Один из вариантов, который вы могли бы рассмотреть, - это использование переменных 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>

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