带有元素大小调整的 CSS 变换
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10858523/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CSS Transform with element resizing
提问by Gus
I found this: width/height after transform
我发现了这个:转换后的宽度/高度
and several others, but nothing is not quite what I'm looking for. What I want is to scale something to 50% of it's size (with nice animated transition of course) and have the page layout re-adjust to the new (visual) size of the element. What seems to happen by default is that the element still retains it's original size in the layout structure, and is merely drawn with the associated transformations.
和其他几个,但没有什么不是我正在寻找的。我想要的是将某些内容缩放到其大小的 50%(当然还有漂亮的动画过渡),并使页面布局重新调整为元素的新(视觉)大小。默认情况下似乎发生的是,元素在布局结构中仍然保留其原始大小,并且仅使用关联的转换进行绘制。
Basically I want the user to click on a block of text (or other content), and then scale that text to 50% (or whatever) of it's size and stick it in a panel below to indicate that it's been selected. I don't want 50% whitespace around the element after I move it.
基本上,我希望用户单击文本块(或其他内容),然后将该文本缩放到其大小的 50%(或其他大小)并将其粘贴在下面的面板中以表明它已被选中。移动元素后,我不希望元素周围有 50% 的空白。
I've tried re-setting the height/width, but that causes the element iself to undergo a new layout and then the scale is applied to the new layout and this still leaves me with 50% white space after all is finished. My mozilla specific (for simplicity) code looks like this:
我试过重新设置高度/宽度,但这会导致元素本身经历一个新的布局,然后将比例应用于新的布局,这在完成后仍然给我留下了 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>
I'm really hoping I don't have to go into messing with negative margins or relative positioning to achieve this...
我真的希望我不必为了实现这一目标而纠结于负边距或相对定位......
Edit:Since writing this I found a very similar question with neither comments or answers. It differs slightly as I don't care about it being an html5 specific solution, I suspect the solution either doesn't exist or lies in CSS/javascript regardless of the html level.
编辑:自从写这篇文章以来,我发现了一个非常相似的问题,既没有评论也没有答案。它略有不同,因为我不关心它是 html5 特定的解决方案,我怀疑该解决方案要么不存在,要么位于 CSS/javascript 中,而不管 html 级别如何。
Scale/zoom a DOM element and the space it occupies using CSS3 transform scale()
使用 CSS3 变换 scale() 缩放/缩放 DOM 元素及其占用的空间
Edit 2:(another non-working attempt)
编辑2:(另一个非工作尝试)
I've also tried this, but the scale and the translate functions seem to interact in a manner that makes the final position impossible to predict... and scale before transform doesn't appear to be the same as transform then scale. Unfortunately it's not just a matter of adjusting the translate by the scale factor ...
我也试过这个,但是缩放和平移函数似乎以一种使最终位置无法预测的方式相互作用......并且变换前的缩放似乎与变换然后缩放不同。不幸的是,这不仅仅是通过比例因子调整翻译的问题......
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 ;
}
Even if it worked, the above would still require me to first move the element to the bottom of the page before running this code (to get rid of the whitespace), and furthermore I would need to recalculate the transform on re-size... so I wasn't too happy with this attempt to start with anyway.
即使它有效,上面仍然需要我在运行此代码之前首先将元素移动到页面底部(以去除空格),而且我需要重新计算重新调整大小的变换.. . 所以无论如何我对这个尝试都不太满意。
Also note that if you use scale + trans
vs trans + scale
above the result is drastically different.
另请注意,如果您在上面使用scale + trans
vs trans + scale
,结果会大不相同。
Edit 3:I figured out the placement issues... the transforms are applied in the order specified, and scale(0.5,0.5)
essentially changes the size of a pixel to half what it was originally (probably hinting at how they implemented it internally). If I put translate is first, translating slightly less/more to account for the change in the position of the upper left corner caused by scale will do the trick, but managing the location of the objects and adjusting the transforms when the dom changes in a reasonable manner is still eluding me. This sort of feels wrong because I am drifting in the direction of writing my own layout manager in javascript just to get this effect.
编辑 3:我发现了放置问题......变换按指定的顺序应用,并且scale(0.5,0.5)
基本上将像素的大小更改为原来的一半(可能暗示他们如何在内部实现它)。如果我把翻译放在第一位,翻译稍微少一点/多一点来解释由缩放引起的左上角位置的变化就可以了,但是当dom变化时管理对象的位置并调整变换合理的方式仍然让我望而却步。这种感觉是错误的,因为我正朝着在 javascript 中编写自己的布局管理器的方向漂移,只是为了获得这种效果。
采纳答案by Sófka
The problem I noticed is that when element scales, browser change its pixels ratio, not pixels amount. Element is smaller but it doesn't change its actual pixel size in DOM. Because of that I don't think that CSS-only solution exist.
我注意到的问题是,当元素缩放时,浏览器会改变其像素比例,而不是像素数量。元素较小,但不会改变其在 DOM 中的实际像素大小。因此,我认为不存在仅使用 CSS 的解决方案。
I put scalable element into container which keeps the same pixel ratio as rest of elements. Using Java Script I simply change container's size. Everything is still based on CSS3 transform: scale. Maybe JS code could be simplier, but now it's all about the idea (just a proof of concept);) Fiddle with two examples: http://jsfiddle.net/qA5Tb/9/
我将可缩放元素放入容器中,该容器与其余元素保持相同的像素比。使用 Java Script 我只需更改容器的大小。一切仍然基于 CSS3 变换:缩放。也许 JS 代码可以更简单,但现在都是关于这个想法的(只是一个概念证明);)摆弄两个例子:http: //jsfiddle.net/qA5Tb/9/
HTML:
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:
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:
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');
}?
回答by Nathan Sharfi
I finally figured out a simple solution and it is much similar than where I started from.
我终于想出了一个简单的解决方案,它与我开始的地方非常相似。
I will admit, it took many attempts to figure this out (over the last year or so) to finally figure it out. I was actually looking for an answer to this question. I have had problems with this before. Anyways, I started working this out again and I did find a simple solution.
我承认,(在过去一年左右的时间里)花了很多次尝试才最终弄明白。我实际上是在寻找这个问题的答案。我以前遇到过这个问题。无论如何,我再次开始解决这个问题,我确实找到了一个简单的解决方案。
Anyways, the trick was to use the margin bottom together with the CSS calc script.
无论如何,诀窍是将边距底部与 CSS calc 脚本一起使用。
Also, you must have to have absolute height declared for the the object (div). I dont think this will work with if the div can expand, otherwise, after many attempts and hours on this I finally have a very simple, clean, working solution.
此外,您必须为对象 (div) 声明绝对高度。如果 div 可以扩展,我认为这不会起作用,否则,经过多次尝试和数小时后,我终于有了一个非常简单、干净、有效的解决方案。
So, for example, height = 300px (not 30%, or no height). I would even set overflow-y = hidden if you can. If you want the div to grow (not have an absolute height), I believe you will need JavaScript. I did not try it. Otherwise this is working correctly in all tests.
因此,例如,高度 = 300 像素(不是 30%,或没有高度)。如果可以的话,我什至会设置 overflow-y = hidden。如果您希望 div 增长(没有绝对高度),我相信您将需要 JavaScript。我没有尝试。否则这在所有测试中都能正常工作。
I am sure this will work nice with SASS or LESS since you could declare some of the repeated things using variables in the CSS. I have not tried that yet.
我相信这将适用于 SASS 或 LESS,因为您可以使用 CSS 中的变量声明一些重复的内容。我还没有尝试过。
Some important comments on my solution:
关于我的解决方案的一些重要评论:
- Notice I am using the height of the object and a CSS calc method together with the transform size to figure out the bottom margin.
- I color coded my work to help show what is happening.
- the wrap div does have padding are there only to show it is working. They are absolute and it does not affect the internal object.
- If you were building a responsive page, like I am, you can use media queries vs classes to get the same affect.
- I am using transform-origin: 50% 0; This code ended up not being as important as I originally thought it would be. I am using the bottom margin to resolve the problems I had had.
- In this example, I am just centering the div in the parent div. If you need to place the div, it is a little more complicated, but a similar solution will work. I did not attempt it.
- You could use this same solution with jQuery vs CSS. The idea is the same. You would search for all elements with the transform in the page and add the CSS as needed.
- 请注意,我使用对象的高度和 CSS calc 方法以及变换大小来计算底部边距。
- 我对我的工作进行了颜色编码,以帮助显示正在发生的事情。
- wrap div 确实有填充,只是为了表明它正在工作。它们是绝对的,不会影响内部对象。
- 如果您正在构建响应式页面,就像我一样,您可以使用媒体查询与类来获得相同的效果。
- 我正在使用变换原点:50% 0; 这段代码最终没有我原先想象的那么重要。我正在使用底部边距来解决我遇到的问题。
- 在这个例子中,我只是将 div 放在父 div 中。如果需要放置 div,则稍微复杂一些,但类似的解决方案会起作用。我没有尝试。
- 您可以在 jQuery 与 CSS 中使用相同的解决方案。这个想法是一样的。您将搜索页面中具有转换的所有元素并根据需要添加 CSS。
I have also have set up a Codepen to test this with and for sharing.
我还设置了一个 Codepen 来测试和共享。
https://codepen.io/cyansmiles/details/yvGaVP
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>
回答by Nathan Sharfi
I had to tweak my code a little from above.
我不得不从上面稍微调整我的代码。
It now works on all sides (not just up and down). I see a little edit, I think that is CSS issue (you could add another pixel to code to resolve this).
它现在适用于所有方面(不仅仅是上下)。我看到了一些编辑,我认为这是 CSS 问题(您可以在代码中添加另一个像素来解决此问题)。
Here is the working Codepen link. Feel free to let me know if you use it. It felt good to finally figure this out.
这是有效的 Codepen 链接。如果您使用它,请随时告诉我。终于弄清楚了这一点感觉很好。
https://codepen.io/cyansmiles/pen/bLOqZo
https://codepen.io/cyansmiles/pen/bLOqZo
ps. I am forking my codepen to add a moveable CSS.
附:我正在分叉我的代码笔来添加一个可移动的 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>