Tools to selectively Copy HTML+CSS+JS From A Specific Element of DOM
Solution 1
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!
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.
Solution 2
I originally asked this question I was looking for a Chrome (or FireFox) solution, but I stumbled across this feature in Internet Explorer developer tools. Pretty much what I'm looking for (except for the javascript)
Result:
Solution 3
Webkit browsers (not sure about FireBug) allow you to copy the HTML of an element easily, so that's one part of the process out of the way.
Running this (in the javascript console) prior to copying the HTML for an element will move all the computed styles for the parent element given, as well as all child elements, into the inline style attribute which will then be available as part of the HTML.
var el = document.querySelector("#someid");
var els = el.getElementsByTagName("*");
for(var i = -1, l = els.length; ++i < l;){
els[i].setAttribute("style", window.getComputedStyle(els[i]).cssText);
}
It's a total hack and you'll have alot of "junk" css attributes to wade through, but should at least get your started.
Solution 4
I've created this tool years ago for the same purpose:
http://www.betterprogramming.com/htmlclipper.html
You're welcome to use and improve upon it.
Solution 5
This can be done by Firebug Plugin called scrapbook
You can check Javascript option in setting
Edit:
This can also help
Firequark is an extension to Firebug to aid the process of HTML Screen Scraping. Firequark automatically extracts css selector for a single or multiple html node(s) from a web page using Firebug (a web development plugin for Firefox). The css selector generated can be given as an input to html screen scrapers like Scrapi to extract information. Firequark is built to unleash the power of css selector for use of html screen scraping.
Ankur
i write software for a living. someday a robot is going to take my job. i can't wait.
Updated on July 21, 2022Comments
-
Ankur almost 2 years
Like most web developers, I occasionally like to look at the source of websites to see how their markup is built. Tools like Firebug and Chrome Developer Tools make it easy to inspect the code, but if I want to copy a specific section and play around with it locally, it would be a pain to copy all the individual elements and their associated CSS. And probably just as much work to save the entire source and cut out the unrelated code.
It would be great if I could right-click a Element in Firebug and have a "Save HTML+CSS+JS for this Element" option. Does such a tool exist? Is it possible to extend Firebug or Chrome Developer Tools to add this feature?
-
peteorpeter about 13 yearsScrapbook looks great - unfortunately both the latest version (1.4.5) and a previous one recommended in the reviews (1.4.3) wouldn't work for me on OSX/FF3.6.1. Anyone have this working?
-
Ankur about 13 yearsi wish i could more precisely select a node to save, but this worked pretty well
-
Steve Campbell almost 12 yearsGreat answer, but...unrelated to the actual answer, whats with the for...loop syntax? It reads as obfuscated to me.
-
Karman Kertesz over 11 yearsThis is great, just misses the root element. Add this too: el.setAttribute("style", window.getComputedStyle(el).cssText);
-
Muhd over 11 yearsThis is what I do, but it involves manually copying the CSS for each element. What I think the OP wants ideally is something that can copy the CSS styles affecting an element and all nested elements -- copying it in one go like you do for the HTML.
-
Barney over 11 yearsGives an error: Error: SyntaxError: unterminated string literal
-
Hashbrown over 10 years@KonradDzwinel, I'm looking for a way to do this programmatically within a page (For printing a specific DOM subtree, just copy it to a new window and
print()
). How hard would it be (for you or for someone to looking to fork your repo) to make this in JS alone as a callable function? -
Konrad Dzwinel over 10 years@Hashbrown Mail me and we can talk details - I think it will be pretty simple.
-
Yassine edouiri over 10 years@KonradDzwinel thank you so much for the effort, but what if i want to get the node element with the php function 'file_get_contents($url)', is there any solution, here is my post : stackoverflow.com/questions/21419857/…
-
Viktor Tango about 10 yearsin chrome console, .querySelector returned null for me. So change it to the following and it worked: var el = document.getElementById("#someid"); el.setAttribute("style", window.getComputedStyle(el).cssText); var els = el.getElementsByTagName("*"); for(var i = -1, l = els.length; ++i < l;){ els[i].setAttribute("style", window.getComputedStyle(els[i]).cssText); }
-
Rodolfo Jorge Nemer Nogueira almost 10 yearsIE11 also works. But the option is accessible from right click directly on element.
-
dmnd almost 10 yearsWow, finally an example where IE devtools are superior!
-
xoofx over 9 yearsBest solution I have tried compare to all others listed in this page. The generated CSS+HTML is super clean while keeping original css names, meaning that the html is same as the original.
-
t31321 over 9 yearsGreat work! but is it possible to include the js code that acts on the element?
-
mc0e about 9 yearsAnd you say it was inspired by this question? You sure went the extra mile. That said, it doesn't actually work for me, and I'll say it for the sake of people with similar requirements. What I need is to keep the adaptive resizing stuff intact, and as I understand it, a solution based on getComputedStyle can't do that.
-
mc0e about 9 yearsThis is kinda helpful, but didn't solve my need for moving a page element with required css to another page. Scrapbook copies all of the pages css, whether it's needed or not for the selected part of the page, and it doesn't do any rewriting of the css that would help avoid the styles colliding with the css of another page.
-
mc0e about 9 yearsFor my need, this looks quite promising, as it avoids the limitations of getComputedStyle. I'm just too much of a javascript noob to be sure how to use it to get the actual text of the css.
-
mc0e about 9 yearsI've changed the usage to use
jQuery
instead of$
, which gets me a little way, but now I getSecurityError: The operation is insecure.
Any pointers? -
fro_oo almost 9 yearsThis is exactly what I need right now. Many thanks... thinking of this solution available 4 years ago...
-
fro_oo almost 9 yearsFor those who are not happy with the fixed sizes (getComputedStyle), you maybe should have a look at this : betterprogramming.com/htmlclipper.html
-
ken almost 9 yearsgreat one! works like a charm! i did some modification so that it can just run in chrome. just remove the 'export' and 'require' dependency , and copy them to chrome snippet. then can in the console, type
copy(divclip.bySel('.topbar'))
which will copy the processed output to the clipboard! ;) -
hajamie over 8 yearsI like how this keeps all the selectors as in the original.
-
Daniel Sokolowski over 8 yearsHoly crap that is awesome. Can confirm @xoofx 's findings that the HTML markup remains the same but wanted to comment further that it also outputs skeleton parent wrapping elements needed to truly match the style.
-
J.Tural over 8 yearsman it delete all the classes ... I need to reuse my work ... all ID is not accepted at all
-
David Keaveny over 8 yearsA +1 on the amazing plugin, for sure. However, it doesn't work with CSS sprites, which is a bit of a bummer.
-
Konrad Dzwinel over 8 years@DavidKeaveny can you please report that here: github.com/kdzwinel/SnappySnippet/issues ? Thanks!
-
David Keaveny over 8 years@KonradDzwinel someone has already beaten me to it: github.com/kdzwinel/SnappySnippet/issues/37.
-
Patoshi パトシ over 8 yearshow does this compare to snappy snippet chrome extension?
-
Mohammad Hossein Amri almost 8 years@Barney: he means, you should copy the answer there and make a snippet out of that. it's not the answer, but i suggest to make it a comment instead of an answer
-
Watson over 7 yearsUsed this. Couldn't get snappy snippet to work correctly (complex html & css). I can't believe this actually worked. And just so people know, I didn't see this feature in edge just explorer.
-
Iman Sedighi over 7 yearsIf it could take media queries was very helpful. Some DOM Elements have different styles in different sizes.
-
John over 7 yearsIs there any way to copy the associated Javascript or Jquery along with css ?
-
Slava over 7 yearshave an error: shellprod.msocdn.com/16.00.1692.002/en-US/JSC/O365ShellG2Plus.js:21 Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('portal.office.com') does not match the recipient window's origin ('null').
-
Matt almost 7 yearsWow, this worked perfectly in Microsoft Edge. Tried htmlclipper and snappysnippet but had issues retaining the responsiveness of elements I'm trying to copy.
-
Admin over 6 years@Watson right click the element and a button will say "copy element with styles" i.imgur.com/p5MeO3N.png
-
Ryan Chou over 5 yearsCould it copy the relevant javascript code bind to the selected element?
-
Hamza Zafeer over 5 yearsOops! We can't find that page.
-
Revious almost 5 years@KonradDzwinel; have you got suggestion on how to copy javascript too?
-
Sliq over 4 yearsTHAT'S engagement :) Wow, seeing a problem and writing software for it! My biggest respect to you!
-
snit80 over 4 yearsthis is amazing, works perfectly well.
-
cawecoy over 3 yearsIt gets no CSS3 media queries on IE 11, other than that, it's fine
-
Devmyselz almost 3 yearsIt has no effect, I click over elemetn, Copy with styles, but nothing was copied to
-
Devmyselz almost 3 yearsabsolutely non working this is only if html has the styles fitted, if css then this not work
-
Farhang Amaji about 2 yearsisnt it for copy text in textbox to clipboard? or I am making a mistake