JavaScript'te dinamik olarak CSS sınıfı nasıl oluşturulur ve uygulanır?


Yanıtlar:


394

JavaScript ile neden CSS sınıfları oluşturmak istediğinizden emin olmasam da, işte bir seçenek:

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

10
Kullanım durumum, KG amaçları için belirli öğeleri vurgulayan bir yer imi.
TomG

25
Bunun IE 8 ve altında bilinmeyen bir çalışma zamanı hatasıyla sonuçlandığından emin olabilirsiniz.
Andy Hume

1
Benim kullanım durumu rastgele bir Google web yazı tipini yüklerken ve sonra randomFont sınıfı font-family :-) veriyor
w00t

26
Başka bir kullanım durumu, CSS dosyalarına bağımlı olmadan tek bir JS lib'i istediğiniz yerdir. Benim durumumda hafif hırsız tarzı uyarı pop-up'ları kutudan istiyorum.
xeolabs

1
W00t gibi bir şey yapıyorum. Bir tuval üzerine yazma olacak etkileşimli bir html5 uygulaması üzerinde çalışıyorum ve kullanacağım fontların geniş bir yelpazesinden seçim yapmasına izin vermek istiyorum. Tüm yazı tipi ile bir loooong css sahip olmak yerine, sadece yazı tipi verilerini yükleyeceğim bir arka plan oluşturmayı planlıyorum ve program her yüklendiğinde, bir web hizmetine küçük bir çağrı yazı tipini getiriyor ve ekliyor
CJLopez

117

Tüm tarayıcılarda çalışan daha iyi bir çözüm buldum.
Kural eklemek veya değiştirmek için document.styleSheet öğesini kullanır. Kabul edilen cevap kısa ve kullanışlıdır, ancak bu IE8 ve daha azında da çalışır.

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

Fonksiyon aşağıdaki gibi kullanılır.

createCSSSelector('.mycssclass', 'display:none');

2
IE8 ile çalıştığı onaylandı. Görünüşe göre bazen Chrome'da çalışmadığı için mediaType for-loop'a "styleSheet.cssRules [i] .selectorText &&" ve "styleSheet.rules [i] .selectorText &&" eklemeliydim. tanımlanmadı.
w00t

@ w00t Çalıştırmak için kodu yapıştırabilir veya düzenleyebilir misiniz?
Hengjie

Chrome'u yeni açtım (Sürüm 34.0.1847.132), işlevleri yapıştırdı ve çalıştırdı, ancak işe yaramadı: "TypeError: null özelliği 'length' okunamıyor". Geliştirici konsolundan oluşturmaya çalışmaz mı?
dnuske

Bazı krom (veya krom) sürümlerinin dizin 0'a InsertRule eklenmesine izin vermediği ortaya çıktı. İşte düzeltme: styleSheet.insertRule (selector + "{" + style + "}", styleSheet.cssRules.length);
dnuske

1
@dnuske Aynı sorunla karşılaştım. styleSheet.cssRules öğesinin null olarak değerlendirildiği ortaya çıkar. kullandığım düzeltme, yeni bir değişken oluşturmak var styleSheetLength = styleSheet.cssRules ? styleSheet.cssRules.length : 0ve işlevini, işlevin yerine getirilmesi yerine kullanmaktır.
Raj Nathani

27

