Преобразование абсолютных значений в относительные CSS с помощью Javascript
мне было интересно, возможно ли и возможно преобразовать абсолютные значения CSS в относительные сохраняя пропорции использование Javascript. Решение должно работать как с 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:100%">
<svg width="83%" height="62.5%">
<rect width="3%" height="10%" x="3.4% y="4.8%"/>
</svg>
</div>
Я
- начинается с корневого элемента (
div
) - get
.width()
и.height()
ofthis
и родителем элемент - рассчитать долю (
this_height/parent_height*100
) - задать ширину и высоту соответственно
- повторите над детьми, установите child как root, начните с 1.
каковы общие подводные камни, которые могут произойти? Вероятно, есть теги, у которых нет набора ширины или высоты, например svg:g
. То есть нестандартные определения размера как в svg:circle
или атрибуты, о которых вы не думаете сначала, например svg:text
s dy
. Есть ли способ взять образованная догадка о производительности хита из-за массивных отражений? Что еще?
большое спасибо!
1 ответов
ОК. Итак, вот что я понимаю, что вы хотите сделать моими словами.
петля через все элементы DOM, преобразующие абсолютные размеры (т. е. высота / ширина в пикселях) в относительные размеры (т. е. высота/ширина в процентах). Это должно быть сделано с чувствительность к тому, задано ли измерение с помощью CSS или HTML атрибуты, которые можно использовать для элементов SVG.
это, как говорится, есть одно серьезное ограничение: если вы хотите преобразовать абсолютные размеры в относительные, используя <x>
в качестве корневого элемента, затем <x>
должны иметь абсолютные размеры. В противном случае относительные размеры внутри контейнера изменят размер в зависимости от их содержимого вместо общего размера родительского <x>
.
С этим условием то, что вы просите, довольно легко. Это алгоритм, который необходимо использовать.
- Пуск на
<body>
- дать
<body>
фиксированный размер - прогулка DOM-дерево для
<body>
выполнение следующих действий для каждого элемента- получить размеры элемента
- получить размеры родителя
- преобразовать в относительные размеры (ширина / родитель).
- применить относительные размеры
чтобы проверить мой код, я использовал следующий 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>
это JavaScript. Он довольно хорошо комментируется и обеспечивает достойный консольный выход. Для производственного кода я бы рекомендовал удалить журнал консоли.
пожалуйста, имейте в виду, что код выполняется не сразу, а с задержкой в 2 секунды. Таким образом, вы можете увидеть, как выглядит DOM, прежде чем он будет изменен.
для тех, кто не знает, следующий код вернет a
если он присутствует, а не false и b
иначе.
foo = a || b;
мы могли бы переписать, как один из двух ниже, но это более сжато.
foo = a ? a : b;
if(a)
foo = a
else
foo = b
здесь jsFiddle.
и код!
/** 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: круг или атрибуты, которые вы не думаете о сначала, как svg: тексты dy.
есть теги, которые не имеют width
/height
элемент. Однако использование jQuery должно дать нам немного больше надежности в этом отделе. Я не много работал с jQuery и SVG, но есть плагин для поддержки, если у нас возникнут проблемы с более неясными элементами.
есть ли способ сделать обоснованное предположение о производительности хита из-за массивных отражений?
я считаю, что этот код будет работать в O(m * n)
здесь m = delay for a single reflow
и n = number of nodes
. Отражения должны иметь довольно последовательное изменение, потому что мы преобразуем самые большие элементы перед самыми маленькими. но я могу оказаться неправ в этом последнем утверждении.
что еще?