Làm cách nào để tự động tạo lớp CSS trong JavaScript và áp dụng?


299

Tôi cần tạo một lớp biểu định kiểu CSS một cách linh hoạt trong JavaScript và gán nó cho một số phần tử HTML như - div, bảng, span, tr, v.v. và cho một số điều khiển như asp: Textbox, Dropdownlist và datalist.

Có thể không?

Nó sẽ là tốt đẹp với một mẫu.



Câu trả lời:


394

Mặc dù tôi không chắc tại sao bạn muốn tạo các lớp CSS bằng JavaScript, đây là một tùy chọn:

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
Trường hợp sử dụng của tôi là một bookmarklet làm nổi bật các yếu tố nhất định cho mục đích QA.
TomG

25
Khá chắc chắn rằng điều này dẫn đến một lỗi thời gian chạy không xác định trong IE 8 và ít hơn.
Andy Hume

1
Trường hợp sử dụng của tôi đang tải một phông chữ web ngẫu nhiên của Google và sau đó cung cấp cho lớp RandomFont họ phông chữ :-)
w00t

26
Một trường hợp sử dụng khác sẽ là nơi bạn muốn có một lib lib duy nhất mà không phụ thuộc vào các tệp CSS. Trong trường hợp của tôi, tôi muốn cửa sổ bật lên cảnh báo kiểu gầm nhẹ nhẹ ra khỏi hộp.
xeolabs

1
Tôi đang làm một cái gì đó tương tự như w00t. Tôi đang làm việc trên một ứng dụng html5 tương tác, ứng dụng này sẽ có chữ viết trên khung vẽ và tôi muốn cho phép người dùng của mình chọn từ một loạt các phông chữ để sử dụng. Thay vì có một loooong css với tất cả các phông chữ, tôi dự định tạo một phụ trợ trong đó tôi sẽ chỉ tải lên dữ liệu phông chữ và bất cứ khi nào chương trình được tải, một cuộc gọi nhỏ đến dịch vụ web sẽ mang lại phông chữ và thêm chúng
CJLopez

117

Tìm thấy một giải pháp tốt hơn, hoạt động trên tất cả các trình duyệt.
Sử dụng document.styleSheet để thêm hoặc thay thế các quy tắc. Câu trả lời được chấp nhận là ngắn và tiện dụng nhưng điều này hoạt động trên IE8 và ít hơn.

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

Chức năng được sử dụng như sau.

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

2
Xác nhận làm việc với IE8. Tôi đã phải thêm một "styleSheet.cssRules [i] .selectorText &&" và "styleSheet.rules [i] .selectorText &&" trong if if vòng lặp mediaType vì nó không hoạt động trong Chrome, đôi khi đôi khi selectorText không hoạt động 't xác định.
w00t

@ w00t Bạn có thể vui lòng dán hoặc chỉnh sửa mã để làm cho nó hoạt động không?
Hengjie

Tôi mới mở Chrome (Phiên bản 34.0.1847.132) đã dán các chức năng và thực thi nó, nhưng nó không hoạt động: "TypeError: Không thể đọc thuộc tính 'độ dài' của null". Có thể nó không hoạt động khi tạo nó từ bảng điều khiển dành cho nhà phát triển?
dnuske

Hóa ra một số phiên bản của chrome (hoặc crom) không cho phép insertRule trên chỉ mục 0. Đây là cách khắc phục: styleSheet.insertRule (selector + "{" + style + "}", styleSheet.cssRules.length);
dnuske

1
@dnuske Mình gặp phải vấn đề tương tự. nó chỉ ra rằng styleSheet.cssRules ước tính là null. cách khắc phục tôi đã sử dụng là tạo một biến mới var styleSheetLength = styleSheet.cssRules ? styleSheet.cssRules.length : 0và thay thế cách sử dụng của nó qua việc thực hiện chức năng.
Raj Nathani

27