Kısa cevap, bu "tüm tarayıcılarda" uyumludur (özellikle 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;");

Ve bu son bit sınıfı bir öğeye uygular:

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

İşte küçük bir test sayfası: https://gist.github.com/shadybones/9816763

Önemli olan, stil öğelerinin kural eklemek / kaldırmak için kullanabileceğiniz bir "styleSheet" / "sheet" özelliğine sahip olmasıdır.


yani bu her sınıf yaratımında yeni bir "stil" öğesi yaratır mı? Verilere dayalı bir for döngüsünde 1000+ sınıf oluşturacak olsaydım, bunun document.head.appendChild 1000 kez uygulanması gerekir?
bluejayke

chrome style.sheet and style.styleSheet yok
bluejayke


7

YUI orada gördüğüm en iyi stil sayfası yardımcı programı vardır. Kontrol etmenizi öneririm, ama işte bir tat:

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

Açıkçası burada önerilenler gibi stilleri değiştirmenin çok daha basit yolları var. Sorununuz için mantıklıysa, en iyileri olabilir, ancak css'i değiştirmenin daha iyi bir çözüm olmasının kesinlikle nedenleri vardır. En belirgin durum, çok sayıda elemanı değiştirmeniz gerektiğidir. Diğer önemli durum ise, kaskadı dahil etmek için stil değişikliklerinize ihtiyaç duymanızdır. Bir öğeyi değiştirmek için dom'u kullanmak her zaman daha yüksek önceliğe sahip olacaktır. Balyoz yaklaşımıdır ve stil özniteliğini doğrudan html öğesinde kullanmaya eşdeğerdir. Bu her zaman istenen etki değildir.


5

IE 9'dan itibaren. Artık bir metin dosyası yükleyebilir ve bir style.innerHTML özelliği ayarlayabilirsiniz. Yani aslında ajax aracılığıyla bir css dosyası yükleyebilir (ve geri arama alabilirsiniz) ve sonra sadece böyle bir stil etiketinin içindeki metni ayarlayabilirsiniz.

Bu, diğer tarayıcılarda çalışır, ne kadar geri döndüğünden emin değilim. Ancak IE8'i desteklemeniz gerekmediği sürece işe yarayacaktır.

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

ve sonra myCss.css gibi harici bir dosya çekmesini sağlayabilirsiniz

.myClass { background:#F00; }

5

Vishwanath'ın çözümü, yorumlarla hafifçe yeniden yazılmış:

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

4

Görevinizde size yardımcı olabilecek ilginç bir proje JSS .

JSS, CSS üzerinde daha iyi bir soyutlamadır. Stilleri bildirici ve sürdürülebilir bir şekilde tanımlamak için JavaScript'i dil olarak kullanır. Tarayıcılarda ve sunucu tarafında çalışma zamanında çalışan yüksek performanslı bir JS - CSS derleyicisidir.

JSS kütüphanesi, .attach()fonksiyonu kullanarak DOM / head bölümüne enjekte etmenizi sağlar .

Çevrimiçi sürümü yanıtlaDeğerlendirme için .

JSS hakkında daha fazla bilgi .

Bir örnek:

// 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()

3

Google kapanışını kullanma:

ccsom modülünü kullanabilirsiniz:

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

Javascript kodu, css düğümü belge kafasına yerleştirilirken çapraz tarayıcı olmaya çalışır.


3

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

JavaScript'te dinamik olarak CSS sınıfı oluşturmak ve güncellemek için bir seçenek:

  • CSS bölümü oluşturmak için Stil Öğesini kullanma
  • CSS
    sınıfını güncelleyebilmemiz için stil öğesi için bir kimlik kullanma

.....

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)

1

Cevapları inceledikten sonra en açık ve en basit olanı eksik: document.write()İhtiyacınız olan bir yığın CSS yazmak için kullanın .

İşte bir örnek (codepen'de görüntüleyin: 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>

Sayfa yüklendikten sonra CSS kuralları oluşturmanız gerekmediği veya XHTML kullanmadıkça bu sorun olmaz.
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);

ya belgede güncel bir stil sayfası yoksa
bluejayke

1

İşte benim modüler çözüm:

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

Temelde her yerde kodunda yapın:
addNewStyle('body', 'color: ' + color1);neredecolor1 değişken tanımlanır.

Yaptığınız mevcut CSS dosyasını "göndermek" istediğinizde submitNewStyle(),
daha sonra yine de daha fazla CSS ekleyebilirsiniz.

"Medya sorguları" ile eklemek istiyorsanız, seçeneğiniz vardır.
"AddNewStyles" den sonra sadece kullanın submitNewStyleWithMedia('min-width: 1280px');.


Kamu (benim değil) web sitesinin CSS'sini şu anki zamana göre değiştirdiğim için kullanım durumum için oldukça yararlıydı. "Aktif" komut dosyalarını kullanmadan önce bir CSS dosyası gönderiyorum ve daha sonra geri kalanı (sitenin öğelere erişmeden önce olması gerektiği gibi görünmesini sağlar querySelector).


Bunu bugün deneyeceğim. Kullanım durumumda bunun nasıl çalıştığını size bildireceğim. Parmak çarpı işareti !!!!
lopezdp

0

Arama yapanların yararına; jQuery kullanıyorsanız aşağıdakileri yapabilirsiniz:

var currentOverride = $('#customoverridestyles');

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

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

İç css'yi istediğiniz gibi değiştirebilirsiniz.

Bazılarının saf JavaScript'i tercih etmesini takdir edin, ancak çalışır ve stilleri dinamik olarak yazmak / üzerine yazmak için oldukça sağlamdır.


0

Burada bazı cevapları inceliyordum ve hiçbiri yoksa otomatik olarak yeni bir stil sayfası ekleyen bir şey bulamadım ve eğer sadece gerekli stili içeren mevcut olanı değiştirmezse, yeni bir işlev yaptım ( test edilmemiş olsa da tüm tarayıcılarda çalışmalı, addRule kullanır ve bunun yanı sıra yalnızca temel yerel JavaScript, çalışıp çalışmadığını bana bildirin):

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

};  

bu 2 yardımcı işlevi yukarıdaki işlevin içine veya başka bir yere eklemeniz yeterlidir:

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

(her ikisinde de .filter yerine bir for döngüsü kullandığımı unutmayın, çünkü CSS stil / kural listesi sınıfları yalnızca length özelliğine sahiptir ve .filter yöntemi yoktur.)

Sonra aramak için:

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

Tarayıcınız için işe yarayıp yaramadığını bana bildirin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.