ค้นหากฎ CSS ทั้งหมดที่ใช้กับองค์ประกอบ


87

เครื่องมือ / API จำนวนมากมีวิธีการเลือกองค์ประกอบของคลาสหรือ ID เฉพาะ นอกจากนี้ยังสามารถตรวจสอบสไตล์ชีทดิบที่เบราว์เซอร์โหลดได้อีกด้วย

อย่างไรก็ตามสำหรับเบราว์เซอร์ในการแสดงผลองค์ประกอบพวกเขาจะรวบรวมกฎ CSS ทั้งหมด (อาจมาจากไฟล์สไตล์ชีตอื่น) และนำไปใช้กับองค์ประกอบ นี่คือสิ่งที่คุณเห็นจาก Firebug หรือ WebKit Inspector - โครงสร้างการสืบทอด CSS แบบเต็มสำหรับองค์ประกอบ

ฉันจะสร้างคุณลักษณะนี้ใหม่ใน JavaScript บริสุทธิ์โดยไม่ต้องใช้ปลั๊กอินเบราว์เซอร์เพิ่มเติมได้อย่างไร

บางทีตัวอย่างอาจให้ความกระจ่างสำหรับสิ่งที่ฉันกำลังมองหา:

<style type="text/css">
    p { color :red; }
    #description { font-size: 20px; }
</style>

<p id="description">Lorem ipsum</p>

ที่นี่องค์ประกอบคำอธิบาย p # มีการใช้กฎ CSS สองกฎ: สีแดงและขนาดตัวอักษร 20 px

ฉันต้องการค้นหาแหล่งที่มาจากที่มาของกฎ CSS ที่คำนวณเหล่านี้ (สีมาจากกฎ p เป็นต้น)



ดูในเบราว์เซอร์และใช้เครื่องมือสำหรับนักพัฒนาเบราว์เซอร์ (เช่นแท็บองค์ประกอบใน Chrome)?
Ronnie Royston

คำตอบ:


77

เนื่องจากคำถามนี้ยังไม่มีคำตอบที่ใช้งานร่วมกับข้ามเบราว์เซอร์ได้ง่าย (ไม่ใช่ไลบรารี) ฉันจะพยายามให้คำตอบ:

function css(el) {
    var sheets = document.styleSheets, ret = [];
    el.matches = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector 
        || el.msMatchesSelector || el.oMatchesSelector;
    for (var i in sheets) {
        var rules = sheets[i].rules || sheets[i].cssRules;
        for (var r in rules) {
            if (el.matches(rules[r].selectorText)) {
                ret.push(rules[r].cssText);
            }
        }
    }
    return ret;
}

JSFiddle: http://jsfiddle.net/HP326/6/

การโทรcss(document.getElementById('elementId'))จะส่งคืนอาร์เรย์พร้อมองค์ประกอบสำหรับกฎ CSS แต่ละรายการที่ตรงกับองค์ประกอบที่ส่ง หากคุณต้องการทราบข้อมูลเฉพาะเพิ่มเติมเกี่ยวกับกฎแต่ละข้อโปรดดูเอกสารออบเจ็กต์ CSSRule


1
a.matchesถูกกำหนดไว้ในบรรทัดนี้: a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector. หมายความว่าหากมีเมธอด (มาตรฐาน) "ตรงกัน" สำหรับโหนด DOM ก็จะใช้วิธีนั้นมิฉะนั้นจะพยายามใช้ Webkit เฉพาะ (webkitMatchesSelector) จากนั้นจึงใช้ Mozilla, Microsoft และ Opera คุณสามารถอ่านเพิ่มเติมได้ที่นี่: developer.mozilla.org/en/docs/Web/API/Element/matches
SB

3
น่าเสียดายที่ฉันคิดว่าทางเลือกนี้ตรวจไม่พบกฎ CSS ทั้งหมดที่เรียงซ้อนจากองค์ประกอบหลักในกลุ่มย่อย Fiddle: jsfiddle.net/t554xo2Lในกรณีนี้กฎ UL (ซึ่งใช้กับองค์ประกอบ) จะไม่ตรงกับif (a.matches(rules[r].selectorText))เงื่อนไขการป้องกัน
funforums

