1

I want to keep an aspect ratio on an absolute positioned div with auto dimensions. I tried some solutions from other stackoverflow questions, but they don't work or they need fixed dimensions.

I would like the div to wrap its content while maintaining a 4:3 ratio. I would like to solve it with css and less javascript.

Is there a clever way to do this with css?

My code is below.

$('span').hover(function() {
  $(this).find('div').css('visibility', 'visible')
}, function() {
  $(this).find('div').css('visibility', '')
})
.jsmbox {
  position: absolute;
  overflow: hidden;
  -webkit-transition: all .3s ease;
  transition: all .3s ease;
  max-width: 100%;
  max-height: 100%;
  color: black;
  background-color: gold;
  padding: 6px;
  visibility: hidden;
  top: 0;
  left: 0;
  cursor: default;
  text-align: justify;
  z-index: 100;
}
.jsmbox:hover {
  max-width: 400px;
  max-height: 300px;
}
.custom {
  width: 320px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<span style="position: relative">[hover me1]
    <div class="jsmbox">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ullamcorper eleifend augue, at eleifend lacus tincidunt sed. Nam et ipsum non dui pellentesque suscipit at finibus metus. Nullam vel augue eros. Sed sodales mi ut sodales posuere. Nullam eleifend nisl vel urna bibendum egestas. Sed eget dolor nunc. Curabitur elementum dolor sit amet enim pellentesque, vitae cursus tellus tempus. Maecenas non cursus nisl, sit amet volutpat nisl. Integer faucibus at nunc eget euismod.
    </div>
</span> 

<span style="position: relative">[hover me2]
    <div class="jsmbox custom">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ullamcorper eleifend augue, at eleifend lacus tincidunt sed. Nam et ipsum non dui pellentesque suscipit at finibus metus. Nullam vel augue eros. Sed sodales mi ut sodales posuere. Nullam eleifend nisl vel urna bibendum egestas. Sed eget dolor nunc. Curabitur elementum dolor sit amet enim pellentesque, vitae cursus tellus tempus. Maecenas non cursus nisl, sit amet volutpat nisl. Integer faucibus at nunc eget euismod.
    </div>
</span>

<span style="position: relative">[hover me3]
    <div class="jsmbox custom">This text is much shorter!</div>
</span>

The first div (hover me1) is fully auto dimensioned and the text doesn't even fit. [not true! It has max dimensions when it is being hovered over.]

  • The second div (hover me2) has fixed width.
  • Third div (hover me3) also has fixed width, but the text is shorter and so aspect ratio is incorrect and div is too large for its content...
J. Allan
  • 1,418
  • 1
  • 12
  • 23
Franz Tesca
  • 255
  • 1
  • 5
  • 19
  • Still looking for an answer? – J. Allan Aug 20 '16 at 21:40
  • @JefréN. Yes. My actual solution is to set the width in javascript by estimating the contents size by the string length, which is a very poor solution and not accurate at all. – Franz Tesca Aug 21 '16 at 06:55
  • Would you mind giving a JSFiddle/CodePen/whatever so that I can see what you're currently doing? – J. Allan Aug 23 '16 at 00:41
  • @JefréN. Here you are: https://jsfiddle.net/k0hpqy6L/2/ This is my actual "mini plugin" which works well enough on my webpage, but it's not beautiful and still based on an estimate. I don't get a perfect aspect ratio, but I get a readable result. – Franz Tesca Aug 23 '16 at 10:05
  • There are some random comments in js which you don't have to care about. They're misguiding... – Franz Tesca Aug 23 '16 at 10:10
  • Thanks. Isn't `.jsmbox` redundant and unnecessary? I'm not sure what you're trying to accomplish with it that `.jsmcon` can't do. – J. Allan Aug 24 '16 at 10:38
  • I'd love to hear questions, comments, and feedback on my answer. :D – J. Allan Aug 25 '16 at 02:14
  • @JefréN. I use two divs, one inside the other, because if I put the text inside `.jsmbox` directly, during the transition the text try to fit the div dimensions, which makes it behave in a strange way: https://jsfiddle.net/97pk6cyo/ – Franz Tesca Aug 25 '16 at 10:04

1 Answers1

1

In answer to this question:

Is there a clever way to do this with css?

I don't know of one.

There's some dumb or inflexible ones:

  • Set width and height on .jsmcon so that all of them have the same dimensions and aspect ratio. [dumb--it looks horrible and it's inflexible.]

  • Do this. [doesn't work for this problem--despite its cleverness, this solution maintains its aspect ratio based on its container, not it's content.]


I decided to approach this problem a little differently than you.

Rather than approximate the necessary width of the box based on the length of its content, I estimate the necessary width based on how much area the text currently takes up.

Instead of:

var l = box.text().length;
l = (l > $(window).width()*0.9) ? $(window).width()*0.9 : l;

I use this:

/*Some math formulae:
     *****
     ColumnsPerRow = Width/Height;
     Width = ColumnsPerRow * Height;
     Area = Width * Height;
        Area = (ColumnsPerRow * Height) * Height;
        Area = ColumnsPerRow * Height^2;
        Height^2 = Area/ColumnsPerRow;
        Height = sqrt(Area/ColumnsPerRow);
     Width = Area / Height;
     */
        
     //get approximate area needed to display the text
     var tArea = (con.width() * con.height());
     var tColumnsPerRow = ratio; //ratio is global
     var tHeight = Math.sqrt(tArea/tColumnsPerRow);
        
     var l = tArea/tHeight;
     l = (l > $(window).width()*0.9) ? $(window).width()*0.9 : l;

What's the difference?

The difference between the 'old way' and the 'new way' differs based on browser, font-size, etc.

For illustration purposes, here are the results for 2 browsers with font-size: 17px; in the css and var ratio = 4/3 in the JS.

Vivaldi:

31.25% off vs. 4.76% off.
66.67% off vs. 3.18% off.

Firefox:

81.25% off vs. 28.71% off.
36.36% off vs. 8.25% off.


Notes:

  1. The intended aspect ratio is now found at the top of the javascript.

  2. min-width was removed from .jsmcon. (It throws the aspect ratio off on the little one.)

  3. We have some finangling to do so that we can calculate the area of each .jsmcon.

    • box.css("max-width", "unset"); removes the max-width on .jsmbox so that .jsmcon has a width greater than 0px.

    • box.css("max-width", ""); removes max-width from the inline style of .jsmbox so that the CSS in our stylesheet can take over.)

  4. A better way to calculate the area taken up by the text would involve changing things around, forgetting about the transitions, or making a dummy element to test how much area is taken up by the text.

JSFiddle here.

Community
  • 1
  • 1
J. Allan
  • 1,418
  • 1
  • 12
  • 23
  • That's clever. It's not the clean css solution which I now suppose does not exist, but it works like a charm. Thanks. I have not understood the 3rd note. In fiddle it works well. – Franz Tesca Aug 25 '16 at 09:54