使用CSS transform scale()放大元素而不进行裁剪,保持滚动

Ada*_*ott 15 html javascript css scaletransform css-transforms

实例:https://jsfiddle.net/b8vLg0ny/

可以使用CSS scaletranslate函数来放大元素.

以这个例子为例,在2x2网格中有4个方框.

HTML:

<div id="container">
  <div id="zoom-container">
    <div class="box red">A</div>
    <div class="box blue">B</div>
    <div class="box green">C</div>
    <div class="box black">D</div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

CSS:

* { margin: 0; }

body, html { height: 100%; }

#container {
  height: 100%;
  width: 50%;
  margin: 0 auto;
}

#zoom-container {
  height: 100%;
  width: 100%;
  transition: all 0.2s ease-in-out;
}

.box {
  float: left;
  width: 50%;
  height: 50%;
  color: white;
  text-align: center;
  display: block;
}

.red { background: red; }
.blue { background: blue; }
.green { background: green; }
.black { background: black; }
Run Code Online (Sandbox Code Playgroud)

JavaScript的:

window.zoomedIn = false;

$(".box").click(function(event) {
  var el = this;
  var zoomContainer = $("#zoom-container");

  if (window.zoomedIn) {
    console.log("resetting zoom");
    zoomContainer.css("transform", "");
    $("#container").css("overflow", "auto");
    window.zoomedIn = false;
  } else {
    console.log("applying zoom");
    var top = el.offsetTop;
    var left = el.offsetLeft - 0.25*zoomContainer[0].clientWidth;

    var translateY = 0.5*zoomContainer[0].clientHeight - top;
    var translateX = 0.5*zoomContainer[0].clientWidth - left;

    $("#container").css("overflow", "scroll");
    zoomContainer.css("transform", "translate(" + 2 * translateX + "px, " + 2 * translateY + "px) scale(2)");
    window.zoomedIn = true;
  }
});
Run Code Online (Sandbox Code Playgroud)

通过控制的价值translateXtranslateY,你可以改变变焦的工作方式.

初始渲染视图看起来像这样:

初始渲染视图

单击A框将适当放大您的位置:

缩放到A然后缩小

(注意,在末尾单击D只是通过缩小显示重置.)

问题是:缩放到框D将缩放缩放容器,使得滚动到顶部和左边不起作用,因为内容溢出.当缩放到方框B(左半部分被裁剪)和C(上半部分被裁剪)时也会发生同样的情况.仅使用A,内容不会溢出容器外部.

在与缩放相关的类似情况下(请参阅CSS3变换比例和带溢出的容器),一种可能的解决方案是指定transform-origin: top left(或0 0).由于缩放相对于左上角的工作方式,滚动功能保持不变.但这似乎不适用于此,因为这意味着您不再重新定位要关注点击框(A,B,C或D)的内容.

另一种可能的解决方案是在缩放容器中添加a margin-left和a margin-top,这会增加足够的空间来弥补溢出的内容.但同样:翻译价值不再排队.

那么:有没有办法既可以放大给定的元素,可以通过滚动来溢出,这样内容就不会被裁剪?

更新:有通过动画是一个粗略的几乎解决方案scrollTopscrollLeft,类似于/sf/answers/2198469311/(见的例子的jsfiddle),而是因为它首先缩放到左上角是不是很妥善的解决办法,不是预期的目标.我开始怀疑这实际上是不可能的,因为它可能等于要求scrollLeft消极.

ten*_*its 5

为什么不只是在动画之后重新定位TransformOriginto 0 0并使用正确的动画呢?scrollTop/scrollLeft

如果您不需要动画,则TransformOrigin可以始终保留该动画,0 0仅使用滚动来显示该框。

为了减少动画的跳动,请仅将过渡用于transform属性,否则也将对transform-origin动画进行动画处理。我已经使用4x4元素编辑了示例,但是我认为将框完全缩放到视图中很有意义,这就是为什么我更改了缩放级别。但是,如果以缩放级别2和网格大小15x15为例,那么使用这种方法时,应该计算出真正精确的原点进行变换,然后进行正确的滚动。

无论如何,我不知道您是否认为此方法有用。

堆栈片段

var zoomedIn = false;
var zoomContainer = $("#zoom-container");

$(".box").click(function(event) {
  var el = this;
  
  if (zoomedIn) {    
    zoomContainer.css({
    	transform: "scale(1)",
      transformOrigin: "0 0"
    });
    zoomContainer.parent().scrollTop(0).scrollLeft(0);
    zoomedIn = false;
    return;
  } 
  zoomedIn = true;
  var $el = $(el);
  animate($el);
  zoomContainer.on('transitionend', function(){
  	zoomContainer.off('transitionend');
  	reposition($el);
  })
});

var COLS = 4, ROWS = 4, 
  	COLS_STEP = 100 / (COLS - 1), ROWS_STEP = 100 / (ROWS - 1),
    ZOOM = 4;
  

function animate($box) {
  var cell = getCell($box);
  var col =  cell.col * COLS_STEP + '%',
      row =  cell.row * ROWS_STEP + '%';
  zoomContainer.parent().css('overflow', 'hidden');
	zoomContainer.css({
    transition: 'transform 0.2s ease-in-out',
  	transform: "scale(" + ZOOM + ")",
    transformOrigin: col + " " + row
  });
}
function reposition($box) {
  zoomContainer.css({
    transition: 'none',
  	transform: "scale(" + ZOOM + ")",
    transformOrigin: '0 0'
  });  
  zoomContainer.parent().css('overflow', 'auto');
  $box.get(0).scrollIntoView();
}
function getCell ($box) {
	var idx = $box.index();
  var col = idx % COLS,
      row =  (idx / ROWS) | 0;
  return { col: col, row: row };
}
Run Code Online (Sandbox Code Playgroud)
* { margin: 0; }

body, html { height: 100%; }

#container {
  height: 100%;
  width: 50%;
  margin: 0 auto;
  overflow: hidden;
}

#zoom-container {
  height: 100%;
  width: 100%;
  will-change: transform;
}

.box {
  float: left;
  width: 25%;
  height: 25%;
  color: white;
  text-align: center;  
}

.red { background: red; }
.blue { background: blue; }
.green { background: green; }
.black { background: black; }
.l { opacity: .3 }
Run Code Online (Sandbox Code Playgroud)
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>

<div id="container">
  <div id="zoom-container">
    <div class="box red">A</div>
    <div class="box blue">B</div>
    <div class="box green">C</div>
    <div class="box black">D</div>

    <div class="box red l">E</div>
    <div class="box blue l">F</div>
    <div class="box green l">G</div>
    <div class="box black l">H</div>

    <div class="box red">I</div>
    <div class="box blue">J</div>
    <div class="box green">K</div>
    <div class="box black">L</div>

    <div class="box red l">M</div>
    <div class="box blue l">N</div>
    <div class="box green l">O</div>
    <div class="box black l">P</div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)