So erhalten Sie den angewendeten Stil von einem Element, mit Ausnahme der Standardstile des Benutzeragenten

Lesezeit: 14 Minuten

Benutzer-Avatar
Gjum Fuchs

Wie rufen Sie in JavaScript die Stile ab, die auf ein Element angewendet wurden, ausgenommen die Standardstile des Benutzeragenten (also nur Inline- und Stylesheet-Stile).

Grundsätzlich alle Benutzerstile, die Sie auf der Registerkarte „Berechnet“ Ihres bevorzugten Entwicklertools sehen können:

Benutzerstile, die im Entwicklertool von Edge angezeigt werden

Bitte kein Framework, IE8+, Edge, Chrome und Firefox.

Ich erwarte, dass die Antwort das Ergebnis von sein wird getComputedStyle Minus- getDefaultComputedStyle, aber browserübergreifend. Da alle Entwicklertools dazu in der Lage sind, muss es eine Lösung geben 🙂

  • window.getComputedStyle() ?

    – Alex K.

    3. Februar 2017 um 13:23 Uhr


  • Mögliches Duplikat von Wie erhält man alle angewendeten Stile eines Elements, indem man einfach seine ID angibt?

    – n_pflaume

    3. Februar 2017 um 13:24 Uhr

  • @AlexK.: Nein, ich möchte nicht die Standardstile des Benutzeragenten: jsfiddle.net/701tg35d

    – Gjum Fuchs

    3. Februar 2017 um 13:33 Uhr

  • @n_palum Weder diese Frage noch ihre Antwort schließen den Standard-User-Agent-Stil für das Ergebnis aus

    – Gjum Fuchs

    3. Februar 2017 um 13:41 Uhr

  • getDefaultComputedStyle ist kein Standard, also keine Option. Entwicklertools sind wahrscheinlich fest codiert, um zu wissen, was der Browser anwendet, daher ist dies möglicherweise nicht über Javascript möglich.

    – Rik Lewis

    3. Februar 2017 um 13:56 Uhr

Benutzer-Avatar
er-han

Es gibt eine schreibgeschützte Eigenschaft des Dokuments namens „styleSheets“.

var styleSheetList = document.styleSheets;

https://developer.mozilla.org/en-US/docs/Web/API/Document/styleSheets

Damit erreichen Sie alle Stile, die vom Autor verwendet werden.

Hier gibt es eine ähnliche Frage, aber kein Duplikat:

Ist es möglich, mit Javascript zu überprüfen, ob bestimmte CSS-Eigenschaften innerhalb des Style-Tags definiert sind?

Sie können den angewendeten Stil von einem Element erhalten, mit Ausnahme der Standardstile des Benutzeragenten, indem Sie die akzeptierte Antwort auf die Frage verwenden, die ich gerade erwähnt habe.

Diese Antwort lieferte nicht die des Elements style Attributinhalt, also habe ich den Code ein wenig verbessert:

var proto = Element.prototype;
var slice = Function.call.bind(Array.prototype.slice);
var matches = Function.call.bind(proto.matchesSelector || 
                proto.mozMatchesSelector || proto.webkitMatchesSelector ||
                proto.msMatchesSelector || proto.oMatchesSelector);

// Returns true if a DOM Element matches a cssRule
var elementMatchCSSRule = function(element, cssRule) {
  return matches(element, cssRule.selectorText);
};

// Returns true if a property is defined in a cssRule
var propertyInCSSRule = function(prop, cssRule) {
  return prop in cssRule.style && cssRule.style[prop] !== "";
};

// Here we get the cssRules across all the stylesheets in one array
var cssRules = slice(document.styleSheets).reduce(function(rules, styleSheet) {
  return rules.concat(slice(styleSheet.cssRules));
}, []);




