Đặt quy tắc giả lớp CSS từ JavaScript


125

Tôi đang tìm cách thay đổi các quy tắc CSS cho các bộ chọn lớp giả (chẳng hạn như: link ,: hover, v.v.) từ JavaScript.

Vì vậy, một sự tương tự của mã CSS: a:hover { color: red } trong JS.

Tôi không thể tìm thấy câu trả lời ở bất cứ nơi nào khác; nếu bất cứ ai biết rằng đây là điều mà các trình duyệt không hỗ trợ, đó cũng sẽ là một kết quả hữu ích.

Câu trả lời:


191

Bạn không thể tạo kiểu giả lớp trên một thành phần cụ thể, giống như cách bạn không thể có lớp giả trong thuộc tính kiểu style = "..." (vì không có bộ chọn).

Bạn có thể làm điều đó bằng cách thay đổi biểu định kiểu, ví dụ bằng cách thêm quy tắc:

#elid:hover { background: red; }

giả sử mỗi phần tử bạn muốn tác động có một ID duy nhất để cho phép nó được chọn.

Về lý thuyết, tài liệu bạn muốn là http://www.w3.org/TR/DOM-Level-2-Style/Overview.html có nghĩa là bạn có thể (được cung cấp một biểu định kiểu được nhúng hoặc liên kết trước đó) bằng cú pháp như:

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

IE, tất nhiên, yêu cầu cú pháp riêng của nó:

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

Các trình duyệt cũ và nhỏ hơn có thể không hỗ trợ cú pháp. Kiểu định dạng động hiếm khi được thực hiện bởi vì nó khá khó chịu để làm đúng, hiếm khi cần thiết và rắc rối trong lịch sử.


32
Tại sao điều này không được chọn làm câu trả lời?
SZH


2
Firefox: "Lỗi: Hoạt động không an toàn."
8128

@fluteflute hoạt động được coi là không an toàn nếu bạn đang cố thao túng một tệp CSS từ một tên miền khác (tôi đoán đó là một loại điều chính sách cùng nguồn gốc). Xấu hổ! Chức năng đơn giản để kiểm tra tuân thủ chính sách cùng nguồn gốc: 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
Thao tác với biểu định kiểu chỉ để áp dụng kiểu cho một thành phần cụ thể không được khuyến nghị vì nó khiến trình duyệt hiển thị lại toàn bộ tài liệu mỗi khi thay đổi biểu định kiểu. stubbornella.org/content/2009/03/27/ trộm
Julian Ewald

29

Tôi đã tập hợp một thư viện nhỏ cho việc này vì tôi nghĩ có những trường hợp sử dụng hợp lệ để thao tác các bảng định kiểu trong JS. Lý do là:

  • Cài đặt kiểu phải được tính toán hoặc truy xuất - ví dụ: đặt kích thước phông chữ ưa thích của người dùng từ cookie.
  • Đặt các kiểu hành vi (không thẩm mỹ), đặc biệt là cho các nhà phát triển widget / plugin UI. Tab, băng chuyền, v.v., thường yêu cầu một số CSS cơ bản để hoạt động - không nên yêu cầu biểu định kiểu cho chức năng cốt lõi.
  • Tốt hơn các kiểu nội tuyến vì các quy tắc CSS áp dụng cho tất cả các yếu tố hiện tại và tương lai và không làm lộn xộn HTML khi xem trong Công cụ dành cho nhà phát triển / Firebird.

17

Một chức năng để đối phó với các công cụ trình duyệt chéo:

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

7

Chỉ cần đặt css trong một chuỗi mẫu.

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

Sau đó tạo một phần tử kiểu và đặt chuỗi trong thẻ kiểu và đính kèm nó vào tài liệu.

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

Tính cụ thể sẽ chăm sóc phần còn lại. Sau đó, bạn có thể loại bỏ và thêm các thẻ kiểu động. Đây là một thay thế đơn giản cho các thư viện và gây rối với mảng bản định kiểu trong DOM. Chúc mừng mã hóa!


insertAdjacentElementyêu cầu 2 đối số trong các trình duyệt chính (Chrome, Firefox, Edge), lần đầu tiên thiết lập vị trí liên quan đến yếu tố tham chiếu ( xem tại đây ). Đây có phải là một sự thay đổi gần đây? (Đã thêm 'trước khi trả lời' vào câu trả lời).
sụp đổ

