68

我发现了这个:变换后的宽度/高度

和其他几个,但没有什么不是我想要的。我想要的是将某些东西缩放到其大小的 50%(当然还有漂亮的动画过渡),并让页面布局重新调整到元素的新(视觉)大小。默认情况下似乎发生的情况是元素在布局结构中仍保留其原始大小,并且仅使用相关的转换进行绘制。

基本上,我希望用户单击文本块(或其他内容),然后将该文本缩放到其大小的 50%(或其他)并将其粘贴在下面的面板中以指示它已被选中。移动元素后,我不希望元素周围有 50% 的空白。

我尝试重新设置高度/宽度,但这会导致元素本身经历新的布局,然后将比例应用于新布局,这仍然给我留下了 50% 的空白空间。我的 mozilla 特定(为简单起见)代码如下所示:

<script type="text/javascript">
 function zap(e) {

  var height = e.parentNode.offsetHeight/2 + 'px';
  var width = e.parentNode.offsetWidth/2 + 'px';
  e.parentNode.style.MozTransform='scale(0.0)'; 
  e.parentNode.addEventListener(
    'transitionend', 
    function() { 
      var selectionsArea = document.getElementById("selected");
      selectionsArea.appendChild(e.parentNode);
      e.parentNode.style.MozTransform='scale(0.5,0.5)'; 
      e.parentNode.style.display = 'inline-block';
      e.parentNode.style.height = height;
      e.parentNode.style.width = width;
    },
    true) 
}
</script>

我真的希望我不必为了实现这一目标而陷入负边距或相对定位的混乱......

编辑:自从写这篇文章以来,我发现了一个非常相似的问题,既没有评论也没有答案。它略有不同,因为我不关心它是一个特定于 html5 的解决方案,我怀疑该解决方案要么不存在,要么位于 CSS/javascript 中,无论 html 级别如何。

使用 CSS3 转换 scale() 缩放/缩放 DOM 元素及其占用的空间

编辑2:(另一个非工作尝试)

我也试过这个,但是缩放和平移函数似乎以一种使最终位置无法预测的方式相互作用......并且变换之前的缩放似乎与变换然后缩放不同。不幸的是,这不仅仅是通过比例因子调整翻译的问题......

function posX(e) {
    return e.offsetLeft + (e.offsetParent ? posX(e.offsetParent) : 0)
}

function posY(e) {
    return e.offsetTop + (e.offsetParent ? posY(e.offsetParent) : 0)
}

function placeThumbNail(e, container, x, y, scale) {
    var contX = posX(container);
    var contY = posY(container);
    var eX = posX(e);
    var eY = posY(e);
    var eW = e.offsetWidth;
    var eH = e.offsetHeight;

    var margin = 10;
    var dx = ((contX - eX) + margin + (x * eW * scale));
    var dy = ((contY - eY) + margin + (y * eH * scale));

    // assumes identical objects     
    var trans = 'translate(' + dx + 'px, ' + dy + 'px) ';
    var scale = 'scale(' + scale + ',' + scale + ') ';
    e.style.MozTransform =  trans + scale ; 
}

即使它有效,上面仍然需要我在运行此代码之前先将元素移动到页面底部(以摆脱空白),此外,我还需要在重新调整大小时重新计算转换.. .所以无论如何我对这个尝试开始不太满意。

另请注意,如果您在上面使用scale + transvs trans + scale,则结果会大不相同。

编辑 3:我发现了放置问题......转换按指定的顺序应用,并且scale(0.5,0.5)基本上将像素的大小更改为原来的一半(可能暗示他们如何在内部实现它)。如果我把 translate 放在第一位,那么翻译稍微少/多一点来解释由比例引起的左上角位置的变化就可以了,但是当 dom 发生变化时管理对象的位置并调整变换合理的方式仍然让我望而却步。这种感觉是错误的,因为我正朝着用 javascript 编写自己的布局管理器的方向漂移,只是为了获得这种效果。

4

3 回答 3

48

我注意到的问题是,当元素缩放时,浏览器会改变它的像素比率,而不是像素数量。元素更小,但它不会改变它在 DOM 中的实际像素大小。因此,我认为不存在仅 CSS 的解决方案。