var getAppliedCss = function(elm) {
	// get only the css rules that matches that element
	var elementRules = cssRules.filter(elementMatchCSSRule.bind(null, elm));
	var rules =[];
	if(elementRules.length) {
		for(i = 0; i < elementRules.length; i++) {
			var e = elementRules[i];
			rules.push({
				order:i,
				text:e.cssText
			})
		}		
	}
	
	if(elm.getAttribute('style')) {
		rules.push({
				order:elementRules.length,
				text:elm.getAttribute('style')
			})
	}
	return rules;
}







function showStyle(){
var styleSheetList = document.styleSheets;
// get a reference to an element, then...
var div1 = document.getElementById("div1");

var rules = getAppliedCss(div1);

var str="";
for(i = 0; i < rules.length; i++) {
			var r = rules[i];
			str += '<br/>Style Order: ' + r.order + ' | Style Text: ' + r.text; 
		}		
		
	document.getElementById("p1").innerHTML = str;	

}
#div1 {
float:left;
width:100px;
}

div {
text-align:center;
}
<div id="div1" style="font-size:14px;">
	Lorem ipsum 
	</div>
<br/>
<br/>
<a href="https://stackoverflow.com/questions/42025329/javascript:;" onclick="showStyle()"> Show me the style. </a>
	<p id="p1"><p>

  • Ich mag diesen Ansatz, aber ich möchte anmerken, dass er derzeit Inline-Stile ignoriert. Man sollte die hinzufügen element.style zu den Ergebnissen, um es zu vervollständigen.

    – Nur ein Student

    6. Februar 2017 um 13:42 Uhr

  • Stimmt, jetzt sehe ich es. Lass mich überlegen, was ich tun kann

    – er-han

    6. Februar 2017 um 13:44 Uhr

  • Ich habe den Inhalt des eigenen Stilattributs des Elements in das Codebeispiel eingefügt

    – er-han

    6. Februar 2017 um 14:27 Uhr

  • @GyumFox Ich frage mich, ob Sie diesen Ansatz in mehreren Browsern ausprobiert haben? Wenn ja, können Sie die Ergebnisse teilen?

    – er-han

    7. Februar 2017 um 12:46 Uhr

  • Ich habe den Code Ihrer Antwort hier verwendet: stackoverflow.com/questions/50567761/… Vielleicht möchten Sie sehen, was ich geändert habe!

    – Takit Issy

    28. Mai 2018 um 18:58 Uhr

Benutzer-Avatar
Nur ein Student

Alle Entwicklertools können schummeln, weil sie Zugriff auf die Standardregeln haben, die der Browser anwendet, in den sie eingebaut sind.

Ich dachte, dass die folgenden Ansatz könnte funktionieren.

  1. Konstruieren Sie ein Element vom genau gleichen Typ (sagen wir a div oder p) als derjenige, an dem wir interessiert sind.
  2. Hängen Sie dieses Element irgendwo auf der Seite an, sodass nur Standardbrowserregeln angewendet werden. Wir können dies tun, indem wir es in ein einfügen iframe.
    Wenn Sie sicher sind, dass Sie keine Regeln haben, die darauf abzielen p -Element, zum Beispiel, dann kann das Anhängen an den Körper effizienter sein.
  3. Überprüfen Sie die Unterschiede in den Stilen und geben Sie nur unterschiedliche Werte an.
  4. Temporäre Elemente bereinigen.

In der Praxis scheint es einigermaßen gut zu funktionieren. Ich habe dies nur in Firefox und Chrome getestet, aber ich denke, dass es auch in anderen Browsern funktionieren sollte – außer vielleicht der Tatsache, dass ich es verwendet habe für in und für … von, aber das könnte man leicht umschreiben. Beachten Sie, dass nicht Nur Die von Ihnen angegebenen Eigenschaften werden gemeldet, aber auch einige Eigenschaften, die von den von Ihnen angegebenen Eigenschaften beeinflusst werden. Beispielsweise entspricht die Rahmenfarbe der Textfarbe per Design und wird daher auch dann als unterschiedlich gemeldet, wenn Sie nur festlegen color: white.

