Impostazione delle regole della pseudo-classe CSS da JavaScript


125

Sto cercando un modo per cambiare le regole CSS per i selettori di pseudo-classe (come: link,: hover, ecc.) Da JavaScript.

Quindi un analogo del codice CSS: a:hover { color: red }in JS.

Non sono riuscito a trovare la risposta da nessun'altra parte; se qualcuno sa che questo è qualcosa che i browser non supportano, anche questo sarebbe un risultato utile.

Risposte:


192

Non puoi modellare una pseudo-classe su un particolare elemento da solo, allo stesso modo in cui non puoi avere una pseudo-classe in un attributo inline style = "..." (in quanto non esiste un selettore).

Puoi farlo modificando il foglio di stile, ad esempio aggiungendo la regola:

#elid:hover { background: red; }

supponendo che ogni elemento che si desidera influenzare abbia un ID univoco per consentirne la selezione.

In teoria il documento che vuoi è http://www.w3.org/TR/DOM-Level-2-Style/Overview.html, il che significa che puoi (dato un foglio di stile incorporato o collegato preesistente) usando una sintassi come:

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

IE, ovviamente, richiede una propria sintassi:

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

È probabile che i browser meno recenti e meno supportino nessuna delle due sintassi. La manipolazione dinamica dei fogli di stile viene eseguita raramente perché è abbastanza fastidioso ottenere il giusto, raramente necessario e storicamente problematico.


32
Perché questo non è stato scelto come risposta?
SZH,


2
Firefox: "Errore: l'operazione non è sicura."
8128

@fluteflute l'operazione è considerata non sicura se si sta tentando di manipolare un file CSS da un dominio diverso (immagino che sia un tipo di cosa politica della stessa origine). Vergogna! La semplice funzione di controllo è conforme alla politica della stessa origine: 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
Non è consigliabile manipolare il foglio di stile solo per applicare gli stili a un elemento specifico poiché fa sì che il browser ridisegni l'intero documento ogni volta che il foglio di stile viene modificato. stubbornella.org/content/2009/03/27/…
Johannes Ewald,

29

Ho creato una piccola libreria per questo poiché penso che ci siano casi d'uso validi per manipolare i fogli di stile in JS. I motivi sono:

  • Impostazione di stili che devono essere calcolati o recuperati, ad esempio l'impostazione della dimensione del carattere preferita dell'utente da un cookie.
  • Impostazione di stili comportamentali (non estetici), in particolare per gli sviluppatori di widget / plugin dell'interfaccia utente. Schede, caroselli, ecc., Richiedono spesso alcuni CSS di base semplicemente per funzionare - non dovrebbero richiedere un foglio di stile per la funzione principale.
  • Meglio degli stili incorporati poiché le regole CSS si applicano a tutti gli elementi attuali e futuri e non ingombrano l'HTML durante la visualizzazione in Firebug / Strumenti di sviluppo.

17

Una funzione per far fronte alle cose cross-browser:

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

Basta inserire il CSS in una stringa di modello.

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

Quindi crea un elemento di stile e posiziona la stringa nel tag di stile e collegala al documento.

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

La specificità si occuperà del resto. Quindi è possibile rimuovere e aggiungere tag di stile in modo dinamico. Questa è una semplice alternativa alle librerie e alla messaggistica con l'array di fogli di stile nel DOM. Buona programmazione!


insertAdjacentElementrichiede 2 argomenti nei principali browser (Chrome, Firefox, Edge), il primo dei quali stabilisce la posizione relativa all'elemento di riferimento ( vedi qui ). È un cambiamento recente? (Aggiunto 'beforeend' alla risposta).
collapsar

6

Il mio trucco sta usando un selettore di attributi. Gli attributi sono più facili da impostare tramite 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
Questa soluzione utilizza jQuery: introdurre una dipendenza delle dimensioni di jQuery per qualcosa di semplice come questo, quando l'interrogante ha chiesto Javascript puro, non è corretto.
Tom Ashworth,

Anche se praticamente tutti i siti web oggigiorno USANO jquery, lo modificherò per usare javascript puro.
Sergio Abreu,

1
Ed esattamente come fa questo metodo a cambiare gli attributi CSS di .class [special]: dopo lo pseudo elemento, come il colore di sfondo o qualcos'altro?
Andreszs,

5

C'è un'altra alternativa. Invece di manipolare direttamente le pseudo-classi, crea vere e proprie classi che modellano le stesse cose, come una classe "hover" o una classe "visitata". Dai uno stile alle classi con il solito "." sintassi e quindi è possibile utilizzare JavaScript per aggiungere o rimuovere classi da un elemento quando viene generato l'evento appropriato.


2
Questo non funziona per: prima e dopo le pseudo lezioni.
jbyrd,

E questo non è applicabile per cambiare l'immagine di sfondo con un valore recuperato tramite AJAX.
Andreszs,

1
@jbyrd, :beforee :aftersono pseudo elementi, non classi.
Roy Ling,

@royling - sì, grazie per la correzione! Non riesco a modificare il mio commento.
jbyrd,

4

Invece di impostare direttamente le regole di pseudo-classe con javascript, puoi impostare le regole in modo diverso in diversi file CSS, quindi utilizzare JavaScript per disattivare un foglio di stile e attivarne un altro. Un metodo è descritto in A List Apart (qv. Per maggiori dettagli).

Imposta i file CSS come,

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

E poi passare da uno all'altro usando 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;
     }
   }
}

Cosa succede se è necessario modificare dinamicamente la classe in un valore recuperato da una richiesta AJAX? Non puoi creare un file CSS ora ...
andreszs,

2

Come già detto, questo non è qualcosa che supporta i browser.

Se non stai creando gli stili in modo dinamico (ovvero estraendoli da un database o qualcosa del genere) dovresti essere in grado di aggirare questo aggiungendo una classe al corpo della pagina.

Il CSS sarebbe simile a:

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

E il javascript per cambiare questo sarebbe qualcosa del tipo:

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

document.body.className += " theme1";  

Per curiosità, element.classList.addnon è ben supportato? Continuo a vedere la gente fare element.className +=.
Joel Cornett,

2
classList è una funzionalità più recente e sembra che non abbia avuto un buon supporto fino a poco tempo fa (vedi caniuse.com/classlist )
Nathaniel Reinhart,


-1

In jquery puoi impostare facilmente le pseudo classi al passaggio del mouse.

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

-1

ecco una soluzione che include due funzioni: addCSSclass aggiunge una nuova classe css al documento e toggleClass la attiva

L'esempio mostra l'aggiunta di una barra di scorrimento personalizzata a un 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>


-2

Se usi REACT, c'è qualcosa chiamato radio . È così utile qui:

  • Aggiungi gestori agli oggetti di scena se sono stati specificati stili interattivi, ad esempio onMouseEnter per: passa il mouse, se necessario avvolge i gestori esistenti

  • Se viene attivato uno dei gestori, ad esempio passando con il mouse, Radium chiama setState per aggiornare un campo specifico di Radium sull'oggetto stato dei componenti

  • Al re-rendering, risolvi tutti gli stili interattivi che si applicano, ad esempio: passa il mouse, cercando la chiave dell'elemento o ref nello stato specifico di Radium

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.