Add Rules to Stylesheets with JavaScript

Ngày nay chúng ta đang sử dụng rất nhiều JavaScript trong các ứng dụng web và chúng ta đang tìm kiếm các cách khác nhau để cho ứng dụng web chạy nhanh hơn nữa. Chúng ta sử dụng event delegation để việc bắt sự kiện đem lại hiệu quả hơn, chúng ta sử dụng function debouncing để giới hạn số lần sử dụng phương thức JavaScript loaders để chỉ tải những resource mà chúng ta cần,..vv..Một cách khác chúng ta có thể làm để tăng hiệu năng các trang là tự động thêm và xóa trực tiếp style thay vì liên tục truy vấn những phần tử DOM và thêm vào style. Và sau đây là cách chúng ta sẽ thực hiện:

Lấy ra Stylesheet

Trong Stylesheet, bạn có thể thêm bất kỳ rules nào tùy thuộc vào bạn. Nếu bạn đã định nghĩa stylesheet rõ ràng, bạn có thể thêm một ID vào LINK hoặc phần tử STYLE ở trong trang HTML và lấy ra được đối tượng CSSStyleSheet bở mối liên hệ với thuộc tính phần tử sheet. Stylesheets có thể được tìm thấy trong đối tượng document.styleSheets:

var sheets = document.styleSheets; // trả về một Array-like StyleSheetList

/*
Returns:  

StyleSheetList {0: CSSStyleSheet, 1: CSSStyleSheet, 2: CSSStyleSheet, 3: CSSStyleSheet, 4: CSSStyleSheet, 5: CSSStyleSheet, 6: CSSStyleSheet, 7: CSSStyleSheet, 8: CSSStyleSheet, 9: CSSStyleSheet, 10: CSSStyleSheet, 11: CSSStyleSheet, 12: CSSStyleSheet, 13: CSSStyleSheet, 14: CSSStyleSheet, 15: CSSStyleSheet, length: 16, item: function}
*/

//Lấy phần tử đầu tiên
var sheet = document.styleSheets[0];

Một lưu ý quan trọng về media của stylesheet là bạn không biết chắc chắn về các rule bạn có thể thêm vào thì bạn có thể in ra trên màn hình bằng lệnh console.log. Một đối tượng CSSStyleSheet sẽ có các thông tin thuộc tính cần thiết cho bạn:

// Lấy thông tin về stylesheet đầu tiên
console.log(document.styleSheets[0]);

/*
Trả về:  

CSSStyleSheet
	cssRules: CSSRuleList
	disabled: false
	href: "https://davidwalsh.name/somesheet.css"
	media: MediaList
	ownerNode: link
	ownerRule: null
	parentStyleSheet: null
	rules: CSSRuleList
	title: null
	type: "text/css"
*/

// Lấy media type
console.log(document.styleSheets[0].media.mediaText)
/*
Trả về:
	tất cả hoặc in ra hoặc bất kỳ media được sử dụng cho stylesheet
*/

Trong bất kỳ trường hợp nào, có nhiều cách để lấy một stylesheet để thêm vào các rule

Tạo ra một stylesheet mới

Trong một số trường hợp, cách tốt nhất bạn nên tạo một phần tử style mới cho các rule động của bạn. Điều này khá dễ để thực hiện

var sheet = (function() {
	// Tạo ra  <style> tag
	var style = document.createElement("style");

	// Thêm một media hoặc media query tại đây nếu bạn muốn
	style.setAttribute("media", "screen")
	style.setAttribute("media", "only screen and (max-width : 1024px)")

	// WebKit hack:
	style.appendChild(document.createTextNode(""));

	// Thêm phần tử style vào thẻ head
	document.head.appendChild(style);

	return style.sheet;
})();

Chèn vào các rule

Stylesheet có một phương thức insertRule (nhưng không hỗ trợ trên các phiên bản IE cũ) để thêm vào các rule theo một chuẩn nhất định. Phương thức insertRule yêu cầu bạn viết toàn bộ rule CSS giống như trong stylesheet:

sheet.insertRule("header { float: left; opacity: 0.8; }", 1);

phương thức này có vẻ hơi ugly so với một API javascript nhưng đó là cách nó hoạt động. Đối số thứ hai, index đại diện cho độ ưu tiên của việc chèn vào rule. Điều này hoàn toàn hữu ích khi bạn chèn vào cùng một rule/code. Mặc định index có giá trị là -1 và đây cũng là giá trị thấp nhất của index. Để tăng có thể kiểm soát tốt hơn, bạn có thể thêm important! vào các rule để tránh những rắc rối với index.

Thêm vào các rule - addRule không theo chuẩn

Đối tượng CSSStyleSheet có phương thức addRule cho phép bạn đăng ký rule bên trong stylesheet. Phương thức addRule chấp nhận ba đối số: thứ nhất là selector, thứ hai là mã CSS cho rule và cuối cùng là thứ tự ưu tiên index (để xác định độ ưu tiên khi lựa chọn cùng một selector)

sheet.addRule("#myList li", "float: left; background: red !important;", 1);

addRule sẽ trả về -1 nếu không được thêm vào stylesheet.

Thêm vào rule không gây ra lỗi

Không phải trình dhuyệt nào cũng hỗ trợ phương thức insertRule, cách tốt nhất là tạo ra một function để thực hiện việc thêm vào rule. Đây là function chúng ta cần:

function addCSSRule(sheet, selector, rules, index) {
	if("insertRule" in sheet) {
		sheet.insertRule(selector + "{" + rules + "}", index);
	}
	else if("addRule" in sheet) {
		sheet.addRule(selector, rules, index);
	}
}

// Cách gọi đến
addCSSRule(document.styleSheets[0], "header", "float: left");

Nếu bạn vẫn lo lắng về biến style trong ứng dụng của bạn thì bạn có thể bọc code trong khối try{}catch(e){}

Thêm vào rule của các Media query

Media query có thể được thêm vào bằng phương thức insertRule như đã nói ở trên

sheet.insertRule("@media only screen and (max-width : 1140px) { header { display: none; } }");

Kết luận

Rất mong nhận được đóng góp của các bạn đọc để bài viết của mình có thể hoàn thiện hơn Bài viết này mình có tham khảo tại nguồn https://davidwalsh.name/add-rules-stylesheets