Export CSS of Dom Elements

Export CSS of DOM elements

Here is the code for an exportStyles() method that should return a CSS string including all inline and external styles for a given element, except default values (which was the main difficulty).

For example: console.log(someElement.exportStyles());

Since you are using Chrome, I did not bother making it compatible with IE.
Actually it just needs that the browsers supports the getComputedStyle(element) method.

Element.prototype.exportStyles = (function () {  

// Mapping between tag names and css default values lookup tables. This allows to exclude default values in the result.
var defaultStylesByTagName = {};

// Styles inherited from style sheets will not be rendered for elements with these tag names
var noStyleTags = {"BASE":true,"HEAD":true,"HTML":true,"META":true,"NOFRAME":true,"NOSCRIPT":true,"PARAM":true,"SCRIPT":true,"STYLE":true,"TITLE":true};

// This list determines which css default values lookup tables are precomputed at load time
// Lookup tables for other tag names will be automatically built at runtime if needed
var tagNames = ["A","ABBR","ADDRESS","AREA","ARTICLE","ASIDE","AUDIO","B","BASE","BDI","BDO","BLOCKQUOTE","BODY","BR","BUTTON","CANVAS","CAPTION","CENTER","CITE","CODE","COL","COLGROUP","COMMAND","DATALIST","DD","DEL","DETAILS","DFN","DIV","DL","DT","EM","EMBED","FIELDSET","FIGCAPTION","FIGURE","FONT","FOOTER","FORM","H1","H2","H3","H4","H5","H6","HEAD","HEADER","HGROUP","HR","HTML","I","IFRAME","IMG","INPUT","INS","KBD","KEYGEN","LABEL","LEGEND","LI","LINK","MAP","MARK","MATH","MENU","META","METER","NAV","NOBR","NOSCRIPT","OBJECT","OL","OPTION","OPTGROUP","OUTPUT","P","PARAM","PRE","PROGRESS","Q","RP","RT","RUBY","S","SAMP","SCRIPT","SECTION","SELECT","SMALL","SOURCE","SPAN","STRONG","STYLE","SUB","SUMMARY","SUP","SVG","TABLE","TBODY","TD","TEXTAREA","TFOOT","TH","THEAD","TIME","TITLE","TR","TRACK","U","UL","VAR","VIDEO","WBR"];

// Precompute the lookup tables.
for (var i = 0; i < tagNames.length; i++) {
if(!noStyleTags[tagNames[i]]) {
defaultStylesByTagName[tagNames[i]] = computeDefaultStyleByTagName(tagNames[i]);
}
}

function computeDefaultStyleByTagName(tagName) {
var defaultStyle = {};
var element = document.body.appendChild(document.createElement(tagName));
var computedStyle = getComputedStyle(element);
for (var i = 0; i < computedStyle.length; i++) {
defaultStyle[computedStyle[i]] = computedStyle[computedStyle[i]];
}
document.body.removeChild(element);
return defaultStyle;
}

function getDefaultStyleByTagName(tagName) {
tagName = tagName.toUpperCase();
if (!defaultStylesByTagName[tagName]) {
defaultStylesByTagName[tagName] = computeDefaultStyleByTagName(tagName);
}
return defaultStylesByTagName[tagName];
}

return function exportStyles() {
if (this.nodeType !== Node.ELEMENT_NODE) {
throw new TypeError("The exportStyles method only works on elements, not on " + this.nodeType + " nodes.");
}
if (noStyleTags[this.tagName]) {
throw new TypeError("The exportStyles method does not work on " + this.tagName + " elements.");
}
var styles = {};
var computedStyle = getComputedStyle(this);
var defaultStyle = getDefaultStyleByTagName(this.tagName);
for (var i = 0; i < computedStyle.length; i++) {
var cssPropName = computedStyle[i];
if (computedStyle[cssPropName] !== defaultStyle[cssPropName]) {
styles[cssPropName] = computedStyle[cssPropName];
}
}

var a = ["{"];
for(var i in styles) {
a[a.length] = i + ": " + styles[i] + ";";
}
a[a.length] = "}"
return a.join("\r\n");
}

})();

