缩放可滚动容器中的居中div

Ahm*_*otb 23 html javascript css

我正在尝试对以可滚动容器div为中心的div进行缩放转换.

我用来反映转换后的新div大小的技巧是使用包装器并为其设置新的宽度/高度,以便父级可以正确显示滚动条.

.container {
    position: relative;
    border: 3px solid red;
    width: 600px; height: 400px;
    background-color: blue;
    overflow-x: scroll; overflow-y: scroll;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
}
.wrapper {
    order: 1;
    background-color: yellow;
}
.content-outer {
    width: 300px;
    height: 200px;
    transform-origin: 50% 50%;
    /*transform-origin: 0 0;*/
}
.content-outer.animatted {
    animation: scaleAnimation 1s ease-in forwards;
}
.content-outer.animatted2 {
    animation: scaleAnimation2 1s ease-in forwards;
}
.content-inner {
    width: 300px;
    height: 200px;
    background: linear-gradient(to right, red, white);
}
Run Code Online (Sandbox Code Playgroud)

如果转换原点是0,0 div在没有动画跳跃的情况下居中,但滚动条不正确.如果原点位于中间,则div位置和滚动条都会被错过

我尝试了两种方法来进行居中,使用flexbox(http://jsfiddle.net/r3jqyjLz/1/)和使用负边距(http://jsfiddle.net/roLf5tph/1/).

有一个更好的方法吗 ?

Mat*_*ing 8

这就是你追求的吗?

我使用CSS过渡来缩放动画.

#centered {
    background-image: linear-gradient(to bottom,yellow,red);
    height: 200px;
    transform: scale(1);
    transition: transform 1s ease-out;
    width: 200px;
}

#scrollable {
    align-items: center;
    border: 1px solid red;
    display: flex;
    height: 300px;
    justify-content: center;
    overflow: auto;
    width: 300px;
}
Run Code Online (Sandbox Code Playgroud)

更新#1

这个怎么样?

  • 使用旧学校绝对居中(绝对位置)
  • 我看到了关于flexbox的观点.当居中元素大于其容器时,似乎flexbox居中有一些限制.


Abh*_*lks 5

我假设您所遇到的部分问题可归纳为:

  1. 您的内部有一个复杂的结构div,您希望将其作为一个组进行扩展.(如果它是单个元素,使用矩阵就可以轻松实现).
  2. 当内部div缩放超出容器的边界时,如果不控制宽度/高度,则不会获得滚动条.
  3. 您希望内部div保持居中,同时,滚动条应该反映正确的位置.

有了这个,有两个(实际上是三个)简单的选项.

选项1:

在问题中使用相同的标记,div当比例因子低于1时,您可以保持居中.对于高于1的比例因子,您可以将其更改为左上角.的overflow: auto,因为在容器上会照顾滚动的自身div来缩放(通过变换)被包裹的另一个内div.你真的不需要Javascript.

这解决了您的问题1和2.

小提琴1:http://jsfiddle.net/abhitalks/c0okhznc/

小片1:

* { box-sizing: border-box; }
#container {
    position: relative;
    border: 1px solid red; background-color: blue;
    width: 400px; height: 300px;
    overflow: auto;
}
.wrapper {
    position: absolute; 
    background-color: transparent; border: 2px solid black;
    width: 300px; height: 200px;
    top: 50%; left: 50%;
    transform-origin: top left;
    transform: translate(-50%, -50%); 
    transition: all 1s;
}
.box {
    width: 300px; height: 200px;
    background: linear-gradient(to right, red, white);
    border: 2px solid yellow;
}
.inner { width:50px; height: 50px; background-color: green; }

#s0:checked ~ div#container .wrapper { transform: scale(0.5) translate(-50%, -50%); }
#s1:checked ~ div#container .wrapper { transform: scale(0.75) translate(-50%, -50%); }
#s2:checked ~ div#container .wrapper { transform: scale(1) translate(-50%, -50%); }
#s3:checked ~ div#container .wrapper { top: 0%; left: 0%; transform-origin: top left; transform: scale(1.5) translate(0%, 0%); }
#s4:checked ~ div#container .wrapper { top: 0%; left: 0%; transform-origin: top left; transform: scale(2) ; }
#s5:checked ~ div#container .wrapper { top: 0%; left: 0%; transform-origin: top left; transform: scale(3) ; }
Run Code Online (Sandbox Code Playgroud)
<input id="s0" name="scale" data-scale="0.5" type="radio" />Scale 0.5
<input id="s1" name="scale" data-scale="0.75" type="radio" />Scale 0.75
<input id="s2" name="scale" data-scale="1" type="radio" checked />Scale 1
<input id="s3" name="scale" data-scale="1.5" type="radio" />Scale 1.5
<input id="s4" name="scale" data-scale="2" type="radio" />Scale 2
<input id="s5" name="scale" data-scale="3" type="radio" />Scale 3
<hr>
<div id="container">
    <div id="wrapper" class="wrapper">
        <div id="box" class="box">
            <div class="inner"></div>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

但这会产生另一个问题.该overflow:auto会导致跳/闪烁时的div缩放超出容器.这可以通过使其overflow:scroll始终显示滚动条(您已经这样做的方式)来轻松解决.虽然,它的工作方式类似于Firefox中的魅力,Chrome在这里踌躇不前并且不会更新滚动条位置.这里的技巧是使用JavaScript来强制回流通过改变overflowauto一次你的缩放完成.所以你需要稍微延迟一下.