2
ฉันไม่เคยอ้างว่ามันอยู่ในรายการ / สืบทอด / กฎ CSS - ทั้งหมดที่ทำคือแสดงรายการกฎ CSS ที่ตรงกับองค์ประกอบที่ส่งผ่าน หากคุณต้องการรับกฎที่สืบทอดมาสำหรับองค์ประกอบนั้นด้วยคุณอาจต้องสำรวจ DOM ขึ้นไปและเรียกcss()ใช้องค์ประกอบหลักแต่ละองค์ประกอบ
SB

2
ฉันรู้ว่า :-) ฉันแค่อยากจะชี้ให้เห็นสิ่งนี้เนื่องจากคนที่สามารถดูคำถามนี้อาจคิดว่ามันได้รับ 'กฎ css ทั้งหมดที่ใช้กับองค์ประกอบ' ตามที่ชื่อของคำถามกล่าวซึ่งไม่ใช่กรณีนี้ .
funforums

3
หากคุณต้องการให้กฎทั้งหมดใช้กับองค์ประกอบในปัจจุบันรวมถึงกฎที่สืบทอดมาคุณควรใช้ getComputedStyle ด้วยเหตุนี้ฉันคิดว่าคำตอบนี้ถูกต้องและไม่ถูกต้องที่จะไม่รวมสไตล์ที่สืบทอดมาจากผู้ปกครอง (เช่นสีข้อความที่กำหนดให้กับผู้ปกครองเป็นต้น) สิ่งที่ไม่รวมเป็นกฎที่ใช้กับการสืบค้นสื่ออย่างมีเงื่อนไข
tremby

24

แก้ไข: คำตอบนี้จะเลิกในขณะนี้และไม่ทำงานใน Chrome 64+ ออกจากบริบททางประวัติศาสตร์ ในความเป็นจริงแล้วรายงานข้อผิดพลาดจะเชื่อมโยงกลับไปที่คำถามนี้เพื่อหาทางเลือกในการใช้สิ่งนี้


ดูเหมือนว่าฉันจะสามารถตอบคำถามของตัวเองได้หลังจากการค้นคว้าอีกชั่วโมง

ง่ายๆดังนี้:

window.getMatchedCSSRules(document.getElementById("description"))

(ทำงานได้ใน WebKit / Chrome อาจเป็นไปได้อื่น ๆ ด้วย)


4
สิ่งนี้ไม่ได้มีประโยชน์มากนักหากได้รับการสนับสนุนโดย chrome เท่านั้น จะใช้ได้น้อยกว่า 5% ของผู้เข้าชมทั้งหมด (ขึ้นอยู่กับข้อมูลประชากร)
Tomasi

5
@diamandiev: ณ เดือนมิถุนายน 2555 ส่วนแบ่งการใช้งาน Chrome เพิ่มขึ้นเป็น 32% (และสูงกว่าการใช้งาน IE เล็กน้อย!) gs.statcounter.com
Roy Tinker

6
getMatchedCSSRules ไม่แสดงสไตล์สุดท้ายที่ใช้กับองค์ประกอบ ส่งคืนอาร์เรย์ของวัตถุ CSSStyleRule ทั้งหมดที่ใช้ตามลำดับที่ปรากฏ หากคุณออกแบบเว็บแบบตอบสนองผ่านคิวรีสื่อ CSS หรือโหลดมากกว่าหนึ่งสไตล์ชีต (เช่นเดียวกับ IE) คุณยังคงต้องวนซ้ำแต่ละสไตล์ที่ส่งคืนและคำนวณความจำเพาะของ css สำหรับแต่ละกฎ จากนั้นคำนวณกฎสุดท้ายที่ใช้ คุณต้องสร้างซ้ำสิ่งที่เบราว์เซอร์ทำตามธรรมชาติ เพื่อพิสูจน์สิ่งนี้ในตัวอย่างของคุณให้นำหน้า "p {color: blue! important}" ไปที่จุดเริ่มต้นของการประกาศสไตล์ของคุณ
mrbinky3000

