Mengatur aturan pseudo-class CSS dari JavaScript

125

Saya mencari cara untuk mengubah aturan CSS untuk pemilih kelas semu (seperti: tautan,: hover, dll.) Dari JavaScript.

Jadi analog dari kode CSS: a:hover { color: red }di JS.

Saya tidak dapat menemukan jawabannya di tempat lain; jika ada yang tahu bahwa ini adalah sesuatu yang tidak didukung browser, itu akan menjadi hasil yang bermanfaat juga.

pengguna39882
sumber

Jawaban:

192

Anda tidak dapat mendesain kelas pseudo pada elemen tertentu saja, dengan cara yang sama Anda tidak dapat memiliki kelas pseudo dalam atribut inline style = "..." (karena tidak ada pemilih).

Anda bisa melakukannya dengan mengubah stylesheet, misalnya dengan menambahkan aturan:

#elid:hover { background: red; }

dengan asumsi setiap elemen yang ingin Anda pengaruhi memiliki ID unik untuk memungkinkannya dipilih.

Secara teori, dokumen yang Anda inginkan adalah http://www.w3.org/TR/DOM-Level-2-Style/Overview.html yang berarti Anda dapat (diberi stylesheet yang tertanam atau ditautkan sebelumnya) menggunakan sintaksis seperti:

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

IE, tentu saja, membutuhkan sintaksnya sendiri:

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

Browser lama dan kecil cenderung tidak mendukung sintaksis mana pun. Mengutak-atik gaya dinamis jarang dilakukan karena cukup menjengkelkan untuk mendapatkan yang benar, jarang dibutuhkan, dan secara historis merepotkan.

bobince
sumber
32
Mengapa ini tidak dipilih sebagai jawaban?
SZH
2
Firefox: "Kesalahan: Operasi tidak aman."
8128
@ fluteflute, operasi ini dianggap tidak aman jika Anda mencoba memanipulasi file CSS dari domain yang berbeda (saya rasa ini adalah jenis kebijakan yang sama-asal kebijakannya). Malu! Fungsi sederhana untuk memeriksa sesuai dengan kebijakan asal-sama: 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
Memanipulasi stylesheet hanya untuk menerapkan gaya ke elemen tertentu tidak dianjurkan karena menyebabkan browser untuk merefow seluruh dokumen setiap kali stylesheet diubah. stubbornella.org/content/2009/03/27/…
Johannes Ewald
29

Saya mengumpulkan perpustakaan kecil untuk ini karena saya pikir ada kasus penggunaan yang valid untuk memanipulasi stylesheet di JS. Alasannya adalah:

  • Mengatur gaya yang harus dihitung atau diambil - misalnya mengatur ukuran font pilihan pengguna dari cookie.
  • Mengatur gaya perilaku (bukan estetika), terutama untuk pengembang widget / plugin UI. Tab, komidi putar, dll, sering memerlukan beberapa CSS dasar hanya untuk berfungsi - seharusnya tidak menuntut stylesheet untuk fungsi inti.
  • Lebih baik daripada gaya sebaris karena aturan CSS berlaku untuk semua elemen saat ini dan masa depan, dan jangan mengacaukan HTML saat melihat di Firebug / Alat Pengembang.
David Tang
sumber
17

Fungsi untuk mengatasi hal-hal lintas-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);
    }
  }
};

sumber
7

Cukup tempatkan css di string template.

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

Kemudian buat elemen gaya dan tempatkan string di tag gaya dan lampirkan ke dokumen.

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

Kekhususan akan mengurus sisanya. Kemudian Anda dapat menghapus dan menambahkan tag gaya secara dinamis. Ini adalah alternatif sederhana untuk pustaka dan mengacaukan array stylesheet di DOM. Selamat Coding!

situs kusut
sumber
insertAdjacentElementmembutuhkan 2 argumen di browser utama (Chrome, Firefox, Edge), yang pertama menetapkan posisi relatif terhadap elemen referensi ( lihat di sini ). Apakah ini perubahan terbaru? (Ditambahkan 'sebelum akhir' ke jawabannya).
collapsar
6

