I have a div that contains several other divs and elements.
Now I want to use transform: scale(n)
but when I do use it, everything looks fine, except that the margins of inner divs are kept the same size But the inner elements width are changed
As you can see the size of the div is cut by half... but the margin is the same :/
For example code, you have a div inside a parent. This child div has margin top of 100px
if I change the scale of the parent, the margin of the child stays the same but the size not. You can see that by the point the child is not moving while changing scales.
.holder {
background: pink;
transform: scale(0.5);
}
#son {
margin-top: 100px;
padding: 20px;
background: green;
}
<div class="holder">
<div id="son">
dontcare
</div>
</div>
Transforms are relative to the reference box which is set by the transform-box
property which defaults to border-box
. The border box is bounded by the border. As a result the scale transformation will scale everything within and including the border (border, padding, content box).
I'm going to start my answer off with the following example:
button {
padding: 10px;
margin: 10px;
}
.scaled {
transform: scale(2);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<button class="default">Button</button>
<button class="scaled">Button</button>
</body>
</html>
There are two buttons. Both are given 10px padding and 10px margin (as well as default browser styles). The second is scaled by a factor of 2.
In Firefox 58 the first button renders with the following properties:
We'll focus on the properties and values of the horizontal axis:
34.7167 // Content box width
10 // Padding left
10 // Padding right
7 // Border left
7 + // Border right
------------
68.7167
------------
10 // Margin left
10 // Margin right
If you total everything but the margin you'll get the element width. The margin is excluded. This is due to the browser defining the element box as everything inside and including the border. This behaviour is specified by the box-sizing
rule set to border-box
.
So how does this play into the scale
transform function not scaling the margin?
Transformations occur relative to a reference box. The reference box is defined by the transform-box
property which by default has the value border-box
. As a result the border, padding and content box dimensions will be scaled by 2 while the margin is not.
This behaviour can be observed in the second button, which is scaled:
Again, looking at the properties and values of the horizontal axis:
34.7167 * 2 = 69.4334 // Content box width
10 * 2 = 20 // Padding left
10 * 2 = 20 // Padding right
7 * 2 = 14 // Border left
7 * 2 = 14 + // Border right
-----------------------------
68.7167 * 2 = 137.4334
-----------------------------
10 // Margin left
10 // Margin right
transform-box
propertybox-sizing
transform-box
Your first screenshot seems to show an issue with transform-orginin
which by default is 50% 50% 0
(the center of the element). Change it to top left
and your element will be scaled for the top-left and thus the margin will decrease.
Concerning the code you shared, this is not related to scale but your are facing a margin-collapsing issue. The margin of the son is collapsed with the margin of its parent and the same thing happen until this one is collapsed with the body
margin. In other words the margin no more belong to the scaled element.
Here is your intial code with the margin-collpasing:
body {
background:linear-gradient(to bottom,#000 50%,transparent 0) 0 0/100% 100px;
}
.holder {
animation:anim 3s infinite linear;
transform-origin:top;
}
#son {
margin-top: 100px;
padding: 20px;
background: green;
}
@keyframes anim {
from {
transform:scale(1);
}
to {
transform:scale(0.3);
}
}
<div class="holder">
<div id="son">
dontcare
</div>
</div>
And the same code if we remove the margin-collapsing by adding a small padding:
body {
background:linear-gradient(to bottom,#000 50%,transparent 0) 0 0/100% 100px;
}
.holder {
padding-top:1px;
animation:anim 3s infinite linear;
transform-origin:top;
}
#son {
margin-top: 100px;
padding: 20px;
background: green;
}
@keyframes anim {
from {
transform:scale(1);
}
to {
transform:scale(0.3);
}
}
<div class="holder">
<div id="son">
dontcare
</div>
</div>
You can clearly see a difference between both of them. In the second example the margin is considered with the scale unlike the first one.
Here is some usefull links for more details:
CSS margin terror; Margin adds space outside parent element
https://stackoverflow.com/a/9519933/8620333
What is the point of CSS collapsing margins?
https://css-tricks.com/what-you-should-know-about-collapsing-margins/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With