24
นี้จะเลิกตอนนี้ใน Chrome 41 ดูcode.google.com/p/chromium/issues/detail?id=437569#c2
Daniel Darabos

5
ในที่สุดสิ่งนี้ก็ถูกลบออกใน Chrome 63 (โพสต์บล็อกอย่างเป็นทางการ - ซึ่งชี้กลับไปที่คำถามนี้)
brichins

20

ฉบับย่อ12 เมษายน 2560

ชาเลนเจอร์ปรากฏขึ้น

var getMatchedCSSRules = (el, css = el.ownerDocument.styleSheets) => 
    [].concat(...[...css].map(s => [...s.cssRules||[]])) /* 1 */
    .filter(r => el.matches(r.selectorText));            /* 2 */

Line /* 1 */สร้างอาร์เรย์แบบแบนของกฎทั้งหมด
ไลน์/* 2 */ละทิ้งกฎที่ไม่ตรงกัน

ขึ้นอยู่กับฟังก์ชันcss(el)โดย @SB ในหน้าเดียวกัน

ตัวอย่าง 1

var div = iframedoc.querySelector("#myelement");
var rules = getMatchedCSSRules(div, iframedoc.styleSheets);
console.log(rules[0].parentStyleSheet.ownerNode, rules[0].cssText);

ตัวอย่าง 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>

ข้อบกพร่อง

  • ไม่มีการจัดการสื่อไม่@import,@media ,
  • ไม่มีการเข้าถึงสไตล์ที่โหลดจากสไตล์ชีตข้ามโดเมน
  • ไม่มีการจัดเรียงตามตัวเลือก "ความจำเพาะ" (ลำดับความสำคัญ)
  • ไม่มีรูปแบบที่สืบทอดมาจากผู้ปกครอง
  • อาจใช้ไม่ได้กับเบราว์เซอร์เก่าหรือเบราว์เซอร์พื้นฐาน
  • ไม่แน่ใจว่ามันจัดการกับคลาสหลอกและตัวเลือกหลอกได้อย่างไร แต่ดูเหมือนว่าจะไม่เป็นไร

บางทีฉันอาจจะแก้ไขข้อบกพร่องเหล่านี้ในวันหนึ่ง

ฉบับยาว12 สิงหาคม 2561

นี่คือการใช้งานที่ครอบคลุมมากขึ้นซึ่งนำมาจากหน้า GitHub ของใครบางคน (แยกจากรหัสเดิมนี้ผ่านทางBugzilla ) เขียนขึ้นสำหรับ Gecko และ IE แต่มีข่าวลือว่าจะทำงานร่วมกับ Blink

4 พฤษภาคม 2017:เครื่องคำนวณความจำเพาะมีจุดบกพร่องที่สำคัญซึ่งตอนนี้ฉันได้แก้ไขแล้ว (ฉันไม่สามารถแจ้งผู้เขียนได้เนื่องจากฉันไม่มีบัญชี GitHub)

12 สิงหาคม 2018:การอัปเดต Chrome ล่าสุดดูเหมือนว่าจะมีการแยกขอบเขตออบเจ็กต์ ( this) ออกจากวิธีการที่กำหนดให้กับตัวแปรอิสระ ดังนั้นการร้องขอmatcher(selector)จึงหยุดทำงาน การแทนที่โดยmatcher.call(el, selector)ได้แก้ไขแล้ว