Zusammenfassend habe ich das Beispiel, das Sie in einem Ihrer Kommentare gepostet haben, genommen und a hinzugefügt getNonDefaultStyles Funktion dazu, die meiner Meinung nach das tut, was Sie wollen. Es kann natürlich geändert werden, um Standardstile zu cachen, z. div -Elemente und damit effizienter bei wiederholten Aufrufen (weil das Modifizieren der DOM ist teuer), aber es zeigt das Wesentliche.

Das folgende Snippet zeigt, wie die Version implementiert werden kann, die ein Element an den Körper anhängt. Aufgrund von Einschränkungen bei StackOverflow ist es nicht möglich, die anzuzeigen iframe Version in einem Ausschnitt. Es ist auf möglich JSFiddle. Das folgende Snippet befindet sich auch in a Geige.

var textarea = document.getElementById("textarea"),
    paragraph = document.getElementById("paragraph");

/**
 * Computes applied styles, assuming no rules targeting a specific element.
 */
function getNonDefaultStyles(el) {
  var styles = {},
    computed = window.getComputedStyle(el),
    notTargetedContainer = document.createElement('div'),
    elVanilla = document.createElement(el.tagName);
  document.body.appendChild(notTargetedContainer);
  notTargetedContainer.appendChild(elVanilla);
  var vanilla = window.getComputedStyle(elVanilla);
  for (let key of computed) {
    if (vanilla[key] !== computed[key]) {
      styles[key] = computed[key];
    }
  }
  document.body.removeChild(notTargetedContainer);
  return styles;
}

var paragraphStyles = getNonDefaultStyles(paragraph);
for (let style in paragraphStyles) {
  textarea.value += style + ": " + paragraphStyles[style] + "\n";
}
#paragraph {
  background: red;
}

textarea {
  width: 300px;
  height: 400px;
}
<p id="paragraph" style="color: white">
  I am a DIV
</p>

<p>
  User styles:
</p>
<textarea id="textarea"></textarea>

  • Ich mag die Idee, aber Punkt 2 könnte ein Hingucker sein, da Sie nicht in der Lage sein werden, die Stile zu entfernen, die direkt auf alle Elemente eines bestimmten Typs angewendet werden (zB: P {margin:0}). Ich möchte die Lösung optimieren, um diese zu handhaben. Vielleicht indem Sie den Stil dieser Elemente direkt aus den Stylesheets lesen (inspiriert von er-hans Lösung) oder indem Sie eine leere Seite in einen Iframe laden, um die Standardstile für einen bestimmten Elementtyp abzurufen?

    – Gjum Fuchs

    6. Februar 2017 um 18:11 Uhr

  • Danke für das Update. Ich habe die Fiddle leicht geändert, damit sie auf Edge funktioniert: jsfiddle.net/9o178w97/2 (Ich habe für … in verwendet, was, wie Sie sagten, einige Nachteile hat). Obwohl Ihre Lösung meiner ursprünglichen Idee am nächsten kommt, habe ich die Antwort von @er-han akzeptiert, da sie den Vorteil hat, dass nur die Stileigenschaften zurückgegeben werden, die explizit vom Benutzer festgelegt wurden.

    – Gjum Fuchs

    10. Februar 2017 um 13:03 Uhr

  • Dies ist eine großartige Lösung! Ich habe ein paar Verbesserungen hinzugefügt (siehe meine Antwort unten), um das auszublenden <iframe>, die Standardstile zwischenspeichern und Dinge wie Vererbung berücksichtigen. Vielen Dank!

    – Joseph238

    11. Mai um 16:03 Uhr


Benutzer-Avatar
Joe

Hier ist eine Funktion, die alle CSS-Regeln abruft, die auf ein Element angewendet wurden, entweder aus Inline-Stilen (HTML style -Attribut) oder Stylesheets auf der Seite. Es erfasst auch relevante Keyframes für CSS-Animationen und die :active, :hover, ::beforeund ::after Selektoren.

