使用Javascript将绝对CSS值转换为相对CSS值
我想知道在使用Javascript保持比例的同时,将绝对CSS值转换为相对CSS值是否可行。解决方案必须与HTML以及SVG标记一起使用 假设你得到了这个:使用Javascript将绝对CSS值转换为相对CSS值,javascript,html,css,svg,Javascript,Html,Css,Svg,我想知道在使用Javascript保持比例的同时,将绝对CSS值转换为相对CSS值是否可行。解决方案必须与HTML以及SVG标记一起使用 假设你得到了这个: <div style="width:100%;height:800px"> <svg width="1000" height="500"> <rect width="30" height="50" x="34" y="24"/> </svg> </div> 你
<div style="width:100%;height:800px">
<svg width="1000" height="500">
<rect width="30" height="50" x="34" y="24"/>
</svg>
</div>
你将如何做到这一点
<div style="width:100%;height:100%">
<svg width="83%" height="62.5%">
<rect width="3%" height="10%" x="3.4% y="4.8%"/>
</svg>
</div>
嗯。用我自己的话来说,这就是我理解你想要做的
循环通过所有DOM元素转换绝对维度(即。
以像素表示的高度/宽度)转换为相对尺寸(即。
高度/宽度(以百分比表示)。这一点应该通过
是否使用CSS或HTML设置维度的敏感性
属性,以便可用于SVG元素
也就是说,有一个主要限制:如果要使用
作为根元素将绝对维度转换为相对维度,那么
必须具有绝对维度。否则,容器内的相对尺寸将根据其内容而不是父对象的总体尺寸更改大小
有了这个规定,你的要求就相当容易了。这就是需要使用的算法
从
给出固定尺寸
为
遍历DOM树,对每个元素执行以下操作
获取元素的尺寸
获取父对象的维度
转换为相对尺寸(即宽度/父宽度)
应用相对尺寸
为了测试我的代码,我使用了以下HTML。它既有您包含的代码,也有一个子元素大于其父元素的实例。这是我确定为要测试的边界条件的一种情况
<div style="width:100%;height:800px">
<svg width="150" height="200" style="background: red;">
<rect width="30" height="50" x="34" y="24"/>
</svg>
<div style="background: green; width: 50px; height: 50px;">
<p style="background: teal; width: 100px; height: 20px;">Content</p>
</div>
</div>
我们可以像下面两个一样重写,但这更简洁
foo = a ? a : b;
if(a)
foo = a
else
foo = b
这是一本书
还有密码
/** convertToRelative
* Convert absolute width/height to relative. Should work for
* Both HTML and SVG objects. Tries to use CSS attributes, falls
* back on HTML attributes.
*/
function convertToRelative(element) {
// Get Element and Parent
element = $(element);
parent = element.parent();
// If there is no valid with, we need to use attributes
var useAttr = !element.width();
// Get dimensions from css or attributes
var width = element.width() || element.attr('width');
var height = element.height() || element.attr('height');
var pWidth = parent.width() || parent.attr('width');
var pHeight = parent.height() || parent.attr('height');
// Find relative dimensions
var relWidth = (width / pWidth) * 100.0;
var relHeight = (height / pHeight) * 100.0;
// Log info
console.log(element);
console.log("1: "+ parent.height() +", 2: "+ parent.attr('height'));
console.log("Width: "+ width +", Height: "+ height);
console.log("PWidth: "+ pWidth +", pHeight: "+ pHeight);
console.log("relWidth: "+ relWidth +", relHeight: "+ relHeight);
// Clear current stylings
element.removeAttr('width');
element.removeAttr('height');
// Apply relative dimensions
if (useAttr) {
element.attr('width', relWidth +'%');
element.attr('height', relHeight +'%');
} else {
element.width(relWidth +"%");
element.height(relHeight +"%");
}
}
/** walk
* Walk through a DOM element and all its sub elements running
* the convertToRelative function to convert absolute positions
* to relative positions.
* DOES NOT CONVERT THE FIRST ELEMENT, ONLY CHILDREN.
*/
function walk(element) {
$(element).children().each(function() {
convertToRelative(this);
walk(this);
});
}
/** fixBody
* In order to play with relative dimensions for children of the
* body, we need to fix the dimensions of the body. Otherwise it
* will resize as we begin to use relative dimensions.
*/
function fixBody() {
$('body').css('width', $('body').width() +"px");
$('body').css('height', $('body').height() +"px");
}
// Walk the body and all children on a 2 second delay.
setTimeout(function() {
console.log('Running Conversion');
fixBody()
walk('body');
console.log('Conversion Finished');
}, 2000);
如果这不是你想要的,或者你遇到了问题,请告诉我
谢谢你的提问
可能发生的常见陷阱有哪些
最常见的陷阱是错误的转换。在转换过程中会出现一些错误,结果DOM看起来与输入完全不同
可能有一些标记没有设置宽度或高度,比如svg:g。还有一些非标准的大小定义,如svg:circle中的大小定义,或者是您一开始没有想到的属性,如svg:text
有些标记没有宽度
/高度
元素。然而,在这个部门,使用jQuery应该会让我们更加健壮。我很少使用jQuery和SVG,但如果我们遇到更晦涩的元素的问题,有一个插件可以提供支持
有没有办法对由于大规模回流造成的性能损失进行有根据的猜测
我相信该代码将在O(m*n)
中运行,其中m=单次回流的延迟
和n=节点数
。回流焊应该有一个相当一致的变化,因为我们是在最小元素之前转换最大的元素但最后一句话可能证明我错了
还有什么
由于几个原因,这将非常困难。想想SVG的
和transform
属性以及CSS转换。如果我理解正确,您的SVG缩放应该通过viewBox
属性来解决。这背后的目的是什么?@screenmutt:类似于图形历史的。我想为历史中的图像复制组件的DOM。天哪!你试过了吗?谢谢你的努力!您认为我们的基本算法可以扩展到处理整个SVG规范吗?我说的是剪贴画、多段线、变换(平移和缩放,尤其是旋转应该是独立的)等等。我相信它可以。我只是不太熟悉。
/** convertToRelative
* Convert absolute width/height to relative. Should work for
* Both HTML and SVG objects. Tries to use CSS attributes, falls
* back on HTML attributes.
*/
function convertToRelative(element) {
// Get Element and Parent
element = $(element);
parent = element.parent();
// If there is no valid with, we need to use attributes
var useAttr = !element.width();
// Get dimensions from css or attributes
var width = element.width() || element.attr('width');
var height = element.height() || element.attr('height');
var pWidth = parent.width() || parent.attr('width');
var pHeight = parent.height() || parent.attr('height');
// Find relative dimensions
var relWidth = (width / pWidth) * 100.0;
var relHeight = (height / pHeight) * 100.0;
// Log info
console.log(element);
console.log("1: "+ parent.height() +", 2: "+ parent.attr('height'));
console.log("Width: "+ width +", Height: "+ height);
console.log("PWidth: "+ pWidth +", pHeight: "+ pHeight);
console.log("relWidth: "+ relWidth +", relHeight: "+ relHeight);
// Clear current stylings
element.removeAttr('width');
element.removeAttr('height');
// Apply relative dimensions
if (useAttr) {
element.attr('width', relWidth +'%');
element.attr('height', relHeight +'%');
} else {
element.width(relWidth +"%");
element.height(relHeight +"%");
}
}
/** walk
* Walk through a DOM element and all its sub elements running
* the convertToRelative function to convert absolute positions
* to relative positions.
* DOES NOT CONVERT THE FIRST ELEMENT, ONLY CHILDREN.
*/
function walk(element) {
$(element).children().each(function() {
convertToRelative(this);
walk(this);
});
}
/** fixBody
* In order to play with relative dimensions for children of the
* body, we need to fix the dimensions of the body. Otherwise it
* will resize as we begin to use relative dimensions.
*/
function fixBody() {
$('body').css('width', $('body').width() +"px");
$('body').css('height', $('body').height() +"px");
}
// Walk the body and all children on a 2 second delay.
setTimeout(function() {
console.log('Running Conversion');
fixBody()
walk('body');
console.log('Conversion Finished');
}, 2000);