如何扩展容器以使其增长并占用空间

37

我有一个容器,我想要缩放它的大小(放大和缩小),但同时也希望容器的扩展/收缩形式占据空间,而不仅仅是重叠在其他内容上。

更新

有一张图片,其中有一些 absolute 的 div ,它们被放置在坐标中,当缩小或放大时必须保持它们的相对位置(这就是为什么我使用 scale 的原因)。

var b = document.getElementById("outer");
var scale = 1;

function increase() {
  scale += 0.1
  b.style.transform = `scale(${scale})`;
}

function decrease() {
  scale -= 0.1
  b.style.transform = `scale(${scale})`;
}
#outer {
  overflow-x: auto position: relative;
  transform-origin: left top;
}

.pointer {
  width: 20px;
  height: 20px;
  background-color: orange;
  position: absolute;
}

#a1 {
  top: 50px;
  left: 150px;
}

#a2 {
  top: 150px;
  left: 50px;
}

#a3 {
  top: 250px;
  left: 550px;
}
<div>
  <button onclick="increase()">Increase</button>
  <button onclick="decrease()">Decrease</button>
</div>
<div id=outer>
  <img src="http://via.placeholder.com/600x350" />
  <div id="a1" class='pointer'>
  </div>
  <div id="a2" class='pointer'>
  </div>
  <div id="a3" class='pointer'>
  </div>
</div>
<div>
  please don't cover me
</div>

希望不要使用第三方库(除了jQuery),但可以考虑。

6个回答

21
CSS3的scale过渡效果像这样。不幸的是,缩放会重叠其他元素,因为它通过创建一个新的堆叠上下文(本质上将其所有内容相对于容器定位)使容器内容脱离流程——请参见相关文档描述:

如果属性具有与none不同的值,则将创建堆叠上下文。

来源:MDN

以下演示了通过强制缩放所有元素的演示:

var b, scale = 1, offset, pointers;

window.onload = function() {
  b = document.getElementById("outer");
  offset = b.getBoundingClientRect();
  pointers = Array.prototype.map.call(b.querySelectorAll('.pointer'), function(e) {
    return {
      el: e,
      offset: e.getBoundingClientRect()
    }
  });
}

function increase() {
  scale += 0.1;
  scaleIt();
}

function decrease() {
  scale -= 0.1;
  scaleIt();
}

function scaleIt() {
  b.style.width = scale * offset.width + 'px';
  b.style.height = scale * offset.height + 'px';
  Array.prototype.forEach.call(pointers, function(e) {
    e.el.style.width = scale * e.offset.width + 'px';
    e.el.style.height = scale * e.offset.height + 'px';
    e.el.style.top = scale * e.offset.top + 'px';
    e.el.style.left = scale * e.offset.left + 'px';
  });
}
#outer {
  /*overflow-x: auto;*/
  position: relative;
  transform-origin: left top;
}
.pointer {
  width: 20px;
  height: 20px;
  background-color: orange;
  position: absolute;
}
#outer > img {
  height: 100%;
}

#a1 {
  top: 50px;
  left: 150px;
}
#a2 {
  top: 150px;
  left: 50px;
}
#a3 {
  top: 250px;
  left: 550px;
}
<div>
    <button onclick="increase()">Increase</button>
    <button onclick="decrease()">Decrease</button>
</div>
<div id=outer>
  <img src="http://via.placeholder.com/600x350" />
  <div id="a1" class='pointer'>
  </div>
  <div id="a2" class='pointer'>
  </div>
  <div id="a3" class='pointer'>
  </div>
</div>
<div>
    please don't cover me
</div>


指针(黄色框)没有按比例缩放 : \ 。我目前的解决方法是随着进展不断重新调整高度。 - A. L
@A.Lau 我已经添加了 onload 以解决高度问题... 请现在检查一下,谢谢! - kukkuz
.style.left和top是用来干什么的?” - A. L
设置指针的lefttop,使它们的位置也随着缩放而比例变化 - kukkuz
1
我认为我所做的只是减小宽度/高度,以便其他元素会自动跟随,因为缩放可以保持它们的相对位置。 - A. L
1
这是一个非常糟糕的问题解决方案,不应该在任何情况下使用。 - sahbeewah

6

我尝试使用宽度和高度,我认为这将以你所期望的方式工作,添加一个小动画,你就可以使用它。

var b = document.getElementById("outer");
var b_width = document.getElementById("outer").offsetWidth;
var b_height = document.getElementById("outer").offsetHeight;

function increase()
{
    b_width += 10
    b_height += 10
    b.style.width = b_width+"px";
    b.style.height = b_height+"px";
}

function decrease()
{
    b_width -= 10
    b_height -= 10
    b.style.width = b_width+"px";
    b.style.height = b_height+"px";
}
#outer {
  background-color: red;
  padding: 1em;
  height: 80px;
  width: 80px;
  transform-origin: left top;
}

#inner {
  background-color: yellow;
  height: 50px;
  width: 100%;
}
<div>
    <button onclick="increase()">Increase</button>
    <button onclick="decrease()">Decrease</button>
</div>
<div id=outer>
  <div id=inner>
  </div>
</div>
<div>
    please don't cover me
</div>


抱歉,我认为我应该更新我的代码片段,因为它没有准确反映我的当前问题。我有一张图片和一组较小的 div 元素,它们充当指向图片的指针,因此我需要它们保持相对位置。我现在会进行更新。 - A. L

4

编辑:抱歉匆忙了,我是指更新容器

