CSS Transform: Scale Does Not Change Dom Size

CSS transform: scale does not change DOM size?

Transforms don't affect the layout — or more precisely the box model — of an element. They are purely cosmetic. From the spec:

Note: Transformations do affect the visual layout on the canvas, but have no affect on the CSS layout itself. This also means transforms do not affect results of the Element Interface Extensions getClientRects() and getBoundingClientRect(), which are specified in [CSSOM-VIEW].

Scale down big image doesn't update body size

Quick answer: the body (container) won't use the transformed size of the image. To prevent this container element size reflecting the original image size, either you define dimensions or restrict size without transforms, or you remove the element from the document flow with absolute positioning.

Transforms are a visual 'effect' applied to an element, and don't affect the underlying document layout. Basically the browser draws elements as they are before transforms, then applies the transform effect. This allows transformed elements to overlay other elements, push outside the window etc. without affecting other element layout.

More detail in this SO question.

Transform scale keeps the original space around the scaled element

A brutal way would be to virtually reduce space needed by element.

Your example shows a known width & height, so it makes it easy. else you would need a javascript method.

.box_1 {
width: 300px;
height: 300px;
transform: scale(0.5);
transform-origin: left top;
margin-bottom:-150px;
margin-right:-150px;
}

https://jsfiddle.net/0bc4sxk3/1/

Scaling up would mean positive margins.

Transform only happens at screen, elements still use initial room and place needed in the flow of the document.

How to manually set overflow size on parent container when using CSS transform on child?

Well you could use a pseudo element inside the container...

.parent:before {
content: '';
position: relative;
z-index: -1;
width: calc(4900px * 0.25);
height: calc(7000px * 0.25);
}

That should force the overflow. I'm using a negative z-index to make sure it doesn't interact with the content.

Note: if the scaling is dynamic it's likely easier to actually create an empty element (pseudo-classes are difficult to control via JS) and then dynamically control the height/width using Javascript.

<div class="parent">
<div class="spacer"></div>
<div class="child">
</div>
</div>

And CSS

.spacer {
content: '';
position: relative;
z-index: -1;
width: calc(4900px * 0.25);
height: calc(7000px * 0.25);
}

Edit: Oops just realized you need to go smaller than the original. The above would work if the new overflow is larger than the starting state...

In this specific case, you might want to avoid the transform all together and instead scale the background image. Then scale the element using your JS function. In this case, the background will scale to fit its container.

.child {
background-image: url("https://i.redd.it/7ifkx5z39b631.jpg");
background-size: contain;
width: calc(4900px * 0.25);
height: calc(7000px * 0.25)
}

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

The HTML (Thanks Rory)

<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Sandbox for Stack Overflow question http://stackoverflow.com/q/10627306/578288" />
<meta charset=utf-8 />
<title>Sandbox for SO question about scaling an element both visually and dimensionally</title>
</head>
<body>

<div id="wrapper">
<div class="surrounding-content">
before
</div>

<div id="content-to-scale">
<div>something inside</div>
<div><img src="http://placekitten.com/g/150/100"></div>
<div>another something</div>
</div>

<div class="surrounding-content">
after
</div>
</div>

</body>
</html>

The CSS (Still started from Rory's base)

body {
font-size: 13px;
background-color: #fff;
}
#wrapper {
width: 50%;
margin-left: auto;
margin-right: auto;
border: 0.07692307692307693em solid #888;
padding: 1.1538461538461537em;
}
.surrounding-content {
border: 0.07692307692307693em solid #eee;
}
#content-to-scale {
border: 0.07692307692307693em solid #bbb;
width: 10em;
}
#content-to-scale {
font-size: 1.1em;
}
#content-to-scale img {
width: auto;
height: auto;
min-width: 100%;
max-width: 100%;
}

The Explanation:

I'm using font size and ems to "scale" the dimensions of the child elements.

Ems are dimension units that are relative to the current context's font-size.

So if I say I have a font-size of 13px and a border of 1 (the desired border-width in pixels) divded
by 13 (the current context's font-size also in pixels) = 0.07692307692307693em the browser ought to render a 1px border

To emulate a 15px padding I use the same formula, (desired pixels)/(current context's font-size in pixels) = desired ems.
15 / 13 = 1.1538461538461537em

To tame the scaling of the image I use an old favorite of mine: the natural ratio preserving scale, let me explain:

Images have a natural height and width and a ratio between them. Most browser's will preserve this ratio if both width and height are set to auto.
You can then control the desired width with min-width and max-width, in this case making it always scale to the full width of the parent element, even when it will scale beyond it's natural width.

(You can also use max-width and max-height 100% to prevent the image from busting out of the borders of the parent element, but never scaling beyond their natural dimensions)

You can now control the scaling by tweaking the font-size on #content-to-scale. 1.1em roughly equals scale(1.1)

This does have some drawbacks: nested font-sizing in ems are applied recusively. Meaning if you have:

<style type="text/css">
div{
font-size: 16px;
}
span{
font-size: 0.5em;
}
</style>
<div>
<span>
<span>
Text
</span>
</span>
</div>

You will end up with "Text" rendering at 4px instead of the 8px you might expect.

How does css scale transform affect document flow?

CSS Transform does not affect document flow. The DOM element will occupy it's original position and dimensions within the page flow.

So if you have 3 square div's of identical size, displayed inline in a row and apply a -webkit-transform: scale(2) to the center square, this square will scale up to 200% larger, scale from the center of its original position, and overlap both other squares.

Reference example:

http://jsfiddle.net/ypnEk/

HTML:

<div class="square one"></div>
<div class="square two"></div>
<div class="square three"></div>

CSS:

.square{
margin-top:50px;
width:50px;
height:50px;
display:inline-block;
}

.one{
background:#222;
}

.two{
background:#888;
-webkit-transform: scale(2);
}

.three{
background:#ccc;
}

CSS Transform with element resizing

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.

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/

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

CSS: Why transform: scale is not working with justify-content: space-around?

Scaled (using transform: scale) element acts something like absolute, it doesn't affect other DOM element with it's size changes. Use width and height instead.

.carousel {

display: flex;

min-height: 100vh;

justify-content: space-around;

align-items: center;

}

.carousel__box {

--w: 100px;

--h: 100px;

width: var(--w);

height: var(--h);

background: skyblue;

}

.carousel__box:nth-child(1),

.carousel__box:nth-child(5) {

opacity: 0.6;

width: calc(var(--w) / 1.2);

height: calc(var(--h) / 1.2);

}

.carousel__box:nth-child(2),

.carousel__box:nth-child(4) {

opacity: 0.8;

}

.carousel__box:nth-child(3) {

width: calc(var(--w) * 1.2);

height: calc(var(--h) * 1.2);

}
<div class="carousel">

<div class="carousel__box"></div>

<div class="carousel__box"></div>

<div class="carousel__box"></div>

<div class="carousel__box"></div>

<div class="carousel__box"></div>

</div>


Related Topics



Leave a reply



Submit