Câu trả lời ngắn, đây là tương thích "trên tất cả các trình duyệt" (cụ thể là 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;");

Và bit cuối cùng này áp dụng lớp cho một phần tử:

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

Đây cũng là một trang thử nghiệm nhỏ: https://gist.github.com/shadybones/9816763

Điểm mấu chốt là thực tế là các thành phần kiểu có thuộc tính "styleSheet" / "sheet" mà bạn có thể sử dụng để thêm / xóa quy tắc.


Vì vậy, điều này tạo ra một yếu tố "phong cách" mới mỗi sáng tạo lớp? Vì vậy, nếu tôi đã tạo hơn 1000 lớp trong một vòng lặp for dựa trên dữ liệu, điều này có cần áp dụng document.head.appendChild 1000 lần không?
bluejayke

đối với tôi trong chrome style.sheet và style.styleSheet không tồn tại
bluejayke 11/2/19


7

YUI cho đến nay là tiện ích bản định kiểu tốt nhất mà tôi đã thấy ngoài kia. Tôi khuyến khích bạn kiểm tra nó, nhưng đây là một hương vị:

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

Rõ ràng có những cách đơn giản hơn nhiều để thay đổi phong cách một cách nhanh chóng, chẳng hạn như những cách được đề xuất ở đây. Nếu chúng có ý nghĩa cho vấn đề của bạn, chúng có thể là tốt nhất, nhưng chắc chắn có lý do tại sao sửa đổi css là một giải pháp tốt hơn. Trường hợp rõ ràng nhất là khi bạn cần sửa đổi một số lượng lớn các yếu tố. Trường hợp quan trọng khác là nếu bạn cần thay đổi phong cách của mình để liên quan đến thác. Sử dụng dom để sửa đổi một phần tử sẽ luôn có mức độ ưu tiên cao hơn. Đây là cách tiếp cận búa tạ và tương đương với việc sử dụng thuộc tính style trực tiếp trên phần tử html. Đó không phải lúc nào cũng là hiệu quả mong muốn.


5

Kể từ IE 9. Bây giờ bạn có thể tải tệp văn bản và đặt thuộc tính style.innerHTML. Vì vậy, về cơ bản bây giờ bạn có thể tải tệp css thông qua ajax (và nhận cuộc gọi lại) và sau đó chỉ cần đặt văn bản bên trong thẻ kiểu như thế này.

Điều này hoạt động trong các trình duyệt khác, không chắc chắn bao xa. Nhưng miễn là bạn không cần hỗ trợ IE8 thì nó sẽ hoạt động.

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

và sau đó bạn có thể yêu cầu nó kéo một tệp bên ngoài như myCss.css

.myClass { background:#F00; }

5

Đây là giải pháp của Vishwanath hơi viết lại với các bình luận:

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

Một dự án thú vị có thể giúp bạn thực hiện nhiệm vụ của mình là JSS .

JSS là một sự trừu tượng hóa tốt hơn so với CSS. Nó sử dụng JavaScript như một ngôn ngữ để mô tả các phong cách theo cách khai báo và duy trì. Nó là một trình biên dịch JS sang CSS hiệu suất cao, hoạt động trong thời gian chạy trong trình duyệt và phía máy chủ.

Thư viện JSS cho phép bạn tiêm vào phần DOM / head bằng cách sử dụng .attach()chức năng.

Thay thế phiên bản trực tuyến để đánh giá.

Thông tin thêm về JSS .

Một ví dụ:

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

Sử dụng google đóng cửa:

bạn chỉ có thể sử dụng mô-đun ccsom:

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

Mã javascript cố gắng trở thành trình duyệt chéo khi đặt nút css vào đầu tài liệu.


3

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

Một tùy chọn để tự động tạo và cập nhật lớp CSS trong JavaScript:

  • Sử dụng phần tử kiểu để tạo phần CSS
  • Sử dụng ID cho thành phần kiểu để chúng ta có thể cập nhật
    lớp 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)

1

Nhìn qua các câu trả lời và thiếu rõ ràng và thẳng thắn nhất: sử dụng document.write() để viết ra một đoạn CSS bạn cần.

Dưới đây là một ví dụ (xem nó trên 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>

Điều này tốt trừ khi bạn cần tạo quy tắc CSS sau khi tải trang hoặc đang sử dụng 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);

Điều gì xảy ra nếu không có bản định kiểu hiện tại trên tài liệu
bluejayke

1

Đây là giải pháp mô-đun của tôi:

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

Về cơ bản, bất cứ nơi nào trong mã của bạn làm :
addNewStyle('body', 'color: ' + color1);, nơi color1được xác định biến.

Khi bạn muốn "đăng" tệp CSS hiện tại bạn chỉ cần làm submitNewStyle(),
và sau đó bạn vẫn có thể thêm CSS sau này.

Nếu bạn muốn thêm nó bằng "truy vấn phương tiện", bạn có tùy chọn.
Sau khi "thêm NewStyles", bạn chỉ cần sử dụng submitNewStyleWithMedia('min-width: 1280px');.


Nó khá hữu ích cho trường hợp sử dụng của tôi, vì tôi đã thay đổi CSS của trang web công cộng (không phải của tôi) theo thời gian hiện tại. Tôi gửi một tệp CSS trước khi sử dụng các tập lệnh "hoạt động" và phần còn lại sau đó (làm cho trang web trông giống như trước khi truy cập các phần tử thông qua querySelector).


Tôi sẽ thử cái này hôm nay. Sẽ cho bạn biết làm thế nào điều này hoạt động trong trường hợp sử dụng của tôi. Ngón tay đan chéo !!!!
lopezdp

0

Vì lợi ích của người tìm kiếm; nếu bạn đang sử dụng jQuery, bạn có thể làm như sau:

var currentOverride = $('#customoverridestyles');

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

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

Rõ ràng bạn có thể thay đổi css bên trong thành bất cứ điều gì bạn muốn.

Đánh giá cao một số người thích JavaScript thuần túy, nhưng nó hoạt động và khá mạnh mẽ cho các kiểu viết / ghi đè một cách linh hoạt.


0

Tôi đã xem qua một số câu trả lời ở đây và tôi không thể tìm thấy bất cứ điều gì tự động thêm biểu định kiểu mới nếu không có, và nếu không chỉ sửa đổi một kiểu hiện có chứa kiểu cần thiết, vì vậy tôi đã tạo một hàm mới ( nên hoạt động trên tất cả các trình duyệt, mặc dù chưa được thử nghiệm, sử dụng addRule và bên cạnh đó chỉ có JavaScript gốc cơ bản, hãy cho tôi biết nếu nó hoạt động):

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

};  

sau đó chỉ cần thêm 2 hàm trợ giúp này vào bên trong hàm trên hoặc bất kỳ nơi nào khác:

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

(lưu ý rằng trong cả hai chúng tôi đều sử dụng vòng lặp for thay vì .filter, vì các lớp danh sách kiểu / quy tắc CSS chỉ có thuộc tính độ dài và không có phương thức .filter.)

Sau đó, để gọi nó:

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

Hãy cho tôi biết nếu nó hoạt động cho trình duyệt của bạn hoặc đưa ra lỗi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.