// polyfill window.getMatchedCSSRules() in FireFox 6+
if (typeof window.getMatchedCSSRules !== 'function') {
    var ELEMENT_RE = /[\w-]+/g,
            ID_RE = /#[\w-]+/g,
            CLASS_RE = /\.[\w-]+/g,
            ATTR_RE = /\[[^\]]+\]/g,
            // :not() pseudo-class does not add to specificity, but its content does as if it was outside it
            PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g,
            PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g;
        // convert an array-like object to array
        function toArray(list) {
            return [].slice.call(list);
        }

        // handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same
        function getSheetRules(stylesheet) {
            var sheet_media = stylesheet.media && stylesheet.media.mediaText;
            // if this sheet is disabled skip it
            if ( stylesheet.disabled ) return [];
            // if this sheet's media is specified and doesn't match the viewport then skip it
            if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return [];
            // get the style rules of this sheet
            return toArray(stylesheet.cssRules);
        }

        function _find(string, re) {
            var matches = string.match(re);
            return matches ? matches.length : 0;
        }

        // calculates the specificity of a given `selector`
        function calculateScore(selector) {
            var score = [0,0,0],
                parts = selector.split(' '),
                part, match;
            //TODO: clean the ':not' part since the last ELEMENT_RE will pick it up
            while (part = parts.shift(), typeof part == 'string') {
                // find all pseudo-elements
                match = _find(part, PSEUDO_ELEMENTS_RE);
                score[2] += match;
                // and remove them
                match && (part = part.replace(PSEUDO_ELEMENTS_RE, ''));
                // find all pseudo-classes
                match = _find(part, PSEUDO_CLASSES_RE);
                score[1] += match;
                // and remove them
                match && (part = part.replace(PSEUDO_CLASSES_RE, ''));
                // find all attributes
                match = _find(part, ATTR_RE);
                score[1] += match;
                // and remove them
                match && (part = part.replace(ATTR_RE, ''));
                // find all IDs
                match = _find(part, ID_RE);
                score[0] += match;
                // and remove them
                match && (part = part.replace(ID_RE, ''));
                // find all classes
                match = _find(part, CLASS_RE);
                score[1] += match;
                // and remove them
                match && (part = part.replace(CLASS_RE, ''));
                // find all elements
                score[2] += _find(part, ELEMENT_RE);
            }
            return parseInt(score.join(''), 10);
        }

        // returns the heights possible specificity score an element can get from a give rule's selectorText
        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) {
            // comparing function that sorts CSSStyleRules according to specificity of their `selectorText`
            function compareSpecificity (a, b) {
                return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText);
            }

            return rules.sort(compareSpecificity);
        }

        // Find correct matchesSelector impl
        function matchesSelector(el, selector) {
          var matcher = el.matchesSelector || el.mozMatchesSelector || 
              el.webkitMatchesSelector || el.oMatchesSelector || el.msMatchesSelector;
          return matcher.call(el, selector);
        }

        //TODO: not supporting 2nd argument for selecting pseudo elements
        //TODO: not supporting 3rd argument for checking author style sheets only
        window.getMatchedCSSRules = function (element /*, pseudo, author_only*/) {
            var style_sheets, sheet, sheet_media,
                rules, rule,
                result = [];
            // get stylesheets and convert to a regular Array
            style_sheets = toArray(window.document.styleSheets);

            // assuming the browser hands us stylesheets in order of appearance
            // we iterate them from the beginning to follow proper cascade order
            while (sheet = style_sheets.shift()) {
                // get the style rules of this sheet
                rules = getSheetRules(sheet);
                // loop the rules in order of appearance
                while (rule = rules.shift()) {
                    // if this is an @import rule
                    if (rule.styleSheet) {
                        // insert the imported stylesheet's rules at the beginning of this stylesheet's rules
                        rules = getSheetRules(rule.styleSheet).concat(rules);
                        // and skip this rule
                        continue;
                    }
                    // if there's no stylesheet attribute BUT there IS a media attribute it's a media rule
                    else if (rule.media) {
                        // insert the contained rules of this media rule to the beginning of this stylesheet's rules
                        rules = getSheetRules(rule).concat(rules);
                        // and skip it
                        continue
                    }

                    // check if this element matches this rule's selector
                    if (matchesSelector(element, rule.selectorText)) {
                        // push the rule to the results set
                        result.push(rule);
                    }
                }
            }
            // sort according to specificity
            return sortBySpecificity(element, result);
        };
}

แก้ไขข้อบกพร่อง

  • = match+= match
  • return re ? re.length : 0;return matches ? matches.length : 0;
  • _matchesSelector(element, selector)matchesSelector(element, selector)
  • matcher(selector)matcher.call(el, selector)