您可以添加一个容器。存储此容器的初始大小。现在,当您缩小内部元素时,请更新容器的宽度/高度以达到相同的比例。

var a = document.getElementById("outer-wrapper");
var b = document.getElementById("outer");
var scale = 1;
var aWidth = a.offsetWidth;
var aHeight = a.offsetHeight;

function increase()
{
    scale += 0.1
    b.style.transform = `scale(${scale})`;
    a.style.width = `${scale * aWidth}px`;
    a.style.height = `${scale * aHeight}px`;
}

function decrease()
{
    scale -= 0.1
    b.style.transform = `scale(${scale})`;
    a.style.width = `${scale * aWidth}px`;
    a.style.height = `${scale * aHeight}px`;
}
#outer {
  position: relative;
  transform-origin: left top;
}

.pointer {
  width: 20px;
  height: 20px;
  background-color: orange;
  position: absolute;
}

#a1 {
  top: 50px;
  left: 150px;
}
#a2 {
  top: 150px;
  left: 50px;
}
#a3 {
  top: 250px;
  left: 550px;
}
<div>
    <button onclick="increase()">Increase</button>
    <button onclick="decrease()">Decrease</button>
</div>
<div id="outer-wrapper">
  <div id="outer">
    <img src="http://via.placeholder.com/600x350" />
    <div id="a1" class='pointer'>
    </div>
    <div id="a2" class='pointer'>
    </div>
    <div id="a3" class='pointer'>
    </div>
  </div>
</div>
<div>
    please don't cover me
</div>


你意识到你覆盖了文本吗?这不应该发生。 - A. L

4
如果您的用例与您的示例一样简单,我认为您可能过于复杂化了。如果您需要子元素相对于父元素保持其相对位置,只需使用相对单位定义它们的位置,而不是绝对单位,然后让CSS渲染引擎处理即可。
在这里,我将父元素的宽度设置为容器的大小,使图像自动缩放以适应容器并设置其高度,使用了百分比而不是像素。

var b = document.getElementById("outer");
var width = 600;

function increase() {
  width = width * 1.1
  b.style.width = width + 'px';
}

function decrease() {
  width = width / 1.1
  b.style.width = width + 'px';
}
#outer {
  position: relative;
}

#outer img {
    width: 100%;
    height: auto;
}

.pointer {
  width: 3.333%;
  height: 5.714%;
  background-color: orange;
  position: absolute;
}

#a1 {
  top: 8.333%;
  left: 14.285%;
}

#a2 {
  top: 42.857%;
  left: 8.333%;
}

#a3 {
  top: 71.428%;
  left: 91.667%;
}
<div>
  <button onclick="increase()">Increase</button>
  <button onclick="decrease()">Decrease</button>
</div>
<div id=outer>
  <img src="http://via.placeholder.com/600x350" />
  <div id="a1" class='pointer'>
  </div>
  <div id="a2" class='pointer'>
  </div>
  <div id="a3" class='pointer'>
  </div>
</div>
<div>
  please don't cover me
</div>


3

最好的方法是为每个子元素使用动态百分比(%)高度、宽度和位置。

我们只需根据需要将所有像素值除以宽度或高度,在JS中简单地改变父容器的宽度,然后观察魔术发生 ;)

请查看下面的代码,适当的注释在更改值的地方添加。

var b = document.getElementById("outer");
var scale = 1;

function increase() {
  scale += 0.1
  // Just change the width of parent
  b.style.width = 600 * scale + "px";
}

function decrease() {
  scale -= 0.1
  // Just change the width of parent
  b.style.width = 600 * scale + "px";
}
#outer {
  overflow-x: auto;
  position: relative;
  transform-origin: left top;
  width: 600px; /* Give div static width for children to position correctly */
}

#outer img {
  width: 100%; /* Set image to stretch full width */
}

.pointer {
  width: 3.33%; /* 20px/600px*100% */
  padding-top: 3.33%;/* Don't use static height */
  background-color: orange;
  position: absolute;
}

#a1 {
  top: 14.28%;/* 50px/350px*100% */
  left: 25%;/* 150px/600px*100% */
}

#a2 {
  top: 42.85%;/* 150px/350px*100% */
  left: 8.33%;/* 50px/600px*100% */
}

#a3 {
  top: 71.42%;/* 250px/350px*100% */
  left: 91.66%; /* 550px/600px*100% */
}
<div>
  <button onclick="increase()">Increase</button>
  <button onclick="decrease()">Decrease</button>
</div>
<div id=outer>
  <img src="http://via.placeholder.com/600x350" />
  <div id="a1" class='pointer'>
  </div>
  <div id="a2" class='pointer'>
  </div>
  <div id="a3" class='pointer'>
  </div>
</div>
<div>
  please don't cover me
</div>

附注:要将标记显示为方框,我们将其宽度设置为填充顶部(当设置为百分比时与父元素宽度成比例),因此它始终显示为正方形。 ;)

在我看来,这样做更加可管理,因为您不必在JS中处理每个元素。


2
我会使用除了scale之外的其他属性,这些属性不像scale一样影响流程。你可以改变div的高度、宽度、边距、填充、字体大小等。

编辑:如果你真的想使用scale以一种统一的方式更改元素内部所有内容的大小,那么你可以有一个外部元素来更改宽度和高度,还有一个内部元素,你可以在其上更改scale来匹配外部元素的宽度和高度。外部元素会影响内容的流程。但我并不认为这是可取的,因为如果你只是放大容器内所有可能的图标和文本,那么它不会看起来很好,你可能希望无论容器的大小如何,保持容器内许多元素的大小相同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接