小提琴2:http://jsfiddle.net/abhitalks/u7sfef0b/

摘录2:

$("input").on("click", function() {
    var scroll = 'scroll', 
        scale = +($(this).data("scale"));
    if (scale > 1) { scroll = 'auto'; }
    setTimeout(fixScroll, 300, scroll);
});

function fixScroll(scroll) { $("#container").css({ overflow: scroll }); }
Run Code Online (Sandbox Code Playgroud)
* { box-sizing: border-box; }
#container {
    position: relative;
    border: 1px solid red; background-color: blue;
    width: 400px; height: 300px;
    overflow: scroll;
}
.wrapper {
    position: absolute; 
    background-color: transparent; border: 2px solid black;
    width: 300px; height: 200px;
    top: 50%; left: 50%;
    transform-origin: top left;
    transform: translate(-50%, -50%); 
    transition: all 1s;
}
.box {
    width: 300px; height: 200px;
    background: linear-gradient(to right, red, white);
    border: 2px solid yellow;
}
.inner { width:50px; height: 50px; background-color: green; }

#s0:checked ~ div#container .wrapper { transform: scale(0.5) translate(-50%, -50%); }
#s1:checked ~ div#container .wrapper { transform: scale(0.75) translate(-50%, -50%); }
#s2:checked ~ div#container .wrapper { transform: scale(1) translate(-50%, -50%); }
#s3:checked ~ div#container .wrapper { top: 0%; left: 0%;transform-origin: top left; transform: scale(1.5) translate(0%, 0%); }
#s4:checked ~ div#container .wrapper { top: 0%; left: 0%;transform-origin: top left; transform: scale(2) ; }
#s5:checked ~ div#container .wrapper { top: 0%; left: 0%;transform-origin: top left; transform: scale(3) ; }
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="s0" name="scale" data-scale="0.5" type="radio" />Scale 0.5
<input id="s1" name="scale" data-scale="0.75" type="radio" />Scale 0.75
<input id="s2" name="scale" data-scale="1" type="radio" checked />Scale 1
<input id="s3" name="scale" data-scale="1.5" type="radio" />Scale 1.5
<input id="s4" name="scale" data-scale="2" type="radio" />Scale 2
<input id="s5" name="scale" data-scale="3" type="radio" />Scale 3
<hr>
<div id="container">
    <div id="wrapper" class="wrapper">
        <div id="box" class="box">
            <div class="inner"></div>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

选项2:

为了解决保持div居中并同时保持正确滚动条位置的问题3 ,您必须回退Javascript.

原理保持不变,对于大于1的比例因子,您需要重置左上角和translate位置.您还需要重新调整缩放的宽度/高度,然后将其重新分配给包装器div.然后在容器上设置scrollTopand scrollLeft就像获取包装器div和容器的区别一样简单div.

这解决了您的问题1,2和3.

小提琴3:http://jsfiddle.net/abhitalks/rheo6o7p/1/

代码段3:

var $container = $("#container"), 
    $wrap = $("#wrapper"), 
    $elem = $("#box"), 
    originalWidth = 300, originalHeight = 200;

$("input").on("click", function() {
    var factor = +(this.value);
    scaler(factor);
});

function scaler(factor) {
    var newWidth = originalWidth * factor,
        newHeight = originalHeight * factor;
    $wrap.width(newWidth); $wrap.height(newHeight);
    if (factor > 1) {
        $wrap.css({ left: 0, top: 0, transform: 'translate(0,0)' }); 
        $elem.css({ transform: 'scale(' + factor + ')' }); 
        setTimeout(setScroll, 400);
    } else {
        $elem.css({ transform: 'scale(' + factor + ') ' });        
        $wrap.css({ left: '50%', top: '50%', transform: 'translate(-50%, -50%)' });
    }
}

function setScroll() {
    var horizontal, vertical;
    horizontal = ($wrap.width() - $container.width()) / 2;
    vertical = ($wrap.height() - $container.height()) / 2;
    $container.stop().animate({scrollTop: vertical, scrollLeft: horizontal}, 500);
}
Run Code Online (Sandbox Code Playgroud)
* { box-sizing: border-box; }
#container {
    position: relative;
    border: 1px solid red; background-color: blue;
    width: 400px; height: 300px;
    overflow: scroll;
}
.wrapper {
    position: absolute; 
    background-color: transparent; border: 2px solid black;
    width: 300px; height: 200px;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%); 
    transition: all 0.5s;
}
.box {
    width: 300px; height: 200px;
    background: linear-gradient(to right, red, white);
    border: 2px solid yellow;
    transform-origin: top left;
    transition: all 0.5s;
}
.inner { width:50px; height: 50px; background-color: green; }
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<label for="slider1">Scale: </label>
<input id="slider1" type="range" min="0.5" max="3" value="1" step="0.25" list="datalist" onchange="scaleValue.value=value" />
<output for="slider1" id="scaleValue">1</output>
<datalist id="datalist">
	<option>0.5</option>
	<option>0.75</option>
	<option>1</option>
    <option>1.5</option>
    <option>2</option>
    <option>3</option>
</datalist>
<hr>
<div id="container">
    <div id="wrapper" class="wrapper">
        <div id="box" class="box">
            <div class="inner"></div>
        </div>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

所有脚本都使用IE-11,GC-43和FF-38进行了测试

.