ใน getSheetRules ฉันต้องเพิ่ม if (stylesheet.cssRules === null) {return []} เพื่อให้มันทำงานให้ฉัน
Gwater17

ทดสอบ "เวอร์ชันยาว" ใช้ได้ผลสำหรับฉัน น่าเสียดายที่ getMatchedCSSRules () ไม่เคยได้รับการกำหนดมาตรฐานโดยเบราว์เซอร์
colin moock

วิธีนี้จัดการตัวเลือกสองตัวที่มีความจำเพาะเหมือนกันเช่น, h1 และ h1, div - ที่ใดควรใช้ตัวเลือกที่ประกาศล่าสุด
Stellan

บางทีเราอาจได้รับแนวคิดในการจัดการกับหลอกที่นี่? github.com/dvtng/jss/blob/master/jss.js
mr1031011

19

ดูห้องสมุดนี้ซึ่งทำตามที่ขอ: http://www.brothercake.com/site/resources/scripts/cssutilities/

มันทำงานในเบราว์เซอร์ที่ทันสมัยทั้งหมดกลับไปที่ IE6 สามารถให้คอลเลกชันกฎและคุณสมบัติเช่น Firebug (อันที่จริงแล้วมันแม่นยำกว่า Firebug) และยังสามารถคำนวณความจำเพาะสัมพัทธ์หรือสัมบูรณ์ของกฎใด ๆ ข้อแม้เดียวคือแม้ว่าจะเข้าใจประเภทสื่อคงที่ แต่ก็ไม่เข้าใจคำค้นหาของสื่อ


โมดูลนี้ยอดเยี่ยมมากหวังว่าจะได้รับความรักจากผู้เขียนมากขึ้น
mr1031011

4

นี่คือคำตอบของ SB ซึ่งส่งคืนกฎการจับคู่ในแบบสอบถามสื่อที่ตรงกัน ฉันได้ลบไฟล์*.rules || *.cssRulesรวมตัวกันและ.matchesเครื่องมือค้นหาการใช้งานแล้ว เพิ่มโพลีฟิลล์หรือเพิ่มเส้นเหล่านั้นกลับเข้าไปหากคุณต้องการ

เวอร์ชันนี้ยังส่งคืนไฟล์ CSSStyleRuleวัตถุแทนข้อความกฎ ฉันคิดว่าสิ่งนี้มีประโยชน์มากกว่าเล็กน้อยเนื่องจากข้อมูลเฉพาะของกฎสามารถตรวจสอบทางโปรแกรมได้ง่ายขึ้นด้วยวิธีนี้

กาแฟ:

getMatchedCSSRules = (element) ->
  sheets = document.styleSheets
  matching = []

  loopRules = (rules) ->
    for rule in rules
      if rule instanceof CSSMediaRule
        if window.matchMedia(rule.conditionText).matches
          loopRules rule.cssRules
      else if rule instanceof CSSStyleRule
        if element.matches rule.selectorText
          matching.push rule
    return

  loopRules sheet.cssRules for sheet in sheets

  return matching

JS:

function getMatchedCSSRules(element) {
  var i, len, matching = [], sheets = document.styleSheets;

  function loopRules(rules) {
    var i, len, rule;

    for (i = 0, len = rules.length; i < len; i++) {
      rule = rules[i];
      if (rule instanceof CSSMediaRule) {
        if (window.matchMedia(rule.conditionText).matches) {
          loopRules(rule.cssRules);
        }
      } else if (rule instanceof CSSStyleRule) {
        if (element.matches(rule.selectorText)) {
          matching.push(rule);
        }
      }
    }
  };

  for (i = 0, len = sheets.length; i < len; i++) {
    loopRules(sheets[i].cssRules);
  }

  return matching;
}

จะเปลี่ยนไปใช้กับเด็กที่ผ่านelementด้วยได้อย่างไร?
Kragalon

