Bagaimana cara membuat kelas CSS secara dinamis dalam JavaScript dan menerapkannya?

299

Saya perlu membuat kelas stylesheet CSS secara dinamis dalam JavaScript dan menetapkannya ke beberapa elemen HTML seperti - div, tabel, span, tr, dll dan untuk beberapa kontrol seperti asp: Textbox, Dropdownlist dan datalist.

Apa itu mungkin?

Akan menyenangkan dengan sampel.

Himadri
sumber
2
lihat di github.com/Box9/jss
jedierikb

Jawaban:

394

Meskipun saya tidak yakin mengapa Anda ingin membuat kelas CSS dengan JavaScript, berikut adalah opsi:

var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.cssClass { color: #F00; }';
document.getElementsByTagName('head')[0].appendChild(style);

document.getElementById('someElementId').className = 'cssClass';
Saya
sumber
10
Kasing penggunaan saya adalah bookmarklet yang menyorot elemen tertentu untuk tujuan QA.
TomG
25
Cukup yakin ini menghasilkan kesalahan runtime yang tidak diketahui di IE 8 dan kurang.
Andy Hume
1
Kasing penggunaan saya memuat font web Google acak dan kemudian memberikan kelas randomFont font-family :-)
w00t
26
Kasus penggunaan lain adalah di mana Anda ingin JS lib tunggal tanpa ketergantungan pada file CSS. Dalam kasus saya, saya ingin popup peringatan growl-style ringan di luar kotak.
xeolabs
1
Saya melakukan sesuatu yang mirip seperti w00t. Saya sedang mengerjakan aplikasi html5 interaktif, yang akan menulis di atas kanvas, dan saya ingin membiarkan pengguna saya memilih dari berbagai jenis font untuk digunakan. Alih-alih memiliki loooong css dengan semua font, saya berencana membuat backend di mana saya hanya akan mengunggah data font dan setiap kali program dimuat, sedikit panggilan ke layanan web membawa font dan menambahkannya
CJLopez
117

Menemukan solusi yang lebih baik, yang berfungsi di semua browser.
Menggunakan document.styleSheet untuk menambah atau mengganti aturan. Jawaban yang diterima pendek dan praktis tetapi ini berfungsi di IE8 dan juga kurang.

function createCSSSelector (selector, style) {
  if (!document.styleSheets) return;
  if (document.getElementsByTagName('head').length == 0) return;

  var styleSheet,mediaType;

  if (document.styleSheets.length > 0) {
    for (var i = 0, l = document.styleSheets.length; i < l; i++) {
      if (document.styleSheets[i].disabled) 
        continue;
      var media = document.styleSheets[i].media;
      mediaType = typeof media;

      if (mediaType === 'string') {
        if (media === '' || (media.indexOf('screen') !== -1)) {
          styleSheet = document.styleSheets[i];
        }
      }
      else if (mediaType=='object') {
        if (media.mediaText === '' || (media.mediaText.indexOf('screen') !== -1)) {
          styleSheet = document.styleSheets[i];
        }
      }

      if (typeof styleSheet !== 'undefined') 
        break;
    }
  }

  if (typeof styleSheet === 'undefined') {
    var styleSheetElement = document.createElement('style');
    styleSheetElement.type = 'text/css';
    document.getElementsByTagName('head')[0].appendChild(styleSheetElement);

    for (i = 0; i < document.styleSheets.length; i++) {
      if (document.styleSheets[i].disabled) {
        continue;
      }
      styleSheet = document.styleSheets[i];
    }

    mediaType = typeof styleSheet.media;
  }

  if (mediaType === 'string') {
    for (var i = 0, l = styleSheet.rules.length; i < l; i++) {
      if(styleSheet.rules[i].selectorText && styleSheet.rules[i].selectorText.toLowerCase()==selector.toLowerCase()) {
        styleSheet.rules[i].style.cssText = style;
        return;
      }
    }
    styleSheet.addRule(selector,style);
  }
  else if (mediaType === 'object') {
    var styleSheetLength = (styleSheet.cssRules) ? styleSheet.cssRules.length : 0;
    for (var i = 0; i < styleSheetLength; i++) {
      if (styleSheet.cssRules[i].selectorText && styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase()) {
        styleSheet.cssRules[i].style.cssText = style;
        return;
      }
    }
    styleSheet.insertRule(selector + '{' + style + '}', styleSheetLength);
  }
}