6

Thủ thuật của tôi là sử dụng bộ chọn thuộc tính. Các thuộc tính dễ dàng hơn để thiết lập bằng 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)"> ...  

4
Giải pháp này sử dụng jQuery - giới thiệu một phụ thuộc kích thước của jQuery cho một cái gì đó đơn giản như thế này, khi người hỏi yêu cầu Javascript thuần túy, là xấu.
Tom Ashworth

Mặc dù tất cả các trang web hiện nay đều sử dụng jquery, tôi sẽ sửa đổi nó để sử dụng javascript thuần túy.
Sergio Abreu

1
Và chính xác làm thế nào để phương thức này thay đổi các thuộc tính CSS của. Class [đặc biệt]: sau phần tử giả, như, màu nền hoặc bất cứ thứ gì khác?
andreszs

5

Có một sự thay thế khác. Thay vì thao tác trực tiếp các lớp giả, hãy tạo các lớp thực mô hình hóa các thứ giống nhau, như lớp "di chuột" hoặc lớp "đã truy cập". Phong cách các lớp với "." cú pháp và sau đó bạn có thể sử dụng JavaScript để thêm hoặc xóa các lớp khỏi một phần tử khi sự kiện thích hợp kích hoạt.


2
Điều đó không làm việc cho: trước và sau các lớp giả.
jbyrd

Và điều đó không áp dụng để thay đổi hình nền với giá trị được truy xuất thông qua AJAX.
andreszs

1
@jbyrd, :before& :afterlà các phần tử giả, không phải lớp.
Roy Ling

@roomme - vâng, cảm ơn đã sửa! Dường như không thể chỉnh sửa bình luận của tôi.
jbyrd

4

Thay vì trực tiếp đặt quy tắc lớp giả bằng javascript, bạn có thể đặt quy tắc khác nhau trong các tệp CSS khác nhau, sau đó sử dụng Javascript để tắt một biểu định kiểu và bật một biểu định kiểu khác. Một phương thức được mô tả tại A List Apart (qv. Để biết thêm chi tiết).

Thiết lập các tệp CSS như,

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

Và sau đó chuyển đổi giữa chúng bằng cách sử dụng 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;
     }
   }
}

Điều gì xảy ra nếu bạn cần thay đổi thực tế lớp thành giá trị được truy xuất theo yêu cầu AJAX? Bạn không thể tạo tệp CSS ngay bây giờ ...
andreszs

2

Như đã nêu, đây không phải là thứ mà trình duyệt hỗ trợ.

Nếu bạn không tự động tạo ra các kiểu (tức là kéo chúng ra khỏi cơ sở dữ liệu hoặc thứ gì đó), bạn sẽ có thể giải quyết vấn đề này bằng cách thêm một lớp vào phần thân của trang.

Các css sẽ trông giống như:

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

Và javascript để thay đổi điều này sẽ là một cái gì đó như:

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

document.body.className += " theme1";  

Vì tò mò, element.classList.addkhông được hỗ trợ tốt? Tôi cứ thấy mọi người làm element.className +=.
Joel Cornett

2
classList là một tính năng mới hơn và có vẻ như nó không được hỗ trợ tốt cho đến gần đây (xem caniuse.com/ classlist )
Nathaniel Reinhart


-1

Trong jquery bạn có thể dễ dàng thiết lập các lớp giả di chuột.

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

-1

đây là một giải pháp bao gồm hai hàm: addCSS class thêm một lớp css mới vào tài liệu và toggleClass bật nó lên

Ví dụ hiển thị thêm thanh cuộn tùy chỉnh vào 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>


-2

Nếu bạn sử dụng REACT, có một thứ gọi là radium . Nó rất hữu ích ở đây:

  • Thêm trình xử lý vào đạo cụ nếu các kiểu tương tác được chỉ định, ví dụ: onMouseNhập cho: di chuột, gói trình xử lý hiện có nếu cần

  • Nếu bất kỳ trình xử lý nào được kích hoạt, ví dụ bằng cách di chuột, Radium sẽ gọi setState để cập nhật trường dành riêng cho Radium trên đối tượng trạng thái thành phần

  • Khi kết xuất lại, giải quyết mọi kiểu tương tác được áp dụng, ví dụ: di chuột, bằng cách tra cứu khóa của phần tử hoặc tham chiếu ở trạng thái dành riêng cho Radium

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.