2
กรณีการใช้งานของคุณคืออะไร? ฉันไม่เห็นว่าจะมีประโยชน์ตรงไหนเนื่องจากกฎที่ใช้กับเด็กไม่จำเป็นต้องใช้กับผู้ปกครอง คุณจะจบลงด้วยกองกฎโดยไม่มีอะไรเหมือนกันเป็นพิเศษ ถ้าคุณต้องการจริงๆคุณก็สามารถเรียกคืนเด็กและเรียกใช้วิธีนี้สำหรับแต่ละคนและสร้างอาร์เรย์ของผลลัพธ์ทั้งหมด
tremby

ฉันแค่พยายามสร้างcloneNode(true)ฟังก์ชันการทำงาน แต่ด้วยการจัดแต่งทรงผมที่โคลนลึกด้วย
Kragalon

1
เงื่อนไขนี้: if (window.matchMedia (rule.conditionText) .matches) {... } ป้องกันการจับคู่ในกรณีของฉันเนื่องจาก "rule.conditionText" ไม่ได้กำหนด ถ้าไม่มีมันก็ใช้งานได้ คุณสามารถลองและทดสอบนี้ในnews.ycombinator.com "span.pagetop b" มีกฎการสืบค้นสื่อที่ไม่ตรงกับฟังก์ชันของคุณอย่างที่เป็นอยู่
ayal gelles

1
Chrome ไม่สนับสนุนคุณสมบัติ conditionText บนอินสแตนซ์ CSSMediaRule
Macil

3

นี่คือgetMatchedCSSRulesฟังก์ชันเวอร์ชันของฉันที่รองรับการ@mediaสืบค้น

const getMatchedCSSRules = (el) => {
  let rules = [...document.styleSheets]
  rules = rules.filter(({ href }) => !href)
  rules = rules.map((sheet) => [...(sheet.cssRules || sheet.rules || [])].map((rule) => {
    if (rule instanceof CSSStyleRule) {
      return [rule]
    } else if (rule instanceof CSSMediaRule && window.matchMedia(rule.conditionText)) {
      return [...rule.cssRules]
    }
    return []
  }))
  rules = rules.reduce((acc, rules) => acc.concat(...rules), [])
  rules = rules.filter((rule) => el.matches(rule.selectorText))
  rules = rules.map(({ style }) => style)
  return rules
}

1

var GetMatchedCSSRules = (elem, css = document.styleSheets) => Array.from(css)
  .map(s => Array.from(s.cssRules).filter(r => elem.matches(r.selectorText)))
  .reduce((a,b) => a.concat(b));

function Go(paragraph, print) {
  var rules = GetMatchedCSSRules(paragraph);
PrintInfo:
  print.value += "Rule 1: " + rules[0].cssText + "\n";
  print.value += "Rule 2: " + rules[1].cssText + "\n\n";
  print.value += rules[0].parentStyleSheet.ownerNode.outerHTML;
}

Go(document.getElementById("description"), document.getElementById("print"));
p {color: red;}
#description {font-size: 20px;}
<p id="description">Lorem ipsum</p>
<textarea id="print" cols="50" rows="12"></textarea>


3
คำตอบของฉันซ้ำกับเวอร์ชันเก่าอย่างไม่มีจุดหมาย แค่ก่อมลพิษในเพจ สมบูรณ์และรุ่นขึ้นไปวันที่: ที่นี่
7vujy0f0hy

1

เพื่อให้แน่ใจว่า IE9 + ฉันได้เขียนฟังก์ชันที่คำนวณ CSS สำหรับองค์ประกอบที่ร้องขอและลูกของมันและให้ความเป็นไปได้ในการบันทึกลงใน className ใหม่หากจำเป็นในตัวอย่างด้านล่าง

/**
  * @function getElementStyles
  *
  * Computes all CSS for requested HTMLElement and its child nodes and applies to dummy class
  *
  * @param {HTMLElement} element
  * @param {string} className (optional)
  * @param {string} extras (optional)
  * @return {string} CSS Styles
  */
