Festlegen von CSS-Pseudoklassenregeln aus JavaScript

125

Ich suche nach einer Möglichkeit, die CSS-Regeln für Pseudo-Klassen-Selektoren (wie: link ,: hover usw.) von JavaScript aus zu ändern.

Also ein Analogon zum CSS-Code: a:hover { color: red }in JS.

Ich konnte die Antwort nirgendwo anders finden; Wenn jemand weiß, dass dies etwas ist, das Browser nicht unterstützen, wäre dies ebenfalls ein hilfreiches Ergebnis.

user39882
quelle

Antworten:

191

Sie können eine Pseudoklasse nicht nur für ein bestimmtes Element formatieren, so wie Sie keine Pseudoklasse in einem Inline-Attribut style = "..." haben können (da es keinen Selektor gibt).

Sie können dies tun, indem Sie das Stylesheet ändern, indem Sie beispielsweise die Regel hinzufügen:

#elid:hover { background: red; }

Angenommen, jedes Element, das Sie beeinflussen möchten, verfügt über eine eindeutige ID, damit es ausgewählt werden kann.

Theoretisch lautet das gewünschte Dokument http://www.w3.org/TR/DOM-Level-2-Style/Overview.html. Dies bedeutet, dass Sie (bei einem bereits vorhandenen eingebetteten oder verknüpften Stylesheet) folgende Syntax verwenden können:

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

IE erfordert natürlich eine eigene Syntax:

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

Ältere und kleinere Browser unterstützen wahrscheinlich keine der beiden Syntax. Dynamisches Stylesheet-Fummeln wird selten durchgeführt, da es ziemlich ärgerlich ist, es richtig zu machen, es wird selten benötigt und ist historisch problematisch.

Bobince
quelle
32
Warum wurde dies nicht als Antwort gewählt?
SZH
2
Firefox: "Fehler: Der Vorgang ist unsicher."
8128
@fluteflute Der Vorgang wird als unsicher angesehen, wenn Sie versuchen, eine CSS-Datei aus einer anderen Domäne heraus zu manipulieren (ich denke, es handelt sich um eine Art Richtliniensache mit demselben Ursprung). Schande! Einfache Funktion zu überprüfen entspricht der Richtlinie des gleichen Ursprungs: 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
Das Bearbeiten des Stylesheets, um Stile auf ein bestimmtes Element anzuwenden, wird nicht empfohlen, da der Browser bei jeder Änderung des Stylesheets das gesamte Dokument neu fließen lässt. stubbornella.org/content/2009/03/27/…
Johannes Ewald
29

Ich habe dafür eine kleine Bibliothek zusammengestellt, da ich glaube, dass es gültige Anwendungsfälle für die Bearbeitung von Stylesheets in JS gibt. Gründe dafür sind:

  • Festlegen von Stilen, die berechnet oder abgerufen werden müssen, z. B. Festlegen der bevorzugten Schriftgröße des Benutzers aus einem Cookie.
  • Festlegen von Verhaltensstilen (nicht ästhetischen), insbesondere für Entwickler von UI-Widgets / Plugins. Tabs, Karussells, etc., erfordern oft einige grundlegende CSS einfach zu Funktion - nicht sollte verlangen , ein Stylesheet für die Kernfunktion.
  • Besser als Inline-Stile, da CSS-Regeln für alle aktuellen und zukünftigen Elemente gelten und den HTML-Code beim Anzeigen in Firebug / Developer Tools nicht überladen.
David Tang
quelle
17

Eine Funktion, um mit dem Cross-Browser-Zeug fertig zu werden:

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

quelle
7

Platzieren Sie das CSS einfach in einer Vorlagenzeichenfolge.

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

Erstellen Sie dann ein Stilelement, platzieren Sie die Zeichenfolge im Stil-Tag und hängen Sie sie an das Dokument an.

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

Die Spezifität kümmert sich um den Rest. Anschließend können Sie Stil-Tags dynamisch entfernen und hinzufügen. Dies ist eine einfache Alternative zu Bibliotheken und zum Durcheinander mit dem Stylesheet-Array im DOM. Viel Spaß beim Codieren!

Verwicklungsstellen
quelle
insertAdjacentElementerfordert 2 Argumente in den Hauptbrowsern (Chrome, Firefox, Edge), von denen das erste die Position relativ zum Referenzelement festlegt ( siehe hier ). Ist das eine kürzliche Änderung? ('Beforeend' zur Antwort hinzugefügt).
Kollapsar
6