This code is base on my answer for a slightly related question: Extract the current DOM and print it as a string, with styles intact

How to export all relevant HTML/CSS for one element

Yes, there is a tool/s and ways to do that.

First, with Chrome extension, you can install SnappySnippet from Chrome Web Store. It allows easy HTML+CSS extraction from the specified (last inspected) DOM node. Additionally, you can send your code straight to CodePen or JSFiddle.

Second, CSS Used, other Chrome extension, for extracting CSS with children CSSs.

And third, without extension, if you want CSS embedded in HTML or above extensions is not working for you, you can use any Webkit based browser (like Chrome or Firefox) to run script in console which will add all css to html element and you can easily just copy OuterHTML and it will work anywhere.

var el = document.querySelector(“#yourId”); // change yourId to id of your element, or you can write “body” and it will convert all document
var els = el.getElementsByTagName("*");

for(var i = -1, l = els.length; ++i < l;){
els[i].setAttribute("style", window.getComputedStyle(els[i]).cssText);
}

So, just copy this code to Console (Right click on page->Inspect->Console), change yourid to yourid or set it to "body", run it and then right click on your element and "copy outerHTML"

How can I grab all css styles of an element?

UPDATE: As @tank answers below, Chrome version 77 added "Copy Styles" when you right-click on an element in the devtools inspector.


Using Javascript worked best for me. Here's how I did it:

  1. Open Chrome DevTools console.
  2. Paste this dumpCSSText function from this stack overflow answer into the console, and hit Enter:

    function dumpCSSText(element){
    var s = '';
    var o = getComputedStyle(element);
    for(var i = 0; i < o.length; i++){
    s+=o[i] + ':' + o.getPropertyValue(o[i])+';';
    }
    return s;
    }
  3. When using Chrome, you can inspect an element and access it in the console with the $0 variable. Chrome also has a copy command, so use this command to copy ALL the css of the inspected element:

    copy(dumpCSSText($0));
  4. Paste your CSS wherever you like! /p>

Tools to selectively Copy HTML+CSS+JS From A Specific Element of DOM

SnappySnippet

I finally found some time to create this tool. You can install SnappySnippet from Github. It allows easy HTML+CSS extraction from the specified (last inspected) DOM node. Additionally, you can send your code straight to CodePen or JSFiddle. Enjoy!

SnappySnippet Chrome extension

Other features

  • cleans up HTML (removing unnecessary attributes, fixing indentation)
  • optimizes CSS to make it readable
  • fully configurable (all filters can be turned off)
  • works with ::before and ::after pseudo-elements
  • nice UI thanks to Bootstrap & Flat-UI projects

Code

SnappySnippet is open source, and you can find the code on GitHub.

Implementation

Since I've learned quite a lot while making this, I've decided to share some of the problems I've experienced and my solutions to them, maybe someone will find it interesting.

First attempt - getMatchedCSSRules()

At first I've tried retrieving the original CSS rules (coming from CSS files on the website). Quite amazingly, this is very simple thanks to window.getMatchedCSSRules(), however, it didn't work out well. The problem was that we were taking only a part of the HTML and CSS selectors that were matching in the context of the whole document, which were not matching anymore in the context of an HTML snippet. Since parsing and modifying selectors didn't seem like a good idea, I gave up on this attempt.

Second attempt - getComputedStyle()

Then, I've started from something that @CollectiveCognition suggested - getComputedStyle(). However, I really wanted to separate CSS form HTML instead of inlining all styles.

Problem 1 - separating CSS from HTML

The solution here wasn't very beautiful but quite straightforward. I've assigned IDs to all nodes in the selected subtree and used that ID to create appropriate CSS rules.

Problem 2 - removing properties with default values

Assigning IDs to the nodes worked out nicely, however I found out that each of my CSS rules has ~300 properties making the whole CSS unreadable.

Turns out that getComputedStyle() returns all possible CSS properties and values calculated for the given element. Some of them where empty, some had browser default values. To remove default values I had to get them from the browser first (and each tag has different default values). The solution was to compare the styles of the element coming from the website with the same element inserted into an empty <iframe>. The logic here was that there are no style sheets in an empty <iframe>, so each element I've appended there had only default browser styles. This way I was able to get rid of most of the properties that were insignificant.

Problem 3 - keeping only shorthand properties

Next thing I have spotted was that properties having shorthand equivalent were unnecessarily printed out (e.g. there was border: solid black 1px and then border-color: black;, border-width: 1px itd.).

To solve this I've simply created a list of properties that have shorthand equivalents and filtered them out from the results.

Problem 4 - removing prefixed properties

The number of properties in each rule was significantly lower after the previous operation, but I've found that I sill had a lot of -webkit- prefixed properties that I've never hear of (-webkit-app-region? -webkit-text-emphasis-position?).

I was wondering if I should keep any of these properties because some of them seemed useful (-webkit-transform-origin, -webkit-perspective-origin etc.). I haven't figured out how to verify this, though, and since I knew that most of the time these properties are just garbage, I decided to remove them all.

Problem 5 - combining same CSS rules

The next problem I have spotted was that the same CSS rules are repeated over and over (e.g. for each <li> with the exact same styles there was the same rule in the CSS output created).

This was just a matter of comparing rules with each other and combining these that had exactly the same set of properties and values. As a result, instead of #LI_1{...}, #LI_2{...} I got #LI_1, #LI_2 {...}.

Problem 6 - cleaning up and fixing indentation of HTML

Since I was happy with the result, I moved to HTML. It looked like a mess, mostly because the outerHTML property keeps it formatted exactly as it was returned from the server.

The only thing HTML code taken from outerHTML needed was a simple code reformatting. Since it's something available in every IDE, I was sure that there is a JavaScript library that does exactly that. And it turns out that I was right (jquery-clean). What's more, I've got unnecessary attributes removal extra (style, data-ng-repeat etc.).

Problem 7 - filters breaking CSS

Since there is a chance that in some circumstances filters mentioned above may break CSS in the snippet, I've made all of them optional. You can disable them from the Settings menu.

Extracting only the css used in a specific page

I've used Dust-Me Selectors before, which is a Firefox plugin. It's very easy to use and versatile as it maintains a combined list across a number of pages of which CSS values are used.

The downside is that I wasn't able to automate it to spider an entire site, so I ended up using it just on key pages/templates of my site. It is very useful nonetheless.

http://www.sitepoint.com/dustmeselectors/

https://addons.mozilla.org/en-US/firefox/addon/dust-me-selectors/

Contrary to the comment above Dust-Me Selectors 2.2 is compatible with Firefox 3.6 (I've just installed it).

How to get and extract matched css rules on dom-node?

What prevents you from mouse-selecting and copying (Ctrl-C, whatever) the contents of the "Matched CSS Rules" or "Computed Styles" section in the sidebar (am I missing the task you are trying to solve?)

There's a known issue with pasting the copied contents into well-known HTML-aware text editors (the CSS properties inside rules are rendered as a numbered list, which is actually a bug in the respective editors) but otherwise, if you want to manually grab a copy of all your matched CSS rules/computed style for a DOM element, this workflow should work for you.

3rd party edit

In the comment below it is recommended to use window.getMatchedCSSRules(). Using it in Chrome 62 returns this

VM1395:1 [Deprecation] 'getMatchedCSSRules()' is deprecated. For more
help, check
https://code.google.com/p/chromium/issues/detail?id=437569#c2

The discussion getMatchedCSSRules was started in november 2014 and contains this bit getMatchedCSSRules is non-standard and likely to be removed in the coming months. Relying on it is bad for cross-browser interop since major browsers like Firefox and IE won't be supported. It seems that M63 will start to remove it.

An alternative might be to use CSS Object Model (CSSOM)



Related Topics



Leave a reply



Submit