使用CSS transform scale()缩放元素而不裁剪,保持滚动 [英] Using CSS transform scale() to zoom into an element without cropping, maintaining scrolling

查看:1702
本文介绍了使用CSS transform scale()缩放元素而不裁剪,保持滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

活动示例:



点击A框将适当缩放:





(请注意, )



问题是:缩放到框D会缩放缩放容器,以便滚动到顶部和左边不工作,因为内容溢出。当缩放到框B(左半部分被裁剪)和C(上半部分被裁剪)时也会发生同样的情况。



在与缩放相关的类似情况下(请参阅 CSS3 Transform Scale and Container with Overflow ),一个可能的解决方案是指定 transform-origin:top left (或 0 0 )。由于缩放相对于左上角的工作方式,滚动功能保持不变。这似乎并不在这里工作,因为它意味着你不再重新定位的内容,专注于点击框(A,B,C或D)。



另一个可能的解决方案是向缩放容器添加 margin-left margin-top 增加了足够的空间来弥补溢出的内容。



因此:有一种方法可以放大给定的元素,

:有一个粗略的几乎解决方案通过动画 scrollTop scrollLeft ,类似于 http://stackoverflow.com/a/31406704/528044 (请参阅 jsfiddle示例),但它不是一个合适的解决方案,因为它首先缩放到左上角,而不是目标。我开始怀疑这是不可能的,因为它可能等于要求 scrollLeft 为负。

解决方案

为什么不只是将 TransformOrigin 重新定位到 0 0 要在

之后使用 scrollTop / scrollLeft





如果您不需要动画, TransformOrigin 可以始终保持 0 0 ,只有滚动用于显示框。 p>

为了使动画更少跳跃,只使用 transform porperty的转换,否则 transform-origin 也获取动画。我已经编辑了 4x4 元素的示例,但我认为将一个框完全放大到视图是有意义的,这就是为什么我改变了缩放级别。但是如果你保持缩放级别2和网格大小 15x15 例如,那么使用这种方法真正精确的原点应该计算变换,然后也是正确的滚动。



反正我不知道,如果你觉得这种方法有用。



堆栈片段



 

  * {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;宽度:25%;身高:25%颜色:白色; text-align:center; } .red {background:red; } .blue {background:blue; } .green {background:green; } .black {background:black; } .l {opacity:.3}  

 < 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>  


Live example: https://jsfiddle.net/b8vLg0ny/

It's possible to use the CSS scale and translate functions to zoom into element.

Take this example, of 4 boxes in a 2x2 grid.

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>

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; }

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;
  }
});

By controlling the value of translateX and translateY, you can change how the zooming works.

The initial rendered view looks something like this:

Clicking on the A box will zoom you in appropriately:

(Note that clicking D at the end is just showing the reset by zooming back out.)

The problem is: zooming to box D will scale the zoom container such that scrolling to the top and left doesn't work, because the contents overflow. The same happens when zooming to boxes B (the left half is cropped) and C (the top half is cropped). Only with A does the content not overflow outside the container.

In similar situations related to scaling (see CSS3 Transform Scale and Container with Overflow), one possible solution is to specify transform-origin: top left (or 0 0). Because of the way the scaling works relative to the top left, the scrolling functionality stays. That doesn't seem to work here though, because it means you're no longer repositioning the contents to be focused on the clicked box (A, B, C or D).

Another possible solution is to add a margin-left and a margin-top to the zoom container, which adds enough space to make up for the overflowed contents. But again: the translate values no longer line up.

So: is there a way to both zoom in on a given element, and overflow with a scroll so that contents aren't cropped?

Update: There's a rough almost-solution by animating scrollTop and scrollLeft, similar to http://stackoverflow.com/a/31406704/528044 (see the jsfiddle example), but it's not quite a proper solution because it first zooms to the top left, not the intended target. I'm beginning to suspect this isn't actually possible, because it's probably equivalent to asking for scrollLeft to be negative.

解决方案

Why not just to reposition the TransformOrigin to 0 0 and to use proper scrollTop/scrollLeft after the animation?

If you do not need the animation, the TransformOrigin can always stays 0 0 and only the scrolling is used to show the box.

To make the animation less jumpy use transition only for transform porperty, otherwise the transform-origin gets animated also. I have edited the example with 4x4 elements, but I think it makes sense to zoom a box completely into view, thats why I changed the zoom level. But if you stay by zoom level 2 and the grid size 15x15 for instance, then with this approach really precise origin should be calculated for transform, and then also the correct scrolling.

Anyway I don't know, if you find this approach useful.

Stack snippet

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 };
}

* { 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 }

<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>

这篇关于使用CSS transform scale()缩放元素而不裁剪,保持滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