CSS转换元素大小调整

时间:2012-06-01 23:25:25

标签: css css3 css-transforms

我发现了这个:width/height after transform

和其他几个人,但没有什么不是我正在寻找的。我想要的是将某些东西缩放到它的大小的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级别如何。

Scale/zoom a DOM element and the space it occupies using CSS3 transform scale()

编辑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 + trans vs trans + scale,则结果会大不相同。

编辑3 我找出了展示位置问题...变换按照指定的顺序应用,scale(0.5,0.5)实际上将像素的大小更改为原来的一半(可能暗示他们是如何在内部实施的)。如果我把翻译放在第一位,翻译稍微少于/更多来考虑由比例引起的左上角位置的变化就可以解决问题,但是当dom改变时,管理对象的位置并调整变换。合理的态度仍在逃避我。这种感觉是错误的,因为我正朝着在javascript中编写我自己的布局管理器的方向漂移,只是为了达到这个效果。

3 个答案:

答案 0 :(得分:40)

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

我将可扩展元素放入容器中,与其余元素保持相同的像素比率。使用Java Script我只需更改容器的大小。一切仍然基于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');
}​

答案 1 :(得分:1)

我终于找到了一个简单的解决方案,它与我的起点非常相似。

我承认,经过多次尝试才能弄明白(过去一年左右)才能最终解决这个问题。我其实是在寻找这个问题的答案。我之前遇到过这个问题。无论如何,我再次开始这样做,我确实找到了一个简单的解决方案。

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

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

因此,例如,height = 300px(不是30%,或没有高度)。如果可以的话,我甚至会设置overflow-y = hidden。如果你想让div增长(没有绝对高度),我相信你需要JavaScript。我没试过。否则,这在所有测试中都能正常工作。

我确信这对SASS或LESS很有用,因为你可以使用CSS中的变量声明一些重复的东西。我还没试过。

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

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

答案 2 :(得分:0)

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

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

这是工作的Codepen链接。如果您使用它,请随时告诉我。终于明白了这一点感觉很好。

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

PS。我要求我的codepen添加一个可移动的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>