42

In the middle of my page I have a div element with some content in it (other divs, images, whatever).

<div>
    before
</div>
<div id="content-to-scale">
    <div>something inside</div>
    <div>another something</div>
</div>
<div>
    after
</div>

I would like to scale that element (content-to-scale) and all it's children. Seems like a job for CSS3 transform's scale operation. However, the problem is that this is a transform on the visualization of that element hierarchy only, it doesn't change the amount of space (or position) of the element on the page. In other words, scaling that element larger will cause it to overlap with the "before" and "after" text.

Is there a simple/reliable way to scale not just the visual representation, but also the amount of space occupied?

Extra points for pure CSS without Javascript. Even more points for a solution that does the right thing with other transformation functions like rotate and skew. This doesn't have to use CSS3 transform, but it does need to be supported across all recent HTML5 capable browsers.

Rich Bradshaw
  • 71,795
  • 44
  • 182
  • 241
kanaka
  • 70,845
  • 23
  • 144
  • 140
  • 3
    Here is [a JS Bin for everyone to experiment in](http://jsbin.com/izicog/3/edit), with [Stylus](http://learnboost.github.com/stylus/) as the styling language. There is also a [plain CSS version](http://jsbin.com/ohosaw/1/edit). – Rory O'Kane Aug 20 '12 at 18:25
  • 1
    Some references on CSS transforms: [a demo of rotate, skew, and scale](http://www.zenelements.com/blog/css3-transform/). Mozilla Developer Network on the [`transform`](https://developer.mozilla.org/en-US/docs/CSS/transform) and [`transform-origin`](https://developer.mozilla.org/en-US/docs/CSS/transform-origin) properties. – Rory O'Kane Aug 20 '12 at 18:32
  • so let me get this straight: you want to transform child element and while doing so, you want CSS to change parent's height, width. Right? If so, then there is no child->to->parent i.e. backward/upward hierarchical inheritance in CSS. –  Aug 27 '12 at 10:48
  • 1
    @AnubhavSaini, I did not rule out Javascript in my question. My goal is for a simple and reliable solution that works across all recent HTML5 capable browsers (regardless of mechanism). Pure CSS would be ideal but not necessary. – kanaka Aug 27 '12 at 15:11

1 Answers1

13

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.

Community
  • 1
  • 1
Lucas Green
  • 3,951
  • 22
  • 27
  • 1
    At first I thought you could fix the nested `em` problem by using the [`rem` (“root em”) unit](http://snook.ca/archives/html_and_css/font-size-with-rem), but now I think that that would only work if you’re scaling the whole page – `rem` only notices font-size changes to the root `html` element. – Rory O'Kane Aug 23 '12 at 20:56
  • what you said about em and image ratio might be quite correct, but how does this answer the question about transformation and keeping the transformed element still inside the outer surroundings? –  Aug 27 '12 at 11:16
  • 1
    [JS Bin of this solution](http://jsbin.com/ehejih/1/edit). [Version also demonstrating the nested `em` problem.](http://jsbin.com/idoxan/1/edit). – Rory O'Kane Aug 27 '12 at 17:59
  • @Anubhav Saini: The last line of the original question says that kanaka doesn't need to use CSS3 Transform, he just needs the scaling, and the desired effect of the scaled size dictating the width/height in layout. I would like to solve it with transforms but in my experience transforms do not have any affect on the layout/positioning of non-transformed elements. – Lucas Green Aug 27 '12 at 21:44
  • will this break down if the user has a minimum font size set on their browser? – Jonathan Basile Apr 27 '15 at 16:08
  • 1
    @JonathanBasile probably – Lucas Green Apr 27 '15 at 23:09