我将可缩放元素放入容器中,该容器与其他元素保持相同的像素比。使用 Java 脚本,我只需更改容器的大小。一切仍然基于 CSS3 变换:缩放。也许 JS 代码可以更简单,但现在都是关于这个想法(只是一个概念证明);)摆弄两个例子:http: //jsfiddle.net/qA5Tb/9/

HTML:

<div class="overall-scalable">
    <div class="scalable" scalex='0.5' scaley='0.5'>
        Nunc et nisi ante. Integer in blandit nisi. Nulla facilisi. Vestibulum vulputate sapien eget mauris elementum sollicitudin. Nullam id lobortis dolor. Nulla vitae nibh vitae sem volutpat pretium. Nunc et nisi ante. Integer in blandit nisi. Nulla facilisi. Vestibulum vulputate sapien eget mauris elementum sollicitudin. Nullam id lobortis dolor. Nulla vitae nibh vitae sem volutpat pretium.
    </div>
</div>

CSS:

.overall-scalable {width: 350px; height: 150px; overflow: hidden; -webkit-transition: all 1s;}
.scalable {color: #666; width: 350px; height: 150px; -webkit-transform-origin: top left; -webkit-transition: all 1s;}

JS:

$('button').click(function() {
    $('.scalable').each(function(){
        rescale($(this));
    })
});

function rescale(elem) {

    var height = parseInt(elem.css('height'));
    var width = parseInt(elem.css('width'));
    var scalex = parseFloat(elem.attr('scalex'));
    var scaley = parseFloat(elem.attr('scaley'));

    if (!elem.hasClass('rescaled')){
        var ratioX = scalex;
        var ratioY = scaley;
    }else{          
        var ratioX = 1;
        var ratioY = 1;
    }

    elem.toggleClass('rescaled');
    elem.css('-webkit-transform', 'scale('+ratioX +', '+ratioY+')');        
    elem.parent().css('width', parseInt(width*ratioX) + 'px');
    elem.parent().css('height', parseInt(height*ratioY) + 'px');
}​
于 2012-06-06T11:27:51.313 回答
10

我终于想出了一个简单的解决方案,它与我开始的地方非常相似。

我承认,(在过去一年左右的时间里)花了很多努力才最终弄明白。我实际上是在寻找这个问题的答案。我以前遇到过这个问题。无论如何,我再次开始解决这个问题,我确实找到了一个简单的解决方案。

无论如何,诀窍是将边距底部与 CSS calc 脚本一起使用。

此外,您必须为对象 (div) 声明绝对高度。如果 div 可以扩展,我认为这不会起作用,否则,经过多次尝试和数小时后,我终于有了一个非常简单、干净、有效的解决方案。

因此,例如,高度 = 300 像素(不是 30%,或者没有高度)。如果可以的话,我什至会设置 overflow-y = hidden。如果您希望 div 增长(没有绝对高度),我相信您将需要 JavaScript。我没有尝试。否则,这在所有测试中都可以正常工作。

我相信这将适用于 SASS 或 LESS,因为您可以使用 CSS 中的变量声明一些重复的内容。我还没有尝试过。

关于我的解决方案的一些重要评论:

  1. 请注意,我使用对象的高度和 CSS calc 方法以及变换大小来计算底部边距。
  2. 我对我的工作进行了颜色编码,以帮助显示正在发生的事情。
  3. wrap div 确实有填充,只是为了表明它正在工作。它们是绝对的,不会影响内部对象。
  4. 如果您像我一样构建响应式页面,则可以使用媒体查询与类来获得相同的效果。
  5. 我正在使用 transform-origin: 50% 0; 这段代码最终没有我最初想象的那么重要。我正在使用底部边距来解决我遇到的问题。
  6. 在此示例中,我只是将 div 置于父 div 的中心。如果您需要放置 div,它会稍微复杂一些,但类似的解决方案也可以。我没有尝试。
  7. 您可以在 jQuery 与 CSS 中使用相同的解决方案。这个想法是一样的。您将在页面中搜索所有具有转换的元素并根据需要添加 CSS。

我还设置了一个 Codepen 来测试和分享。

https://codepen.io/cyansmiles/details/yvGaVP

.box-wrap {
  display: block;
  position: relative;
  box-sizing: border-box;
  width: 100%;
  margin: auto;
  text-align: center;
  margin: 30px 10px;
  padding: 40px;
  background: yellow;
}

.box-wrap:before {
  content: "";
  display: block;
  box-sizing: border-box;
  position: absolute;
  background: rgba(0, 0, 0, 0.5);
  width: calc(100% - 80px);
  height: calc(100% - 80px);
  top: 40px;
  left: 40px;
}

.box {
  display: inline-block;
  box-sizing: border-box;
  position: relative;
  transform-origin: 50% 0;
  width: 300px;
  height: 150px;
  background: red;
}

.box.size-80 {
  transform: scale(0.8);
  margin: 0 auto calc(-150px * (1 - 0.8));
}

.box.size-70 {
  transform: scale(0.7);
  margin: 0 auto calc(-150px * (1 - 0.7));
}

.box.size-60 {
  transform: scale(0.6);
  margin: 0 auto calc(-150px * (1 - 0.6));
}

.box.size-50 {
  transform: scale(0.5);
  margin: 0 auto calc(-150px * (1 - 0.5));
}

//etc
<div class="box-wrap">
  <div class="box">
    <h1>Box at 100%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-80">
    <h1>Box at 80%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-70">
    <h1>Box at 70%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
</div>

于 2018-02-27T23:06:17.390 回答
4

我不得不从上面稍微调整我的代码。

它现在适用于所有方面(不仅仅是上下)。我看到了一些编辑,我认为这是 CSS 问题(您可以在代码中添加另一个像素来解决这个问题)。

这是有效的 Codepen 链接。如果您使用它,请随时告诉我。终于弄清楚这一点感觉很好。

https://codepen.io/cyansmiles/pen/bLOqZo

附言。我正在分叉我的代码笔以添加可移动的 CSS。

.box-wrap {
  display: block;
  position: relative;
  box-sizing: border-box;
  width: 100%;
  margin: auto;
  text-align: center;
  margin: 30px 10px;
  padding: 40px;
  background: yellow;
}

.box-wrap:before {
  content: "";
  display: block;
  box-sizing: border-box;
  position: absolute;
  background: rgba(0, 0, 0, 0.5);
  width: calc(100% - 80px);
  height: calc(100% - 80px);
  top: 40px;
  left: 40px;
}

.box {
  display: inline-block;
  box-sizing: border-box;
  position: relative;
  transform-origin: 50% 0;
  width: 300px;
  height: 150px;
  background: red;
  color: #fff;
}

.box.size-80 {
  background: red;
  transform: scale(0.8);
  margin: 0 calc((-300px * (1 - 0.8)) / 2) calc(-150px * (1 - 0.8));
}

.box.size-70 {
  background: blue;
  transform: scale(0.7);
  margin: 0 calc((-300px * (1 - 0.7)) / 2) calc(-150px * (1 - 0.7));
}

.box.size-60 {
  background: green;
  transform: scale(0.6);
  margin: 0 calc((-300px * (1 - 0.6)) / 2) calc(-150px * (1 - 0.6));
}

.box.size-50 {
  background: orange;
  transform: scale(0.5);
  margin: 0 calc((-300px * (1 - 0.5)) / 2) calc(-150px * (1 - 0.5));
}

//etc
<div class="box-wrap">
  <h1>This is a bunch of boxes!</h1>
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
  <div class="box size-80">
    <h1>Box at 80%</h1>
  </div>
  <div class="box size-70">
    <h1>Box at 70%</h1>
  </div>
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
  <div class="box size-80">
    <h1>Box at 80%</h1>
  </div>
  <div class="box size-70">
    <h1>Box at 70%</h1>
  </div>
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box">
    <h1>Box at 100%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-80">
    <h1>Box at 80%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-70">
    <h1>Box at 70%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-60">
    <h1>Box at 60%</h1>
  </div>
</div>

<div class="box-wrap">
  <div class="box size-50">
    <h1>Box at 50%</h1>
  </div>
</div>

于 2018-02-28T02:33:12.550 回答