Trik saya menggunakan pemilih atribut. Atribut lebih mudah diatur dengan 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
sumber
4
Solusi ini menggunakan jQuery - memperkenalkan ketergantungan ukuran jQuery untuk sesuatu yang sesederhana ini, ketika si penanya meminta Javascript murni, itu buruk.
Tom Ashworth
Meskipun praktis semua situs web saat ini MENGGUNAKAN jquery, saya akan memodifikasinya untuk menggunakan javascript murni.
Sergio Abreu
1
Dan tepatnya bagaimana metode ini dapat mengubah atribut CSS dari .class [spesial]: setelah elemen semu, seperti, warna latar belakang atau yang lainnya?
andreszs
5

Ada alternatif lain. Alih-alih memanipulasi pseudo-class secara langsung, buat kelas nyata yang memodelkan hal yang sama, seperti kelas "melayang" atau kelas "dikunjungi". Tata kelas dengan gaya biasa "." sintaks dan kemudian Anda dapat menggunakan JavaScript untuk menambah atau menghapus kelas dari suatu elemen ketika acara yang sesuai kebakaran.

Brandon Ramirez
sumber
2
Itu tidak bekerja untuk: sebelum dan: setelah kelas semu.
jbyrd
Dan itu tidak berlaku untuk mengubah gambar latar belakang dengan nilai yang diambil melalui AJAX.
andreszs
1
@jbyrd, :before& :afteradalah elemen semu, bukan kelas.
Roy Ling
@lingling - ya, terima kasih atas koreksinya! Tampaknya tidak dapat mengedit komentar saya.
jbyrd
4

Alih-alih langsung mengatur aturan pseudo-class dengan javascript, Anda dapat mengatur aturan secara berbeda di file CSS yang berbeda, dan kemudian menggunakan Javascript untuk mematikan satu stylesheet dan mengaktifkan yang lain. Metode dijelaskan di A List Apart (qv. Untuk lebih detail).

Atur file CSS sebagai,

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

Dan kemudian beralih di antara mereka menggunakan 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;
     }
   }
}
Trigonometri
sumber
Bagaimana jika Anda perlu mengubah kelas secara dinamis ke nilai yang diambil oleh permintaan AJAX? Anda tidak dapat membuat file CSS sekarang ...
andreszs
2

Seperti yang sudah dinyatakan ini bukan sesuatu yang didukung browser.

Jika Anda tidak membuat style secara dinamis (misalnya menariknya dari database atau sesuatu), Anda harus dapat mengatasinya dengan menambahkan kelas ke badan halaman.

Css akan terlihat seperti:

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

Dan javascript untuk mengubah ini adalah sesuatu seperti:

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

document.body.className += " theme1";  
Nathaniel Reinhart
sumber
Karena penasaran, apakah element.classList.addtidak didukung dengan baik? Saya terus melihat orang melakukan element.className +=.
Joel Cornett
2
classList adalah fitur yang lebih baru dan sepertinya tidak memiliki dukungan yang baik sampai saat ini (lihat caniuse.com/classlist )
Nathaniel Reinhart
-1

Di jquery Anda dapat dengan mudah mengatur kelas pseudo hover.

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

di sini adalah solusi termasuk dua fungsi: addCSSclass menambahkan kelas css baru ke dokumen, dan toggleClass menyalakannya

Contoh menunjukkan menambahkan bilah gulir khusus ke 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
sumber
-2

Jika Anda menggunakan REACT, Ada sesuatu yang disebut radium . Ini sangat berguna di sini:

  • Tambahkan penangan ke alat peraga jika gaya interaktif ditentukan, misalnya onMouseEnter untuk: melayang-layang, membungkus penangan yang ada jika perlu

  • Jika salah satu penangan dipicu, misalnya dengan melayang, Radium memanggil setState untuk memperbarui bidang khusus-Radium pada objek keadaan komponen

  • Saat dirender ulang, selesaikan gaya interaktif apa pun yang berlaku, misalnya: arahkan, dengan mencari kunci elemen atau ref dalam keadaan khusus Radium

Abdennour TOUMI
sumber