How to move all computed CSS styles from one element and apply them to a different element using JavaScript?
I have an external stylesheet that is applying some styles to a given element. I want to be able to move those styles (using JavaScript) to a different element entirely, without having prior knowledge of the styles that are being applied.
The CSS:
td { padding: 5px }
div { }
The HTML:
<td>
<div>
Apply the TD styles to this DIV (instead of the TD).
</div>
</td>
The JavaScript:
$(document).ready(function(){
$('tr').children('td').each(function(){
//move the td styles to div
});
});
How can I achieve this?
Update: To be clear, I have no control over the CSS. I have no way of knowing what styl开发者_StackOverflowes may be applied. The problem that I'm trying to solve is being able to take an element and copy its styles (which may be unknown) and apply them to a different element.
This is a solution I figured out, it mixes document.defaultView.getComputedStyle and jQuery's .css():
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" > </script>
<link href="style.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div id="test" style="background-color: #FF7300">
<p>Hi</p>
</div>
<a href="#" id="button">Apply styles</a>
<script>
$("#button").click(function() {
var element = document.getElementById("test");
$("#victim").css(document.defaultView.getComputedStyle(element, null));
});
</script>
<div id="victim">
<p>Hi again</p>
</div>
</body>
//style.css
#test {
border: 3px solid #000000;
}
What this does is copy the computed style object, including the style.css and the inline style, and set it to the other div using jQuery's .css()
I hope I didn't misunderstand the question and that this is what you need.
Edit: Something I forgot is that you asked to 'move' the style rather than copy it. It's very simple to remove styles from the previous div using jQuery's .removeClass() and using .attr() to remove the style attribute, but you have to keep in mind that if there are any style rules being applied to the element's ID, there's no way to keep them from being applied.
EDIT: This answer was written before the question was clarified.
Give your elements IDs, like this:
<td id="td_element" style="padding:5px">
<div id="div_element">
Apply the TD styles to this DIV (instead of the TD).
</div>
</td>
And use
var td_element = $('#td_element')
$('#div_element').attr('style', td_element.attr('style'));
td_element.removeAttr('style');
Of course you could use a class instead - or you may have the elements from previous javascript code. You'll need to decide the best way to reference the elements yourself.
I know this will look rough but it works. Initially copying all the computed styles from <td>
and applying them to <div>
is easy with this plugin from Mike Dunn. The troublesome bit is in removing the styles from the <td>
after they have been copied. From what I can tell, the only thing you can do is manually reset them to default with .css()
.
Working Example
$.fn.copyCSS = function (source) {
var dom = $(source).get(0);
var dest = {};
var style, prop;
if (window.getComputedStyle) {
var camelize = function (a, b) {
return b.toUpperCase();
};
if (style = window.getComputedStyle(dom, null)) {
var camel, val;
if (style.length) {
for (var i = 0, l = style.length; i < l; i++) {
prop = style[i];
camel = prop.replace(/\-([a-z])/, camelize);
val = style.getPropertyValue(prop);
dest[camel] = val;
}
} else {
for (prop in style) {
camel = prop.replace(/\-([a-z])/, camelize);
val = style.getPropertyValue(prop) || style[prop];
dest[camel] = val;
}
}
return this.css(dest);
}
}
if (style = dom.currentStyle) {
for (prop in style) {
dest[prop] = style[prop];
}
return this.css(dest);
}
if (style = dom.style) {
for (prop in style) {
if (typeof style[prop] != 'function') {
dest[prop] = style[prop];
}
}
}
return this.css(dest);
};
$('td').click(function () {
$('div').copyCSS('td');
$('td').removeAttr('style');
$("td").css({
'font-family': 'none',
'font-size': 'none',
'font-weight': 'none',
'font-style': 'none',
'color': '#000',
'text-transform': 'none',
'text-decoration': 'none',
'letter-spacing': 'none',
'word-spacing': 'none',
'line-height': 'none',
'text-align': 'none',
'vertical-align': 'none',
'direction': 'none',
'background-color': 'transparent',
'background-image': 'none',
'background-repeat': 'none',
'background-position': 'none',
'background-attachment': 'none',
'opacity': '1',
'width': 'none',
'height': 'none',
'top': '',
'right': '',
'bottom': '',
'left': '',
'margin-top': '0',
'margin-right': '0',
'margin-bottom': '0',
'margin-left': '0',
'padding-top': '0',
'padding-right': '0',
'padding-bottom': '0',
'padding-left': '0',
'border-top-width': '0',
'border-right-width': '0',
'border-bottom-width': '0',
'border-left-width': '0',
'border-top-color': '0',
'border-right-color': '0',
'border-bottom-color': '0',
'border-left-color': '0',
'border-top-style': '0',
'border-right-style': '0',
'border-bottom-style': '0',
'border-left-style': '0',
'position': 'static',
'display': '',
'visibility': 'visible',
'z-index': 'auto',
'overflow-x': 'auto',
'overflow-y': 'auto',
'white-space': 'normal',
'clip': 'auto',
'float': 'none',
'clear': 'none',
'cursor': 'default',
'list-style-image': 'none',
'list-style-position': '0',
'list-style-type': 'disc',
'marker-offset': '',
'padding': '0',
'transition': 'none',
'border-radius': 'none'
});
});
Note: obviously I have not included a reset for all possible styles.
EDIT: Code corrected
$('div').attr('style', $('td').attr('style'));
If you want to move just add this line afterwards
$('td').attr('style', '');
I realize that this looks contrived but I have no other selectors to work with here. Normally you'd want to do this with an id or a class instead of the actual attribute.
Don't move the styles is my short answer - find another way. Can you load another stylesheet after the stylesheet being loaded? If so, add a stylesheet that overrides the td and div padding defined in the stylesheet you're having to reference.
What about applying the actual TD style to a class? Then just modify the class of the TD and the DIVs. Or you dont have access to the stylesheet?
The CSS:
.class_name { padding: 5px }
The HTML:
<td class="class_name">
<div>
Apply the TD styles to this DIV (instead of the TD).
</div>
</td>
The JavaScript:
$(document).ready(function(){
$('.class_name').removeClass('class_name').children('div').addClass('class_name');
});
You can try the following steps to copy the styles defined for particular element in stylesheets and <style>
tags ( code is little bit lengthy ):
- Get the contents of original stylesheets using ajax. and contents of each
<style>
tags - Parse the css contents into array
- For each selectors in the parsed stylesheet, compare it's dom element with target dom element ( from which you are copying the styles ). if any of them matches , then apply styles corresponding to mathced selector to the required element
Here is the code:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<style>
#source { width: 100px; height: 100px; background-color: black; }
</style>
<link rel="stylesheet" href="style.css">
</head>
<body>
<table>
<tr>
<td id="source"></td>
</tr>
</table>
<div id="target"></div>
</body>
<script>
var source = $('#source'); // source
var target = $( '#target' ); // target
$( 'link[rel="stylesheet"]' ).each( function() {
$.get( $(this).attr( 'href' ), {}, function( data ) {
var css_obj = parse_css( data );
copy_css( css_obj, source, target );
});
});
$( 'style' ).each( function() {
var css = $(this).text();
var css_obj = parse_css( css );
copy_css( css_obj, source, target );
})
function copy_css( css_obj, source, target ) {
for( selector in css_obj ) {
if( $(selector)[0] === source[0] ) { // compare raw dom elements
for( prop in css_obj[selector] ) {
target.css( prop, css_obj[selector][prop] );
}
}
}
}
function parse_css( css ) {
var css = css.replace( /[\s\n\t]+/g, ' ' ); // remove extra spaces, tabs and newlines
css = css.replace( /\/\*(.|\n)+\*\//g, '' ); // remove comments
css = css.split( '}' ); // split into groups
var css_obj = []; // array to hold parsed css
for( i in css ) {
if( css[i] == false ) continue;
var chunks = css[i].split( '{' );
var selector = $.trim( chunks[0] );
var style_defs = [];
chunks = chunks[1].split( ';' );
for( j in chunks ) {
if( chunks[j] == false ) continue;
var style_def = chunks[j].split( ':' );
var property = $.trim( style_def[0] );
var value = $.trim( style_def[1].replace( /\;$/, '' ) );
style_defs[property] = value;
}
css_obj[selector] = style_defs;
}
return css_obj;
}
</script>
Here's how I do it:
var elFrom = document.getElementById('fromID');
var computedStyle = document.defaultView.getComputedStyle(elFrom,null);
$.each(computedStyle,function(key,value) {
$('#toID').css(value,$(elFrom).css(value));
});
And a more generalized solution from the provided answers..
HTML
<td style="padding:5px">
<div class="inherit">
Apply the TD styles to this DIV (instead of the TD).
</div>
</td>
JS
$('.inherit')
.attr('style', $(this)
.parents('td')
.attr('style')
)
.parents('td')
.removeAttr('style');
精彩评论