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

245,472

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!

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.

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)

Element Source with Style

Result:

Element Source with Style 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

enter image description here

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.

Share:
245,472
Ankur
Author by

Ankur

i write software for a living. someday a robot is going to take my job. i can't wait.

Updated on July 21, 2022

Comments

  • Ankur
    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
    peteorpeter about 13 years
    Scrapbook 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
    Ankur about 13 years
    i wish i could more precisely select a node to save, but this worked pretty well
  • Steve Campbell
    Steve Campbell almost 12 years
    Great answer, but...unrelated to the actual answer, whats with the for...loop syntax? It reads as obfuscated to me.
  • Karman Kertesz
    Karman Kertesz over 11 years
    This is great, just misses the root element. Add this too: el.setAttribute("style", window.getComputedStyle(el).cssText);
  • Muhd
    Muhd over 11 years
    This 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
    Barney over 11 years
    Gives an error: Error: SyntaxError: unterminated string literal
  • Hashbrown
    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
    Konrad Dzwinel over 10 years
    @Hashbrown Mail me and we can talk details - I think it will be pretty simple.
  • Yassine edouiri
    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
    Viktor Tango about 10 years
    in 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
    Rodolfo Jorge Nemer Nogueira almost 10 years
    IE11 also works. But the option is accessible from right click directly on element.
  • dmnd
    dmnd almost 10 years
    Wow, finally an example where IE devtools are superior!
  • xoofx
    xoofx over 9 years
    Best 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
    t31321 over 9 years
    Great work! but is it possible to include the js code that acts on the element?
  • mc0e
    mc0e about 9 years
    And 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
    mc0e about 9 years
    This 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
    mc0e about 9 years
    For 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
    mc0e about 9 years
    I've changed the usage to use jQuery instead of $, which gets me a little way, but now I get SecurityError: The operation is insecure. Any pointers?
  • fro_oo
    fro_oo almost 9 years
    This is exactly what I need right now. Many thanks... thinking of this solution available 4 years ago...
  • fro_oo
    fro_oo almost 9 years
    For those who are not happy with the fixed sizes (getComputedStyle), you maybe should have a look at this : betterprogramming.com/htmlclipper.html
  • ken
    ken almost 9 years
    great 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
    hajamie over 8 years
    I like how this keeps all the selectors as in the original.
  • Daniel Sokolowski
    Daniel Sokolowski over 8 years
    Holy 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
    J.Tural over 8 years
    man it delete all the classes ... I need to reuse my work ... all ID is not accepted at all
  • David Keaveny
    David Keaveny over 8 years
    A +1 on the amazing plugin, for sure. However, it doesn't work with CSS sprites, which is a bit of a bummer.
  • Konrad Dzwinel
    Konrad Dzwinel over 8 years
    @DavidKeaveny can you please report that here: github.com/kdzwinel/SnappySnippet/issues ? Thanks!
  • David Keaveny
    David Keaveny over 8 years
    @KonradDzwinel someone has already beaten me to it: github.com/kdzwinel/SnappySnippet/issues/37.
  • Patoshi パトシ
    Patoshi パトシ over 8 years
    how does this compare to snappy snippet chrome extension?
  • Mohammad Hossein Amri
    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
    Watson over 7 years
    Used 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
    Iman Sedighi over 7 years
    If it could take media queries was very helpful. Some DOM Elements have different styles in different sizes.
  • John
    John over 7 years
    Is there any way to copy the associated Javascript or Jquery along with css ?
  • Slava
    Slava over 7 years
    have an error: shellprod.msocdn.com/16.00.1692.002/en-US/JSC/O365ShellG2Plu‌​s.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
    Matt almost 7 years
    Wow, this worked perfectly in Microsoft Edge. Tried htmlclipper and snappysnippet but had issues retaining the responsiveness of elements I'm trying to copy.
  • Admin
    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
    Ryan Chou over 5 years
    Could it copy the relevant javascript code bind to the selected element?
  • Hamza Zafeer
    Hamza Zafeer over 5 years
    Oops! We can't find that page.
  • Revious
    Revious almost 5 years
    @KonradDzwinel; have you got suggestion on how to copy javascript too?
  • Sliq
    Sliq over 4 years
    THAT'S engagement :) Wow, seeing a problem and writing software for it! My biggest respect to you!
  • snit80
    snit80 over 4 years
    this is amazing, works perfectly well.
  • cawecoy
    cawecoy over 3 years
    It gets no CSS3 media queries on IE 11, other than that, it's fine
  • Devmyselz
    Devmyselz almost 3 years
    It has no effect, I click over elemetn, Copy with styles, but nothing was copied to
  • Devmyselz
    Devmyselz almost 3 years
    absolutely non working this is only if html has the styles fitted, if css then this not work
  • Farhang Amaji
    Farhang Amaji about 2 years
    isnt it for copy text in textbox to clipboard? or I am making a mistake