The window.getComputedStyle()
method gives the values of all the CSS properties of an element after applying the active stylesheets and resolving any basic computation those values may contain.
The demonstration below omits keeping track of pseudo-elements, but that functionality could be shoehorned in using window.getComputedStyle(element[, pseudoElt]);
where:
element
The Element for which to get the computed style.
pseudoElt
Optional
A string specifying the pseudo-element to match. Must be omitted (or null) for regular elements.
Usage
- Add the code to the HTML document you're working on, via
<script>
or the developer console.
- Use
setInitStyles()
to set or reset the state of the styles of each of the elements, which is compared against when calling differenceEngine()
.
- Use
differenceEngine()
to get the difference between the styles set when last calling setInitStyles()
and now.
Example
This code would benefit from some optimization, and alteration to taste i.e. the output format may be undesirable.
The snippet will run as expected (tested in Chrome), but since large amounts of data are logged to the console
, I disabled the snippet's console (for efficiency) so you'll need to see the output in your browser's.
const compressedStyles = ( e ) => {
const ucs = window.getComputedStyle( e );
var s, cs = {};
for ( s in ucs ) {
if ( ucs.hasOwnProperty( s ) && /[^0-9]+/.test( s ) ) {
cs[ s.replace( /([A-Z])/g, "-$1" ).toLowerCase() ] = ucs[ s ];
}
}
return cs;
},
setElementStyles = ( e ) => {
e.stylesInit = compressedStyles( e );
e.stylesDiff = {}; // while we're here
},
allTheThings = () => {
var att = Array.from( document.body.querySelectorAll( "*:not( script )" ) );
att.unshift( document.body );
return att;
},
setInitStyles = () => {
allTheThings().forEach( setElementStyles );
},
differenceEngine = () => {
allTheThings().forEach( ( e ) => {
if ( e.stylesInit ) {
const cs = compressedStyles( e );
var s, css, ess;
for ( s in e.stylesInit ) {
ess = e.stylesInit[ s ].toString();
css = cs[ s ].toString();
if ( ess != css ) {
e.stylesDiff[ s ] = { "curr": css, "init": ess };
}
}
console.log( e, e.stylesDiff );
} else {
setElementStyles( e ); // set current styles on new elements
}
} );
};
console.info( "Setting the initial styles" );
setInitStyles();
console.info( "Changing the style of one of the elements" );
document.querySelector( "div" ).style.border = "2px solid red";
console.info( "What's the difference?" );
differenceEngine();
console.info( "Resetting the style of the element" );
document.querySelector( "div" ).removeAttribute( "style" );
console.info( "What's the difference?" );
differenceEngine();
console.info( "Changing the class of one of the elements" );
document.querySelector( "p" ).classList.add( "foo" );
console.info( "What's the difference?" );
console.warn( "Properties that inherit from color have also changed" );
differenceEngine();
console.info( "Resetting the class of the element" );
document.querySelector( "p" ).classList.remove( "foo" );
console.info( "What's the difference?" );
differenceEngine();
p.foo {
color: red;
}
<div>
<p>Foo</p>
<p>Bar</p>
<p>Baz</p>
</div>
Made with love of the chase, as a suggestion, not a final solution.
Since getComputedStyle()
does exactly that, the results of the above can be a little less than helpful.
Turning our attention to the actual DevTools, we can inspect them (when popped out and focussed) and run scripts on the inspector.
This is a step toward extending the DevTools with a Chrome Extension.
Whilst pondering the build process, I stumbled upon SnappySnippet; a Chrome Extension inspired by a Stack Overflow question that supposedly (I have not used it) makes the creation of Snippets from web pages easy.
That extension may provide functionality that would effectively answer your question, but in case it doesn't (and for fun), I have started to work on what may become another Chrome Extension.
Be aware, this process may be long, slow and fruitless; if at any point I create anything more useful than the code below, I will return to update this answer.
I hereby present my latest kludge! \o/
document.querySelectorAll( ".styles-section" ).forEach( ( e ) => {
var output;
const selector = e.querySelector( ".selector" ).textContent,
properties = e.querySelector( ".style-properties" )
.shadowRoot.querySelectorAll( ".tree-outline > li" );
if ( properties ) {
output = selector + " {\n";
properties.forEach( ( p ) => {
const property = p.querySelector( ".webkit-css-property" ).textContent,
value = p.querySelector( ".value" ).textContent;
if ( p.classList.contains( "inactive" ) ) {
output += "\t/* " + property + ": " + value + "; */\n";
} else {
output += "\t" + property + ": " + value + ";\n";
}
} );
}
console.log( output + "}" );
} );
This code, when run on an inspector on an inspector (not a typo), will spit out a pretty copy of the content of the styles pane for the currently selected element in the inspector of the original HTML.
Mhmm - kludge.
Instead of spitting out a bunch of text, it could be relatively simply tweaked to spit out an object of data, which like in the code of my first response, could be compared with other snapshots to get the difference.
And, since this code is being run on the inspector, and not on the document being manipulated, it is a solid step toward exactly what we could achieve with a DevTools Extension.
I will continue fiddling with this, and update this answer as I go, but don't hold your breath.
Manual Solution (in lieu of wizardry)
Although not even remotely high-tech, there is a very simple and reliable method to keep track of changes one makes to element.style
and CSS from resources or <style>
sheets:

As you can see in the screenshot above, we can add comments to any value of any property we change or add, showing what the value used to be, or that the value is entirely new.
And of course, if we want to remove anything, we can just uncheck the checkbox to the left of the property, so the value is maintained.