function getElementStyles(element, className, addOnCSS) {
  if (element.nodeType !== 1) {
    return;
  }
  var styles = '';
  var children = element.getElementsByTagName('*');
  className = className || '.' + element.className.replace(/^| /g, '.');
  addOnCSS = addOnCSS || '';
  styles += className + '{' + (window.getComputedStyle(element, null).cssText + addOnCSS) + '}';
  for (var j = 0; j < children.length; j++) {
    if (children[j].className) {
      var childClassName = '.' + children[j].className.replace(/^| /g, '.');
      styles += ' ' + className + '>' + childClassName +
        '{' + window.getComputedStyle(children[j], null).cssText + '}';
    }
  }
  return styles;
}

การใช้งาน

getElementStyles(document.getElementByClassName('.my-class'), '.dummy-class', 'width:100%;opaity:0.5;transform:scale(1.5);');

2
1.คุณสามารถแทนที่ทั้งย่อยโดยเพียงแค่computeStyles el => getComputedStyle(el).cssTextหลักฐาน: ซอ . 2. '.' + element.classNameเป็นการก่อสร้างที่ผิดพลาดเนื่องจากถือว่ามีชื่อชั้นเดียว element.className.replace(/^| /g, '.')การก่อสร้างที่ถูกต้อง 3.ฟังก์ชันของคุณไม่สนใจความเป็นไปได้ของตัวเลือก CSS อื่น ๆ นอกเหนือจากคลาส 4. การเรียกซ้ำของคุณถูก จำกัด โดยพลการเพียงหนึ่งระดับ (ลูก ๆ แต่ไม่ใช่ลูกหลาน) 5.การใช้งาน: ไม่มีgetElementByClassNameเท่านั้นgetElementsByClassName(ส่งคืนอาร์เรย์)
7vujy0f0hy

1

ฉันคิดว่าคำตอบจาก SB ควรเป็นคำตอบที่ได้รับการยอมรับ ณ จุดนี้ แต่ยังไม่แน่นอน มีการกล่าวถึงไม่กี่ครั้งว่าจะมีกฎบางอย่างที่อาจพลาดได้ เมื่อเผชิญกับสิ่งนั้นฉันจึงตัดสินใจใช้ document.querySelectorAll แทน element.matches สิ่งเดียวคือคุณต้องมีการระบุองค์ประกอบที่เป็นเอกลักษณ์บางอย่างเพื่อเปรียบเทียบกับองค์ประกอบที่คุณกำลังมองหา ในกรณีส่วนใหญ่ฉันคิดว่าทำได้โดยการตั้งค่า id ให้มีค่าเฉพาะ นั่นคือวิธีที่คุณสามารถระบุองค์ประกอบที่ตรงกันว่าเป็นของคุณ หากคุณสามารถนึกถึงวิธีทั่วไปในการจับคู่ผลลัพธ์ของ document.querySelectorAll กับองค์ประกอบที่คุณกำลังมองหาซึ่งโดยพื้นฐานแล้วจะเป็น polyfill ที่สมบูรณ์ของ getMatchedCSSRules

ฉันตรวจสอบประสิทธิภาพของ document.querySelectorAll เนื่องจากอาจจะช้ากว่า element.matches แต่ในกรณีส่วนใหญ่ไม่น่าจะมีปัญหา ฉันเห็นว่ามันใช้เวลาประมาณ 0.001 มิลลิวินาที

ฉันยังพบไลบรารี CSSUtilities ที่โฆษณาว่าสามารถทำได้ แต่ฉันรู้สึกว่ามันเก่าและไม่ได้รับการอัปเดตมาสักพักแล้ว เมื่อมองไปที่ซอร์สโค้ดมันทำให้ฉันคิดว่าอาจมีบางกรณีที่พลาดไป


CSSUtilities นั้นเก่ามาก แต่ก็คืนกฎสำหรับสถานะหลอกเช่นกัน (ตัวอย่างเช่นมันสามารถส่งคืนกฎโฮเวอร์) ฉันยังไม่พบคำตอบใด ๆ ที่นี่ที่กล่าวถึงสถานะหลอก
mr1031011
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.