Ustawianie reguł pseudoklas CSS z JavaScript

125

Szukam sposobu na zmianę reguł CSS dla selektorów pseudoklas (takich jak: link,: hover itp.) Z JavaScript.

A więc odpowiednik kodu CSS: a:hover { color: red }w JS.

Nie mogłem znaleźć odpowiedzi nigdzie indziej; jeśli ktoś wie, że jest to coś, czego przeglądarki nie obsługują, byłby to również pomocny wynik.

user39882
źródło

Odpowiedzi:

192

Nie możesz stylizować pseudoklasy tylko na konkretny element, w taki sam sposób, w jaki nie możesz mieć pseudoklasy w atrybucie inline style = "..." (ponieważ nie ma selektora).

Możesz to zrobić zmieniając arkusz stylów, na przykład dodając regułę:

#elid:hover { background: red; }

zakładając, że każdy element, na który chcesz wpłynąć, ma unikalny identyfikator, aby umożliwić jego wybranie.

Teoretycznie dokument, który chcesz, to http://www.w3.org/TR/DOM-Level-2-Style/Overview.html, co oznacza, że ​​możesz (biorąc pod uwagę istniejący osadzony lub połączony arkusz stylów) używając składni takiej jak:

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

IE wymaga oczywiście własnej składni:

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

Starsze i mniejsze przeglądarki prawdopodobnie nie obsługują żadnej składni. Dynamiczne manipulowanie arkuszami stylów jest rzadko wykonywane, ponieważ jest to dość denerwujące, rzadko potrzebne i kłopotliwe historycznie.

bobince
źródło
32
Dlaczego nie wybrano tego jako odpowiedzi?
SZH
2
Firefox: „Błąd: operacja jest niepewna”.
8128
@fluteflute operacja jest uważana za niebezpieczną, jeśli próbujesz manipulować plikiem CSS z innej domeny (myślę, że jest to rodzaj polityki tego samego pochodzenia). Wstyd! Prosta funkcja do sprawdzenia jest zgodna z polityką tego samego pochodzenia: 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
Manipulowanie arkuszem stylów tylko po to, aby zastosować style do określonego elementu, nie jest zalecane, ponieważ powoduje to, że przeglądarka zmienia zawartość całego dokumentu za każdym razem, gdy arkusz stylów jest zmieniany. stubbornella.org/content/2009/03/27/…
Johannes Ewald
29

Stworzyłem do tego małą bibliotekę, ponieważ uważam, że istnieją ważne przypadki użycia do manipulowania arkuszami stylów w JS. Powody są:

  • Ustawianie stylów, które muszą być obliczane lub pobierane - na przykład ustawienie preferowanego rozmiaru czcionki użytkownika z pliku cookie.
  • Ustawianie stylów behawioralnych (nie estetycznych), szczególnie dla programistów widżetów / wtyczek UI. Karty, karuzele itp. Często wymagają podstawowego kodu CSS po prostu do działania - nie powinny wymagać arkusza stylów dla funkcji podstawowej.
  • Lepsze niż style wbudowane, ponieważ reguły CSS dotyczą wszystkich obecnych i przyszłych elementów i nie zaśmiecają kodu HTML podczas przeglądania w Firebug / Developer Tools.
David Tang
źródło
17

Funkcja radząca sobie z różnymi przeglądarkami:

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);
    }
  }
};

źródło
7

Po prostu umieść css w ciągu szablonu.

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

Następnie utwórz element stylu i umieść ciąg w znaczniku stylu i dołącz go do dokumentu.

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

Specyfika zajmie się resztą. Następnie możesz dynamicznie usuwać i dodawać tagi stylu. Jest to prosta alternatywa dla bibliotek i mieszania się z tablicą arkuszy stylów w DOM. Miłego kodowania!

plątanina witryn
źródło
insertAdjacentElementwymaga 2 argumentów w głównych przeglądarkach (Chrome, Firefox, Edge), z których pierwszy określa pozycję względem elementu referencyjnego ( patrz tutaj ). Czy to ostatnia zmiana? (Dodano „przed końcem” do odpowiedzi).
collapsar,
6

