我们有以下HTML+CSS代码:
function parentH() {
let height = document.querySelector('#parent_range_H').value + 'px';
document.querySelector('#parent').style.height = height;
document.querySelector('#children').style.height = height;
}
function parentW() {
let width = document.querySelector('#parent_range_W').value + 'px';
document.querySelector('#parent').style.width = width;
document.querySelector('#children').style.width = width;
}
#parent {
width: 300px;
height: 300px;
padding: 10px;
border: 5px solid red;
}
#children {
width: 100%;
height: 100%;
background: green;
}
<p>Изменяем высоту (H) родителя: <input id="parent_range_H" type="range" min="10" max="300" value="300" step="1" name="parent_h" oninput="parentH()"></p>
<p>Изменяем ширину (W) родителя: <input id="parent_range_W" type="range" min="10" max="300" value="300" step="1" name="parent_w" oninput="parentW()"></p>
<div id="parent">
<div id="children"></div>
</div>
父元素<div id="parent">具有相同的宽度300px和高度尺寸300px,形成一个正方形。子元素的尺寸是其父元素尺寸<div id="children">的百分比(宽度 -100%和高度 - ),完全填满其所有空间,也形成一个正方形。100%当更改父元素的大小时,子元素会自动减小其大小,调整到其父元素的大小,从而违反其比例 - 正方形。
问题:在调整父元素的大小时,如何按比例调整子元素的大小?子元素必须是完全响应的正方形,并且对于父元素的高度或宽度的任何变化,子元素 - 正方形 - 必须始终保持为正方形。解决这个问题有哪些选择?
简短的回答:
最简单的方法是使用最适合此任务的 SVG。
viewBox对缩放和定位的影响。它将等于width,heightSVG。所以这个例子中的比例是
1:1AND 正方形将填充 SVG 的所有内部空间。
注意:
红色边框是SVG
的边框绿色边框是父容器的边框(在进一步的例子中)
JS 方法
getBBox()计算围绕正方形的框架的物理尺寸100х100px,也就是说,在我们的例子中,这些将是正方形本身的尺寸1.添加父容器
200х200px由于 SVG 具有固定尺寸,因此它不会缩放并适合其父容器。
100х100px2.父容器.container{width:300px; 高度:150 像素;}
3.容器{宽度:150px; 高度:300 像素;}
这些是固定大小的SVG 示例,其中正方形在父容器中占用的空间等于其自身的尺寸。
100х100px父容器中的 SVG 动态缩放
为此,将 SVG 的宽度和高度指定为百分比或未指定
width,height,相当于100%width="100%" height="100%" viewBox="0 0 100 100"#一%。.container{宽度:200px;高度:200px;
父容器是两倍大,但百分比 svg 完全填满了它。与上面的示例 1 进行比较,其中 SVG 具有固定大小
笔记!
正方形被拉伸到父容器的大小,因为容器的纵横比是 1:1,而正方形的纵横比是 1:1。所以在屏幕上它呈现
200х200px为父级的大小,但它的物理尺寸(在 SVG 中给出)保持不变100х100px,这表明getBBox()#2%。容器{宽度:300px;高度:100px;
父容器的宽度是高度的三倍,但它没有拉伸到全宽
100х100px,因为指定了参数preserveAspectRatio="xMinYMin meet",这迫使正方形保持其比例并紧贴左边缘#2.1。preserveAspectRatio="xMaxYMin 满足"
将正方形推到父容器的右边缘 -
xMax#2.2。保留纵横比=“无”
这个属性告诉 SVG 不要保持纵横比,因为
width="100%"SVG 它会拉伸到父元素的全宽#3%。容器{宽度:100px;高度:300px;
父容器的高度是 SVG 高度的 3 倍,因此 svg 正方形位于最顶部。
结论:
对于响应式 SVG,指定
viewBox.width height在 SVG 标头中,指定为百分比或不指定任何值,相当于 100%Чтобы SVG полностью заполнил родительский контейнер сделайте одинаковым соотношение
width, heightродительского контейнера иwidth, heightSVG (пример в этом ответе - #1%.)Не применяйте
preserveAspectRatio="none"это нарушает пропорции соотношения сторонUpdate
#4. Размеры родительского контейнера заданы в единицах относительно окна браузера
Понятно, что итоговые размеры родителя будут зависеть от разрешения и выбранного гаджета. Но заметьте, что физический размер квадрата SVG остается без изменений
100x100pxсм. вывод консоли.Зачем это нужно?
Это, размеры в исходной (inital) системе координат SVG. Далее мы можем, как угодно трансформировать SVG, выводить результаты на экран, сжимать, растягивать, но исходная система координат останется без изменений.
Связанные топики:
CSS
SVG
Ответ @Alexandr_TT
类似的问题在 ruSO 上很常见。因此,在我看来,添加一个现成且完全可用的解决方案并不是多余的,这可能对未来的许多用户有用。
这是解决问题的选项之一,使用
JavaScript代码和使用变量CSS:和相同的版本,只有代码的微小
JavaScript变化CSS。在这种情况下,为子元素设置了不同的定位方法。对于父元素,值保持不变——position: relative元素的位置是相对于其原始位置设置的。但是子元素将其位置更改为绝对定位 -position: absolute,其中坐标从父元素的边缘开始计算:作为一个单独的答案,我将再添加一个选项,我们将仅更改父元素的高度,仅更改
height子元素的宽度width。同时,我们仍然有一个子元素,它必须按比例改变其大小,并始终保持完全自适应的正方形。Resize элемента может происходить из-за изменения размеров окна браузера, из-за вставки текста / загрузки картинки, вручную (css-resize: both) или скриптом - из любого места кода.
На JS не нашел простого решения, который капитально покроет все случаи жизни. Поэтому разбиваю ответ на несколько конкретных вариантов:
1: Есть ровно один элемент (например, главное окно мини-игры), его нужно сделать квадратным, и обновлять размеры только при resize окна браузера.
1.1: То же самое с защитой от дурака (Если каждое обновление размеров влечет за собой тяжелые изменения, пусть картинка не обновляется, если начнут играться и быстро ресайзить браузер)
2: Если предстоит создавать большое количество таких зависимых блоков (плохо представляю, зачем), приятно было бы иметь функцию, которая запомнит, от кого и к кому нужно передать размеры, и в каких пропорциях. А при изменении размеров, лишь вызвать метод, обновляющий размеры зависимых элементов. Примерно так:
Резиновые блоки, обновляются и от input-ов, и при resize окна:
Блоки не обязательно должны быть родительскими, могут быть где угодно. К одному блоку можно привязать несколько других, в разных местах.
2.1: Применительно к коду из вопроса:
3. Заранее не известно, откуда может происходить resize, но очень нужно контролировать размеры блока. ResizeObserver
Поддерживается во всех современных браузерах.
Если нужна поддержка старых, можно написать функцию, которая, например, раз в полсекунды (
setInterval(fn, 500)) или 60 раз в секунду (requestAnimationFrame) проверяет размер нужного блока и в случае обнаружения изменений, выполняет функцию. Или гуглить → resize observer polyfill