Fungsinya digunakan sebagai berikut.

createCSSSelector('.mycssclass', 'display:none');
Vishwanath
sumber
2
Dikonfirmasi bekerja dengan IE8. Saya memang harus menambahkan "styleSheet.cssRules [i] .selectorText &&" dan "styleSheet.rules [i] .selectorText &&" di mediaType for-loop seandainya karena itu tidak bekerja di Chrome, tampaknya kadang-kadang selectorText tidak tidak didefinisikan.
w00t
@ w00t Bisakah Anda menempelkan atau mengedit kode untuk membuatnya berfungsi?
Hengjie
Saya baru saja membuka Chrome (Versi 34.0.1847.132) menempelkan fungsi dan menjalankannya, tetapi tidak berhasil: "TypeError: Tidak dapat membaca properti 'length' of null". Mungkinkah itu tidak berhasil membuatnya dari konsol pengembang?
dnuske
Ternyata beberapa versi chrome (atau chromium) tidak memungkinkan untuk menyisipkan aturan pada indeks 0. Ini adalah perbaikannya: styleSheet.insertRule (pemilih + "{" + style + "}", styleSheet.cssRules.length);
dnuske
1
@duske Saya mengalami masalah yang sama. ternyata styleSheet.cssRules dievaluasi menjadi nol. perbaikan yang saya gunakan adalah membuat variabel baru var styleSheetLength = styleSheet.cssRules ? styleSheet.cssRules.length : 0dan menggantinya dengan penerapan fungsi.
Raj Nathani
27

Jawaban singkat, ini kompatibel "pada semua browser" (khususnya, IE8 / 7):

function createClass(name,rules){
    var style = document.createElement('style');
    style.type = 'text/css';
    document.getElementsByTagName('head')[0].appendChild(style);
    if(!(style.sheet||{}).insertRule) 
        (style.styleSheet || style.sheet).addRule(name, rules);
    else
        style.sheet.insertRule(name+"{"+rules+"}",0);
}
createClass('.whatever',"background-color: green;");

Dan bit terakhir ini menerapkan kelas ke elemen:

function applyClass(name,element,doRemove){
    if(typeof element.valueOf() == "string"){
        element = document.getElementById(element);
    }
    if(!element) return;
    if(doRemove){
        element.className = element.className.replace(new RegExp("\\b" + name + "\\b","g"));
    }else{      
        element.className = element.className + " " + name;
    }
}

Ini juga halaman pengujian kecil: https://gist.github.com/shadybones/9816763

Kuncinya adalah fakta bahwa elemen style memiliki properti "styleSheet" / "sheet" yang dapat Anda gunakan untuk menambah / menghapus aturan.

tulang rindang
sumber
jadi ini menciptakan elemen "style" baru setiap kreasi kelas? Jadi jika saya membuat 1000+ kelas dalam for for berdasarkan data, ini perlu menerapkan document.head.appendChild 1000 kali?
bluejayke
bagi saya di chrome style.sheet dan style.styleSheet tidak ada
bluejayke
17

Ada plugin jQuery ringan yang memungkinkan untuk menghasilkan deklarasi CSS: jQuery-injectCSS

Sebenarnya, ia menggunakan JSS (CSS dijelaskan oleh JSON), tetapi cukup mudah ditangani untuk menghasilkan stylesheet css dinamis.

$.injectCSS({
    "#test": {
        height: 123
    }
});
Yako
sumber
mirip dengan stackoverflow.com/questions/1212500/… .
user1742529
7

YUI sejauh ini memiliki utilitas stylesheet terbaik yang pernah saya lihat di sana. Saya mendorong Anda untuk memeriksanya, tapi inilah rasanya:

// style element or locally sourced link element
var sheet = YAHOO.util.StyleSheet(YAHOO.util.Selector.query('style',null,true));