function getAppliedCssData(el) {
  // we create a unique id so we can generate unique ids for renaming animations
  let uniqueId = "id" + Math.random().toString().slice(2) + Math.random().toString().slice(2);

  let allRules = [...document.styleSheets].map(s => {
    let rules = [];
    try { rules.push(...s.cssRules) } catch(e) {} // we ignore cross-domain stylesheets with restrictive CORs headers
    return rules;
  }).flat();

  let styleRules = allRules.filter(rule => rule.type === CSSRule.STYLE_RULE)
  let fontFaceRules = allRules.filter(rule => rule.type === CSSRule.FONT_FACE_RULE);
  let keyframesRules = allRules.filter(rule => rule.type === CSSRule.KEYFRAMES_RULE);

  let matchingDefaultRules = styleRules.filter(rule => el.matches(rule.selectorText));
  let nonMatchingRules = styleRules.filter(rule => !el.matches(rule.selectorText));
  let matchingHoverRules =  nonMatchingRules.filter(rule => el.matches(rule.selectorText.replace(/ :/g, " *:").replace(/([^(])(:hover)\b/g, "$1")));
  let matchingActiveRules = nonMatchingRules.filter(rule => el.matches(rule.selectorText.replace(/ :/g, " *:").replace(/([^(])(:active)\b/g, "$1")));
  let matchingBeforeRules = nonMatchingRules.filter(rule => el.matches(rule.selectorText.replace(/ :/g, " *:").replace(/::before\b/g, "")));
  let matchingAfterRules =  nonMatchingRules.filter(rule => el.matches(rule.selectorText.replace(/ :/g, " *:").replace(/::after\b/g, "")));
  let allMatchingStyleRules = [...matchingActiveRules, ...matchingDefaultRules, ...matchingHoverRules, ...matchingBeforeRules, ...matchingAfterRules];
  let matchingAnimationNames = allMatchingStyleRules.map(rule => rule.style.animationName).filter(n => n.trim());
  let matchingKeyframeRules = keyframesRules.filter(rule => matchingAnimationNames.includes(rule.name));
  
  // make name changes before actually grabbing the style text of each type
  allMatchingStyleRules.forEach(rule => rule.style.animationName = rule.style.animationName+uniqueId);
  matchingKeyframeRules.forEach(rule => rule.name = rule.name+uniqueId);

  let matchingDefaultStyles = matchingDefaultRules.map(rule => rule.cssText).map(r => r.split(/[{}]/g)[1].trim()).join(" ") + (el.getAttribute('style') || ""); // important to add these last because inline styles are meant to override stylesheet styles (unless !important is used)
  let matchingHoverStyles = matchingHoverRules.map(rule => rule.cssText).map(r => r.split(/[{}]/g)[1].trim()).join(" ");
  let matchingActiveStyles = matchingActiveRules.map(rule => rule.cssText).map(r => r.split(/[{}]/g)[1].trim()).join(" ");
  let matchingBeforeStyles = matchingBeforeRules.map(rule => rule.cssText).map(r => r.split(/[{}]/g)[1].trim()).join(" ");
  let matchingAfterStyles = matchingAfterRules.map(rule => rule.cssText).map(r => r.split(/[{}]/g)[1].trim()).join(" ");
  let matchingKeyframeStyles = matchingKeyframeRules.map(rule => rule.cssText).join(" ");
  
  // undo the rule name changes because this actually affects the whole document:
  matchingKeyframeRules.forEach(rule => rule.name = rule.name.replace(uniqueId, "")); 
  allMatchingStyleRules.forEach(rule => rule.style.animationName = rule.style.animationName.replace(uniqueId, ""));

  let data = {
    uniqueId,
    defaultStyles: matchingDefaultStyles,
    hoverStyles: matchingHoverStyles,
    activeStyles: matchingActiveStyles,
    keyframeStyles: matchingKeyframeStyles,
    beforeStyles: matchingBeforeStyles,
    afterStyles: matchingAfterStyles,
  }
  return data;
}

Das :focus, :focus-within und :visited Selektoren sind nicht enthalten, könnten aber leicht hinzugefügt werden.

Benutzer-Avatar
Josef238

Sie können die vom Benutzer angewendeten (nicht standardmäßigen) Stile berechnen, indem Sie sie mit einem „Standard“-HTML-Element mit demselben Tag-Namen vergleichen, das isoliert gerendert wird <iframe> daher “lecken” keine Stile aus dem Dokument in das Standardelement.

Diese Lösung ist die gleiche wie @Just a student, fügt aber diese Verbesserungen hinzu:

  1. das <iframe> ist ein verstecktes HTML-Element, sodass der Benutzer es nicht sieht
  2. Für die Leistung werden Standardstile zwischengespeichert und wir warten, bis wir sie bereinigen <iframe> bis zum Ende, wenn wir anrufen removeSandbox
  3. es berücksichtigt die Vererbung (dh wenn Sie angeben parentElement es wird einen Stil auflisten, selbst wenn das übergeordnete Element ihn festlegt und das Element ihn auf den Standardwert zurücksetzt)
  4. Es berücksichtigt Situationen, in denen der Anfangswert und der berechnete Wert eines Standardstils nicht übereinstimmen (weitere Informationen finden Sie unter note [1] in diese PR)
// usage:
element = document.querySelector('div');
styles = getUserComputedStyles(element);
styles = getUserComputedStyles(element, parentElement);
// call this method when done to cleanup:
removeSandbox();

function getUserComputedStyles(element, parentElement = null) {
    var defaultStyle = getDefaultStyle(element.tagName);
    var computedStyle = window.getComputedStyle(element);
    var parentStyle =
      parentElement ? window.getComputedStyle(parentElement) : null;
    var styles = {};
    [...computedStyle].forEach(function(name) {
        // If the style does not match the default, or it does not match the
        // parent's, set it. We don't know which styles are inherited from the
        // parent and which aren't, so we have to always check both.
        // This results in some extra default styles being returned, so if you
        // want to avoid this and aren't concerned about omitting styles that
        // the parent set but the `element` overrides back to the default,
        // call `getUserComputedStyles` without a `parentElement`.
        const computedStyleValue = computedStyle[name];
        if (computedStyleValue !== defaultStyle[name] ||
          (parentStyle && computedStyleValue !== parentStyle[name])) {
            styles[name] = computedStyleValue;
        }
    });
    return styles;
}

var removeDefaultStylesTimeoutId = null;
var sandbox = null;
var tagNameDefaultStyles = {};

function getDefaultStyle(tagName) {
    if (tagNameDefaultStyles[tagName]) {
        return tagNameDefaultStyles[tagName];
    }
    if (!sandbox) {
        // Create a hidden sandbox <iframe> element within we can create
        // default HTML elements and query their computed styles. Elements
        // must be rendered in order to query their computed styles. The
        // <iframe> won't render at all with `display: none`, so we have to
        // use `visibility: hidden` with `position: fixed`.
        sandbox = document.createElement('iframe');
        sandbox.style.visibility = 'hidden';
        sandbox.style.position = 'fixed';
        document.body.appendChild(sandbox);
        // Ensure that the iframe is rendered in standard mode
        sandbox.contentWindow.document.write(
          '<!DOCTYPE html><meta charset="UTF-8"><title>sandbox</title><body>');
    }
    var defaultElement = document.createElement(tagName);
    sandbox.contentWindow.document.body.appendChild(defaultElement);
    // Ensure that there is some content, so properties like margin are applied
    defaultElement.textContent=".";
    var defaultComputedStyle =
      sandbox.contentWindow.getComputedStyle(defaultElement);
    var defaultStyle = {};
    // Copy styles to an object, making sure that 'width' and 'height' are
    // given the default value of 'auto', since their initial value is always
    // 'auto' despite that the default computed value is sometimes an absolute
    // length.
    [...defaultComputedStyle].forEach(function(name) {
        defaultStyle[name] = (name === 'width' || name === 'height')
          ? 'auto' : defaultComputedStyle.getPropertyValue(name);
    });
    sandbox.contentWindow.document.body.removeChild(defaultElement);
    tagNameDefaultStyles[tagName] = defaultStyle;
    return defaultStyle;
}

function removeSandbox() {
    if (!sandbox) {
        return;
    }
    document.body.removeChild(sandbox);
    sandbox = null;
    if (removeDefaultStylesTimeoutId) {
        clearTimeout(removeDefaultStylesTimeoutId);
    }
    removeDefaultStylesTimeoutId = setTimeout(() => {
        removeDefaultStylesTimeoutId = null;
        tagNameDefaultStyles = {};
    }, 20 * 1000);
}

Trotz dieser Verbesserungen werden für Blockelemente immer noch einige Standardstile aufgeführt, weil ihre anfänglichen und berechneten Werte nicht übereinstimmen, nämlich width, height, block-size, inset-block, transform-originund perspective-origin (siehe Hinweis in Nr. 4). Diese Lösung im dom-to-image-mehr (das getUserComputedStyle -Funktion) kann noch mehr davon wegschneiden, obwohl die Berechnung langsamer ist.

Ich habe diese Funktion in der Vergangenheit verwendet …

function get_style(obj,nam) { //obj = HTML element, nam = style property
  var val = "";
  if(document.defaultView && document.defaultView.getComputedStyle) {
    nam = nam.replace(/[A-Z]/g,function(str) { //convert name into hypenated
      return "-"+str.toLowerCase();
    });
    val = document.defaultView.getComputedStyle(obj,"").getPropertyValue(nam); //get current style
  }
  else if(obj.currentStyle) {
    nam = nam.replace(/\-(\w)/g,function(str,p1) { //convert name into camel case
      return p1.toUpperCase();
    });
    val = obj.currentStyle[nam]; //get current style
  }
  return val;
}

Es ermöglicht Ihnen, die Stileigenschaft entweder als Bindestrich (background-color) oder Camel Case (backgroundColor) und ersetzt es je nach verwendeter Methode.

Dies deckt auch ältere Browser ab, sogar alte IE!

  • Hmmm … was ich will, ist eine Funktion, die alle Stile (und Werte) auflistet, die vom Benutzer angewendet wurden (nur Inline oder Stylesheet). Ihre Funktion scheint eine Art “cross-browser” getComputedStyle zu sein

    – Gjum Fuchs

    3. Februar 2017 um 13:38 Uhr

  • Ah ja, tut mir leid. Ich habe die Frage leicht falsch verstanden, ich dachte, Sie wollten einen bestimmten Immobilienwert ermitteln. Sie könnten eine vordefinierte Liste aller Stile durchlaufen, die Sie interessieren könnten, und dann diese Funktion aufrufen und nur diejenigen auflisten, die nicht leer sind. Aber ich vermute, dass dies ziemlich ineffizient wäre und eine ziemlich lange Liste erzeugen würde.

    – Rik Lewis

    3. Februar 2017 um 13:42 Uhr


  • Hmmm … was ich will, ist eine Funktion, die alle Stile (und Werte) auflistet, die vom Benutzer angewendet wurden (nur Inline oder Stylesheet). Ihre Funktion scheint eine Art “cross-browser” getComputedStyle zu sein

    – Gjum Fuchs

    3. Februar 2017 um 13:38 Uhr

  • Ah ja, tut mir leid. Ich habe die Frage leicht falsch verstanden, ich dachte, Sie wollten einen bestimmten Immobilienwert ermitteln. Sie könnten eine vordefinierte Liste aller Stile durchlaufen, die Sie interessieren könnten, und dann diese Funktion aufrufen und nur diejenigen auflisten, die nicht leer sind. Aber ich vermute, dass dies ziemlich ineffizient wäre und eine ziemlich lange Liste erzeugen würde.

    – Rik Lewis

    3. Februar 2017 um 13:42 Uhr


1013720cookie-checkSo erhalten Sie den angewendeten Stil von einem Element, mit Ausnahme der Standardstile des Benutzeragenten

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy