Search code examples
javascripthtmlcssaspect-ratio

Maintaining aspect ratio on element while not exceeding max width or height of entire page


This is a continuation of "Height equal to dynamic width (CSS fluid layout)".

I'd like to maximize the size of a video element, while maintaining the aspect ratio for it, and I'm successful in doing so for the width using most of the answers in the aforementioned question.

However, this is for a single, non-scrolling webpage. Therefore, I'd like the element to automatically reduce the width of the element in case the height is too big.

I'm open to using JavaScript/jQuery to get this result, but a pure CSS solution would be preferable.

In the below example, I've used the img hack to force the aspect ratio to be kept.

Everything works OK if the height is high enough (width works properly, and aspect ratio is kept):

Enough height, no problems

The problem:

Scrollbars are added instead of the element's height getting reduced

How I need it to be when element is too tall (manually edited DOM to obtain result):

Width of element reduced in order for height to fit in page

As you can see here, the width is reduced, which in turn reduces the height to avoid scrollbars while keeping the aspect ratio at 16:9.

See jsfiddle to better understand.


HTML

<script src="https://raw.github.com/flowplayer/flash/master/core/src/javascript/flowplayer.js/flowplayer-3.2.12.min.js">
<div class="top">

    <div class="left">
        <div id="chat">
            chat<br>
            chat<br>
            chat<br>
            chat<br>
            chat<br>
            chat<br>
            chat<br>
            chat<br>
            chat
        </div>
    </div>

    <div class="right">
        <img src="#" width="200" height="58">
    </div>

</div>
<div class="video">
    <img class="maintain169aspectratio" src="https://dl.dropboxusercontent.com/u/21688/staticlinked/maintain_aspect_ratio_hack.png" />
    <div id="player"></div>
</div>

JavaScript (not too relevant, but it generates the player)

$f("player", "flowplayer-3.2.16.swf", {
    clip: {
        provider: 'rtmp',
        live: true,
        url: 'bouvet',
    },
    plugins: {
        rtmp: {
            url: "flowplayer.rtmp-3.2.12.swf",
            netConnectionUrl: '',
            scaling: 'fit',
        }
    }
});

CSS

div.video {
    position: relative;
    margin: 0;
    padding-top: 58px;
}
div.video img.maintain169aspectratio {
    width: 100%;
}
div#player {
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 100%;
}

div#chat {
    position: relative;
    overflow-y: scroll;
    width: 100%;
    height: 100%;
}
div.top {
    position: relative;
    width: 100%;
    height: 58px;
    margin: 0;
}
div.left {
    display: table-cell;
    width: 100%;
    height: 100%;
}
div.right {
    display: table-cell;
    min-width: 200px;
    vertical-align: top;
    height: 100%;
}
body {
    margin: 0;
}

Solution

  • One solution is to use Grid Stylesheets (GSS).

    The following HTML:

    <body>
        <div id="chat">
            Chat
        </div>
        <div id="preview">
            Preview
        </div>
        <div id="video">
            Video
        </div>
    </body>
    

    Can be styled using GSS as following:

    @horizontal |[#chat][#preview]| in(body);
    @vertical |[#chat][#video]| in(body);
    
    #chat[width] == ::window[width] * 0.5;
    #preview[width] == ::window[width] * 0.5;
    
    #chat[height] == #preview[height];
    #chat[height] == 100;
    
    #video[center-x] == ::window[center-x];
    #video[width] <= ::window[width];
    #video[width] == #video[height] * 1.6;
    #video[height] == ::window[height] - 100;
    

    However, GSS is only supported by Firefox 28 and Chrome 34 or newer.

    For the complete solution, look at this Plunker snippet.