sheet = YAHOO.util.StyleSheet(YAHOO.util.Dom.get('local'));


// OR the id of a style element or locally sourced link element
sheet = YAHOO.util.StyleSheet('local');


// OR string of css text
var css = ".moduleX .alert { background: #fcc; font-weight: bold; } " +
          ".moduleX .warn  { background: #eec; } " +
          ".hide_messages .moduleX .alert, " +
          ".hide_messages .moduleX .warn { display: none; }";

sheet = new YAHOO.util.StyleSheet(css);

Jelas ada banyak cara lain yang lebih sederhana untuk mengubah gaya dengan cepat seperti yang disarankan di sini. Jika mereka masuk akal untuk masalah Anda, mereka mungkin yang terbaik, tetapi pasti ada alasan mengapa memodifikasi css adalah solusi yang lebih baik. Kasus yang paling jelas adalah ketika Anda perlu memodifikasi sejumlah besar elemen. Kasus utama lainnya adalah jika Anda membutuhkan perubahan gaya untuk melibatkan kaskade. Menggunakan dom untuk memodifikasi elemen akan selalu memiliki prioritas yang lebih tinggi. Ini pendekatan palu godam dan setara dengan menggunakan atribut style langsung pada elemen html. Itu tidak selalu efek yang diinginkan.

Russell Leggett
sumber
5

Pada IE 9. Sekarang Anda dapat memuat file teks dan mengatur properti style.innerHTML. Jadi pada dasarnya Anda sekarang dapat memuat file css melalui ajax (dan mendapatkan panggilan balik) dan kemudian hanya mengatur teks di dalam tag gaya seperti ini.

Ini berfungsi di browser lain, tidak yakin seberapa jauh ke belakang. Tetapi selama Anda tidak perlu mendukung IE8 maka itu akan berhasil.

// RESULT: doesn't work in IE8 and below. Works in IE9 and other browsers.
$(document).ready(function() {
    // we want to load the css as a text file and append it with a style.
    $.ajax({
        url:'myCss.css',
        success: function(result) {
            var s = document.createElement('style');
            s.setAttribute('type', 'text/css');
            s.innerHTML = result;
            document.getElementsByTagName("head")[0].appendChild(s);
        },
        fail: function() {
            alert('fail');
        }
    })
});

dan kemudian Anda dapat menariknya file eksternal seperti myCss.css