Mein Trick ist die Verwendung eines Attributselektors. Attribute lassen sich einfacher mit Javascript einrichten.

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
quelle
4
Diese Lösung verwendet jQuery - die Einführung einer Abhängigkeit von der Größe von jQuery für etwas so Einfaches wie dieses, wenn der Fragesteller nach reinem Javascript gefragt hat, ist schlecht.
Tom Ashworth
Obwohl heutzutage praktisch alle Websites jquery verwenden, werde ich es so modifizieren, dass es reines Javascript verwendet.
Sergio Abreu
1
Und genau wie kann diese Methode die CSS-Attribute der .class [special] ändern: nach Pseudoelementen wie der Hintergrundfarbe oder irgendetwas anderem?
andreszs
5

Es gibt noch eine andere Alternative. Anstatt die Pseudoklassen direkt zu manipulieren, erstellen Sie echte Klassen, die dieselben Dinge modellieren, wie eine "Hover" -Klasse oder eine "besuchte" Klasse. Gestalten Sie die Klassen mit dem üblichen "." Syntax und dann können Sie JavaScript verwenden, um Klassen zu einem Element hinzuzufügen oder daraus zu entfernen, wenn das entsprechende Ereignis ausgelöst wird.

Brandon Ramirez
quelle
2
Das funktioniert nicht für: vor und: nach Pseudoklassen.
jbyrd
Dies gilt nicht für das Ändern des Hintergrundbilds mit einem über AJAX abgerufenen Wert.
andreszs
1
@jbyrd, :before& :aftersind Pseudoelemente , keine Klassen.
Roy Ling
@royling - ja, danke für die Korrektur! Ich kann meinen Kommentar nicht bearbeiten.
8.
4

Anstatt Pseudoklassenregeln direkt mit Javascript festzulegen, können Sie die Regeln in verschiedenen CSS-Dateien unterschiedlich festlegen und dann mit Javascript ein Stylesheet ausschalten und ein anderes einschalten. Eine Methode wird unter A List Apart beschrieben (siehe für weitere Einzelheiten).

Richten Sie die CSS-Dateien wie folgt ein:

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

Und dann mit Javascript zwischen ihnen wechseln:

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;
     }
   }
}
TRiG
quelle
Was ist, wenn Sie die Klasse dynamisch in einen Wert ändern müssen, der von einer AJAX-Anforderung abgerufen wird? Sie können jetzt keine CSS-Datei erstellen ...
andreszs
2

Wie bereits erwähnt, wird dies von Browsern nicht unterstützt.

Wenn Sie die Stile nicht dynamisch erstellen (dh sie aus einer Datenbank oder etwas anderem ziehen), sollten Sie dies umgehen können, indem Sie dem Hauptteil der Seite eine Klasse hinzufügen.

Das CSS würde ungefähr so ​​aussehen:

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

Und das Javascript, um dies zu ändern, wäre ungefähr so:

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

document.body.className += " theme1";  
Nathaniel Reinhart
quelle
Wird aus Neugier element.classList.addnicht gut unterstützt? Ich sehe immer wieder Leute element.className +=.
Joel Cornett
2
classList ist eine neuere Funktion und scheint bis vor kurzem keine gute Unterstützung zu haben (siehe caniuse.com/classlist )
Nathaniel Reinhart
-1

In jquery können Sie einfach Schwebepseudoklassen festlegen.

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

Hier ist eine Lösung mit zwei Funktionen: addCSSclass fügt dem Dokument eine neue CSS-Klasse hinzu, und toggleClass aktiviert sie

Das Beispiel zeigt das Hinzufügen einer benutzerdefinierten Bildlaufleiste zu einem 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
quelle
-2

Wenn Sie REACT verwenden, gibt es etwas, das Radium genannt wird . Es ist hier so nützlich:

  • Fügen Sie Handlern zu Requisiten hinzu, wenn interaktive Stile angegeben sind, z. B. onMouseEnter für: hover, und schließen Sie vorhandene Handler bei Bedarf um

  • Wenn einer der Handler ausgelöst wird, z. B. durch Bewegen des Mauszeigers, ruft Radium setState auf, um ein Radium-spezifisches Feld im Komponentenstatusobjekt zu aktualisieren

  • Lösen Sie beim erneuten Rendern alle zutreffenden interaktiven Stile auf, z. B.: Hover, indem Sie den Schlüssel oder die Referenz des Elements im Radium-spezifischen Zustand nachschlagen

Abdennour TOUMI
quelle