Phiên bản ngắn ngày 12 tháng 4 năm 2017
Kẻ thách thức xuất hiện.
var getMatchedCSSRules = (el, css = el.ownerDocument.styleSheets) =>
[].concat(...[...css].map(s => [...s.cssRules||[]]))
.filter(r => el.matches(r.selectorText));
Line /* 1 */
xây dựng một mảng phẳng của tất cả các quy tắc.
Dòng /* 2 */
loại bỏ các quy tắc không phù hợp.
Dựa trên chức năngcss(el)
của @SB trên cùng một trang.
ví dụ 1
var div = iframedoc.querySelector("#myelement");
var rules = getMatchedCSSRules(div, iframedoc.styleSheets);
console.log(rules[0].parentStyleSheet.ownerNode, rules[0].cssText);
Ví dụ 2
var getMatchedCSSRules = (el, css = el.ownerDocument.styleSheets) =>
[].concat(...[...css].map(s => [...s.cssRules||[]]))
.filter(r => el.matches(r.selectorText));
function Go(big,show) {
var r = getMatchedCSSRules(big);
PrintInfo:
var f = (dd,rr,ee="\n") => dd + rr.cssText.slice(0,50) + ee;
show.value += "--------------- Rules: ----------------\n";
show.value += f("Rule 1: ", r[0]);
show.value += f("Rule 2: ", r[1]);
show.value += f("Inline: ", big.style);
show.value += f("Computed: ", getComputedStyle(big), "(…)\n");
show.value += "-------- Style element (HTML): --------\n";
show.value += r[0].parentStyleSheet.ownerNode.outerHTML;
}
Go(...document.querySelectorAll("#big,#show"));
.red {color: red;}
#big {font-size: 20px;}
<h3 id="big" class="red" style="margin: 0">Lorem ipsum</h3>
<textarea id="show" cols="70" rows="10"></textarea>
Thiếu sót
- Không xử lý phương tiện truyền thông, không
@import
, @media
.
- Không có quyền truy cập vào các kiểu được tải từ các bảng định kiểu miền chéo.
- Không phân loại theo bộ chọn “tính cụ thể” (thứ tự quan trọng).
- Không có phong cách kế thừa từ cha mẹ.
- Có thể không hoạt động với các trình duyệt cũ hoặc thô sơ.
- Không chắc nó đối phó với lớp giả và bộ chọn giả như thế nào nhưng có vẻ ổn.
Có lẽ một ngày nào đó tôi sẽ giải quyết những thiếu sót này.
Phiên bản dài ngày 12 tháng 8 năm 2018
Đây là cách triển khai toàn diện hơn nhiều được lấy từ trang GitHub của ai đó
(được tách từ mã gốc này , thông qua Bugzilla ). Được viết cho Gecko và IE, nhưng được cho là cũng hoạt động với Blink.
Ngày 4 tháng 5 năm 2017: Máy tính độ cụ thể đã có một số lỗi nghiêm trọng mà tôi hiện đã sửa. (Tôi không thể thông báo cho các tác giả vì tôi không có tài khoản GitHub.)
Ngày 12 tháng 8 năm 2018: Các bản cập nhật Chrome gần đây dường như đã tách phạm vi đối tượng ( this
) khỏi các phương thức được gán cho các biến độc lập. Do đó, lệnh gọi matcher(selector)
đã ngừng hoạt động. Thay thế nó bằng matcher.call(el, selector)
đã giải quyết nó.
if (typeof window.getMatchedCSSRules !== 'function') {
var ELEMENT_RE = /[\w-]+/g,
ID_RE = /#[\w-]+/g,
CLASS_RE = /\.[\w-]+/g,
ATTR_RE = /\[[^\]]+\]/g,
PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g,
PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g;
function toArray(list) {
return [].slice.call(list);
}
function getSheetRules(stylesheet) {
var sheet_media = stylesheet.media && stylesheet.media.mediaText;
if ( stylesheet.disabled ) return [];
if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return [];
return toArray(stylesheet.cssRules);
}
function _find(string, re) {
var matches = string.match(re);
return matches ? matches.length : 0;
}
function calculateScore(selector) {
var score = [0,0,0],
parts = selector.split(' '),
part, match;
while (part = parts.shift(), typeof part == 'string') {
match = _find(part, PSEUDO_ELEMENTS_RE);
score[2] += match;
match && (part = part.replace(PSEUDO_ELEMENTS_RE, ''));
match = _find(part, PSEUDO_CLASSES_RE);
score[1] += match;
match && (part = part.replace(PSEUDO_CLASSES_RE, ''));
match = _find(part, ATTR_RE);
score[1] += match;
match && (part = part.replace(ATTR_RE, ''));
match = _find(part, ID_RE);
score[0] += match;
match && (part = part.replace(ID_RE, ''));
match = _find(part, CLASS_RE);
score[1] += match;
match && (part = part.replace(CLASS_RE, ''));
score[2] += _find(part, ELEMENT_RE);
}
return parseInt(score.join(''), 10);
}
function getSpecificityScore(element, selector_text) {
var selectors = selector_text.split(','),
selector, score, result = 0;
while (selector = selectors.shift()) {
if (matchesSelector(element, selector)) {
score = calculateScore(selector);
result = score > result ? score : result;
}
}
return result;
}
function sortBySpecificity(element, rules) {
function compareSpecificity (a, b) {
return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText);
}
return rules.sort(compareSpecificity);
}
function matchesSelector(el, selector) {
var matcher = el.matchesSelector || el.mozMatchesSelector ||
el.webkitMatchesSelector || el.oMatchesSelector || el.msMatchesSelector;
return matcher.call(el, selector);
}
window.getMatchedCSSRules = function (element ) {
var style_sheets, sheet, sheet_media,
rules, rule,
result = [];
style_sheets = toArray(window.document.styleSheets);
while (sheet = style_sheets.shift()) {
rules = getSheetRules(sheet);
while (rule = rules.shift()) {
if (rule.styleSheet) {
rules = getSheetRules(rule.styleSheet).concat(rules);
continue;
}
else if (rule.media) {
rules = getSheetRules(rule).concat(rules);
continue
}
if (matchesSelector(element, rule.selectorText)) {
result.push(rule);
}
}
}
return sortBySpecificity(element, result);
};
}
Đã sửa lỗi
= match
→ += match
return re ? re.length : 0;
→ return matches ? matches.length : 0;
_matchesSelector(element, selector)
→ matchesSelector(element, selector)
matcher(selector)
→ matcher.call(el, selector)