Moja sztuczka polega na użyciu selektora atrybutów. Atrybuty są łatwiejsze do skonfigurowania za pomocą 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)"> ...  
Sergio Abreu
źródło
4
To rozwiązanie wykorzystuje jQuery - wprowadzenie zależności od rozmiaru jQuery dla czegoś tak prostego, jak to, gdy pytający pytany o czysty Javascript, jest złe.
Tom Ashworth
Chociaż praktycznie wszystkie strony internetowe używają obecnie jquery, zmodyfikuję go tak, aby używał czystego javascript.
Sergio Abreu
1
I dokładnie w jaki sposób ta metoda zmienia atrybuty CSS klasy .class [specjalne]: po pseudo elemencie, na przykład kolor tła lub cokolwiek innego?
andreszs
5

Jest inna alternatywa. Zamiast bezpośrednio manipulować pseudoklasami, utwórz prawdziwe klasy, które modelują te same rzeczy, takie jak klasa „najechana” lub „odwiedzona”. Styl zajęć za pomocą zwykłego „.” składni, a następnie możesz użyć JavaScript, aby dodać lub usunąć klasy z elementu, gdy uruchomi się odpowiednie zdarzenie.

Brandon Ramirez
źródło
2
To nie działa dla: przed i: po pseudoklasach.
jbyrd
Nie dotyczy to zmiany obrazu tła z wartością pobraną przez AJAX.
andreszs
1
@jbyrd, :before& :aftersą pseudoelementami, a nie klasami.
Roy Ling
@royling - tak, dzięki za korektę! Nie mogę edytować mojego komentarza.
jbyrd
4

Zamiast bezpośrednio ustawiać reguły pseudoklas za pomocą javascript, możesz ustawić reguły inaczej w różnych plikach CSS, a następnie użyć Javascript do wyłączenia jednego arkusza stylów i włączenia innego. Metoda jest opisana w A List Apart (patrz więcej szczegółów).

Skonfiguruj pliki CSS jako,

<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 -->

A następnie przełączaj się między nimi za pomocą 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;
     }
   }
}
Wymuskany
źródło
Co się stanie, jeśli musisz dynamicznie zmienić klasę na wartość pobraną przez żądanie AJAX? Nie możesz teraz utworzyć pliku CSS ...
andreszs
2

Jak już wspomniano, nie jest to obsługiwane przez przeglądarki.

Jeśli nie wymyślasz stylów dynamicznie (tj. Wyciągasz je z bazy danych lub czegoś w tym rodzaju), powinieneś być w stanie obejść ten problem, dodając klasę do treści strony.

CSS wyglądałoby mniej więcej tak:

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

A javascript do zmiany tego będzie wyglądał następująco:

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

document.body.className += " theme1";  
Nathaniel Reinhart
źródło
Z ciekawości element.classList.addnie jest dobrze obsługiwany? Ciągle widzę, jak ludzie robią element.className +=.
Joel Cornett
2
classList to nowsze cechą i nie wygląda jakby miał dobre wsparcie do niedawna (patrz caniuse.com/classlist )
Nathaniel Reinhart
-1

W jquery możesz łatwo ustawić pseudoklasy hover.

$("p").hover(function(){
$(this).css("background-color", "yellow");
}, function(){
$(this).css("background-color", "pink");
});
vasanth
źródło
-1

tutaj jest rozwiązanie zawierające dwie funkcje: addCSSclass dodaje nową klasę css do dokumentu, a toggleClass włącza ją

Przykład pokazuje dodanie niestandardowego paska przewijania do elementu 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>

kofifus
źródło
-2

Jeśli używasz REACT, istnieje coś, co nazywa się radem . Jest to tak przydatne tutaj:

  • Dodaj moduły obsługi do właściwości, jeśli określono style interaktywne, np. OnMouseEnter for: hover, zawijając istniejące moduły obsługi, jeśli to konieczne

  • Jeśli którykolwiek z programów obsługi jest wyzwalany, np. Przez najechanie kursorem, Radium wywołuje setState, aby zaktualizować pole specyficzne dla Radium w obiekcie stanu komponentów

  • Przy ponownym renderowaniu rozwiąż wszystkie stosowane style interaktywne, np. Najechanie kursorem, wyszukując klucz elementu lub odwołanie w stanie specyficznym dla Radium

Abdennour TOUMI
źródło