.myClass { background:#F00; }
Codeguy
sumber
5

Inilah solusi Vishwanath yang ditulis ulang dengan komentar:

function setStyle(cssRules, aSelector, aStyle){
    for(var i = 0; i < cssRules.length; i++) {
        if(cssRules[i].selectorText && cssRules[i].selectorText.toLowerCase() == aSelector.toLowerCase()) {
            cssRules[i].style.cssText = aStyle;
            return true;
        }
    }
    return false;
}

function createCSSSelector(selector, style) {
    var doc = document;
    var allSS = doc.styleSheets;
    if(!allSS) return;

    var headElts = doc.getElementsByTagName("head");
    if(!headElts.length) return;

    var styleSheet, media, iSS = allSS.length; // scope is global in a function
    /* 1. search for media == "screen" */
    while(iSS){ --iSS;
        if(allSS[iSS].disabled) continue; /* dont take into account the disabled stylesheets */
        media = allSS[iSS].media;
        if(typeof media == "object")
            media = media.mediaText;
        if(media == "" || media=='all' || media.indexOf("screen") != -1){
            styleSheet = allSS[iSS];
            iSS = -1;   // indication that media=="screen" was found (if not, then iSS==0)
            break;
        }
    }

    /* 2. if not found, create one */
    if(iSS != -1) {
        var styleSheetElement = doc.createElement("style");
        styleSheetElement.type = "text/css";
        headElts[0].appendChild(styleSheetElement);
        styleSheet = doc.styleSheets[allSS.length]; /* take the new stylesheet to add the selector and the style */
    }

    /* 3. add the selector and style */
    switch (typeof styleSheet.media) {
    case "string":
        if(!setStyle(styleSheet.rules, selector, style));
            styleSheet.addRule(selector, style);
        break;
    case "object":
        if(!setStyle(styleSheet.cssRules, selector, style));
            styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
        break;
    }
pengguna3705905
sumber
4

Proyek menarik yang dapat membantu Anda dalam tugas Anda adalah JSS .

JSS adalah abstraksi yang lebih baik daripada CSS. Ini menggunakan JavaScript sebagai bahasa untuk menggambarkan gaya dengan cara deklaratif dan terpelihara. Ini adalah kompiler JS to CSS berkinerja tinggi yang bekerja saat runtime di browser dan sisi server.

Pustaka JSS memungkinkan Anda untuk menyuntikkan di bagian DOM / kepala menggunakan .attach() fungsi.

Ganti versi online untuk evaluasi.

Informasi lebih lanjut tentang JSS .

Sebuah contoh:

// Use plugins.
jss.use(camelCase())

// Create your style.
const style = {
  myButton: {
    color: 'green'
  }
}

// Compile styles, apply plugins.
const sheet = jss.createStyleSheet(style)

// If you want to render on the client, insert it into DOM.
sheet.attach()
GibboK
sumber
3

Menggunakan google closure:

Anda cukup menggunakan modul ccsom:

goog.require('goog.cssom');
var css_node = goog.cssom.addCssText('.cssClass { color: #F00; }');

Kode javascript mencoba menjadi peramban silang saat meletakkan simpul css ke dalam kepala dokumen.

Joe Heyming
sumber
3

https://jsfiddle.net/xk6Ut/256/

Satu opsi untuk secara dinamis membuat dan memperbarui kelas CSS dalam JavaScript:

  • Menggunakan Elemen Gaya untuk membuat bagian CSS
  • Menggunakan ID untuk elemen style sehingga kami dapat memperbarui
    kelas CSS

.....

function writeStyles(styleName, cssText) {
    var styleElement = document.getElementById(styleName);
    if (styleElement) 
             document.getElementsByTagName('head')[0].removeChild(
        styleElement);
    styleElement = document.createElement('style');
    styleElement.type = 'text/css';
    styleElement.id = styleName;
    styleElement.innerHTML = cssText;
    document.getElementsByTagName('head')[0].appendChild(styleElement);
}

...

    var cssText = '.testDIV{ height:' + height + 'px !important; }';
    writeStyles('styles_js', cssText)
Razan Paul
sumber
1

Melihat melalui jawaban dan yang paling jelas dan langsung hilang: gunakan document.write()untuk menulis sepotong CSS yang Anda butuhkan.

Berikut ini sebuah contoh (lihat di codepen: http://codepen.io/ssh33/pen/zGjWga ):

<style>
   @import url(http://fonts.googleapis.com/css?family=Open+Sans:800);
   .d, body{ font: 3vw 'Open Sans'; padding-top: 1em; }
   .d {
       text-align: center; background: #aaf;
       margin: auto; color: #fff; overflow: hidden; 
       width: 12em; height: 5em;
   }
</style>

<script>
   function w(s){document.write(s)}
   w("<style>.long-shadow { text-shadow: ");
   for(var i=0; i<449; i++) {
      if(i!= 0) w(","); w(i+"px "+i+"px #444");
   }
   w(";}</style>");
</script> 

<div class="d">
    <div class="long-shadow">Long Shadow<br> Short Code</div>
</div>
Tumpukan
sumber
Ini bagus kecuali Anda perlu membuat aturan CSS setelah memuat halaman atau menggunakan XHTML.
Tim Down
1
function createCSSClass(selector, style, hoverstyle) 
{
    if (!document.styleSheets) 
    {
        return;
    }

    if (document.getElementsByTagName("head").length == 0) 
    {

        return;
    }
    var stylesheet;
    var mediaType;
    if (document.styleSheets.length > 0) 
    {
        for (i = 0; i < document.styleSheets.length; i++) 
        {
            if (document.styleSheets[i].disabled) 
            {
                continue;
            }
            var media = document.styleSheets[i].media;
            mediaType = typeof media;

            if (mediaType == "string") 
            {
                if (media == "" || (media.indexOf("screen") != -1)) 
                {
                    styleSheet = document.styleSheets[i];
                }
            } 
            else if (mediaType == "object") 
            {
                if (media.mediaText == "" || (media.mediaText.indexOf("screen") != -1)) 
                {
                    styleSheet = document.styleSheets[i];
                }
            }

            if (typeof styleSheet != "undefined") 
            {
                break;
            }
        }
    }

    if (typeof styleSheet == "undefined") {
        var styleSheetElement = document.createElement("style");
        styleSheetElement.type = "text/css";
        document.getElementsByTagName("head")[0].appendChild(styleSheetElement);
        for (i = 0; i < document.styleSheets.length; i++) {
            if (document.styleSheets[i].disabled) {
                continue;
            }
            styleSheet = document.styleSheets[i];
        }

        var media = styleSheet.media;
        mediaType = typeof media;
    }

    if (mediaType == "string") {
        for (i = 0; i < styleSheet.rules.length; i++) 
        {
            if (styleSheet.rules[i].selectorText.toLowerCase() == selector.toLowerCase()) 
            {
                styleSheet.rules[i].style.cssText = style;
                return;
            }
        }

        styleSheet.addRule(selector, style);
    }
    else if (mediaType == "object") 
    {
        for (i = 0; i < styleSheet.cssRules.length; i++) 
        {
            if (styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase()) 
            {
                styleSheet.cssRules[i].style.cssText = style;
                return;
            }
        }

        if (hoverstyle != null) 
        {
            styleSheet.insertRule(selector + "{" + style + "}", 0);
            styleSheet.insertRule(selector + ":hover{" + hoverstyle + "}", 1);
        }
        else 
        {
            styleSheet.insertRule(selector + "{" + style + "}", 0);
        }
    }
}





createCSSClass(".modalPopup  .header",
                                 " background-color: " + lightest + ";" +
                                  "height: 10%;" +
                                  "color: White;" +
                                  "line-height: 30px;" +
                                  "text-align: center;" +
                                  " width: 100%;" +
                                  "font-weight: bold; ", null);
tushar
sumber
bagaimana jika tidak ada stylesheet saat ini pada dokumen
bluejayke
1

Inilah solusi modular saya:

var final_style = document.createElement('style');
final_style.type = 'text/css';

function addNewStyle(selector, style){
  final_style.innerHTML += selector + '{ ' + style + ' } \n';
};

function submitNewStyle(){
  document.getElementsByTagName('head')[0].appendChild(final_style);

  final_style = document.createElement('style');
  final_style.type = 'text/css';
};

function submitNewStyleWithMedia(mediaSelector){
  final_style.innerHTML = '@media(' + mediaSelector + '){\n' + final_style.innerHTML + '\n};';
    submitNewStyle();
};

Anda pada dasarnya di mana saja dalam kode Anda lakukan:, di
addNewStyle('body', 'color: ' + color1);manacolor1 variabel didefinisikan.

Ketika Anda ingin "memposting" file CSS saat ini yang Anda lakukan submitNewStyle(),
dan kemudian Anda masih dapat menambahkan lebih banyak CSS nanti.

Jika Anda ingin menambahkannya dengan "kueri media", Anda memiliki opsi.
Setelah "menambahkanNewStyles" Anda cukup menggunakan submitNewStyleWithMedia('min-width: 1280px');.


Itu cukup berguna untuk kasus penggunaan saya, karena saya mengubah CSS situs web publik (bukan milik saya) menurut waktu saat ini. Saya mengirimkan satu file CSS sebelum menggunakan skrip "aktif", dan sisanya setelahnya (membuat situs terlihat seperti seharusnya sebelum mengakses elemen melalui querySelector).

Gaben
sumber
Saya akan coba ini hari ini. Akan memberi tahu Anda cara kerjanya dalam use case saya. Semoga saja !!!!
lopezdp
0

Untuk kepentingan pencari; jika Anda menggunakan jQuery, Anda dapat melakukan hal berikut:

var currentOverride = $('#customoverridestyles');

if (currentOverride) {
 currentOverride.remove();
}

$('body').append("<style id=\"customoverridestyles\">body{background-color:pink;}</style>");

Jelas Anda dapat mengubah inner css menjadi apa pun yang Anda inginkan.

Menghargai beberapa orang lebih suka JavaScript murni, tetapi berfungsi dan cukup tangguh untuk gaya penulisan / penulisan ulang secara dinamis.

Hoki
sumber
0

Saya sedang mencari beberapa jawaban di sini, dan saya tidak dapat menemukan apa pun yang secara otomatis menambahkan lembar gaya baru jika tidak ada, dan jika tidak hanya mengubah yang sudah ada yang sudah berisi gaya yang diperlukan, jadi saya membuat fungsi baru ( harus bekerja di semua browser, meskipun tidak diuji, menggunakan addRule dan selain itu hanya JavaScript asli dasar, beri tahu saya jika berfungsi):

function myCSS(data) {
    var head = document.head || document.getElementsByTagName("head")[0];
    if(head) {
        if(data && data.constructor == Object) {
            for(var k in data) {
                var selector = k;
                var rules = data[k];

                var allSheets = document.styleSheets;
                var cur = null;

                var indexOfPossibleRule = null,
                    indexOfSheet = null;
                for(var i = 0; i < allSheets.length; i++) {
                    indexOfPossibleRule = findIndexOfObjPropInArray("selectorText",selector,allSheets[i].cssRules);
                    if(indexOfPossibleRule != null) {
                        indexOfSheet = i;
                        break;
                    }
                }

                var ruleToEdit = null;
                if(indexOfSheet != null) {

                    ruleToEdit = allSheets[indexOfSheet].cssRules[indexOfPossibleRule];

                } else {
                    cur = document.createElement("style");
                    cur.type =  "text/css";
                    head.appendChild(cur);
                    cur.sheet.addRule(selector,"");
                    ruleToEdit = cur.sheet.cssRules[0];
                    console.log("NOPE, but here's a new one:", cur);
                }
                applyCustomCSSruleListToExistingCSSruleList(rules, ruleToEdit, (err) => {
                    if(err) {
                        console.log(err);
                    } else {
                        console.log("successfully added ", rules, " to ", ruleToEdit);
                    }
                });
            }
        } else {
            console.log("provide one paramter as an object containing the cssStyles, like: {\"#myID\":{position:\"absolute\"}, \".myClass\":{background:\"red\"}}, etc...");
        }
    } else {
        console.log("run this after the page loads");
    }

};  

kemudian tambahkan saja 2 fungsi pembantu ini di dalam fungsi di atas, atau di tempat lain:

function applyCustomCSSruleListToExistingCSSruleList(customRuleList, existingRuleList, cb) {
    var err = null;
    console.log("trying to apply ", customRuleList, " to ", existingRuleList);
    if(customRuleList && customRuleList.constructor == Object && existingRuleList && existingRuleList.constructor == CSSStyleRule) {
        for(var k in customRuleList) {
            existingRuleList["style"][k] = customRuleList[k];
        }

    } else {
        err = ("provide first argument as an object containing the selectors for the keys, and the second argument is the CSSRuleList to modify");
    }
    if(cb) {
        cb(err);
    }
}

function findIndexOfObjPropInArray(objPropKey, objPropValue, arr) {
    var index = null;
    for(var i = 0; i < arr.length; i++) {
        if(arr[i][objPropKey] == objPropValue) {
            index = i;
            break;
        }
    }
    return index;
}

(perhatikan bahwa pada keduanya saya menggunakan for for alih-alih .filter, karena kelas gaya / daftar aturan CSS hanya memiliki properti panjang, dan tidak ada metode .filter.)

Kemudian menyebutnya:

myCSS({
    "#coby": {
        position:"absolute",
        color:"blue"
    },
    ".myError": {
        padding:"4px",
        background:"salmon"
    }
})

Beri tahu saya jika itu berfungsi untuk browser Anda atau memberikan kesalahan.

bluejayke
sumber