70

From what I've seen in other answers, CSS viewport units can't be used in calc() statements yet. What I would like to achieve is the following statement:

height: calc(100vh - 75vw)

Is there some workaround way I can achieve this using purely CSS even though the viewport units can't be used in the calc() statement? Or just CSS and HTML? I know I can do it dynamically using javascript, but I'd prefer CSS.

Community
  • 1
  • 1
golmschenk
  • 11,736
  • 20
  • 78
  • 137
  • Can you not use javascript? – ggdx Jan 22 '14 at 03:03
  • 1
    Can more context to what you're trying to do? Someone may find a solution outside the narrow definition of the problem. – Andrew Jan 22 '14 at 04:17
  • What exactly is your use case? – apaul Jan 23 '14 at 00:22
  • I'm building a single screen app (no scrolling). The all the elements need to fit on the screen, but several need to preserve ratio. Some of these that preserve the ratio are a complete row across the screen, so depending on their width they must be a certain height. Then the remaining elements are free to take up whatever height those elements don't use. This gives the 100vh (the original screen height) subtracting out some ratio of the width (75vw, although that's not really the ratio, I just gave that as an example). However, I feel the general question is more useful for future people. – golmschenk Jan 23 '14 at 03:01
  • @golmschenk How do you expect that to work with pure CSS when you are aware that the units are not supported? – Mr. Alien Jan 23 '14 at 15:55
  • @Mr.Alien: I don't expect to work with pure CSS. But if there are clean CSS solutions, it's often a good choice to use. I'll use JS when that's the better choice. – golmschenk Jan 23 '14 at 19:27
  • @golmschenk Use JS, instead of reversing the logics with CSS and implementing it, will be dirty to maintain as well – Mr. Alien Jan 23 '14 at 19:28
  • @Mr.Alien: I very well might. The point of asking this question was to see if anyone has a good CSS solution, not to use any possible solution that comes up. – golmschenk Jan 23 '14 at 19:33
  • @golmschenk glad if it comes up, I don't think it will though – Mr. Alien Jan 23 '14 at 19:35

4 Answers4

79

Before I answer this, I'd like to point out that Chrome and IE 10+ actually supports calc with viewport units.

FIDDLE (In IE10+)

Solution (for other browsers): box-sizing

1) Start of by setting your height as 100vh.

2) With box-sizing set to border-box - add a padding-top of 75vw. This means that the padding will be part f the inner height.

3) Just offset the extra padding-top with a negative margin-top

FIDDLE

div
{
    /*height: calc(100vh - 75vw);*/
    height: 100vh;
    margin-top: -75vw;
    padding-top: 75vw;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    background: pink;
}
Arjan Einbu
  • 13,543
  • 2
  • 56
  • 59
Danield
  • 121,619
  • 37
  • 226
  • 255
  • The only difference with mine is compatibility (see http://caniuse.com/#feat=viewport-units and http://caniuse.com/#feat=css3-boxsizing). Dunno if it's the downvote reason though. – MatTheCat Jan 23 '14 at 17:03
  • @golmschenk MatTheCat's solution is not good as it has `margin-top` in percentage. go with this solution. – Mr_Green Jan 25 '14 at 04:59
  • Danield, could this be improved using css translate? I am just asking in curious. – Mr_Green Jan 25 '14 at 05:04
  • @Mr_Green how is a percent `margin-top` a problem? – MatTheCat Jan 25 '14 at 23:42
6

As a workaround you can use the fact percent vertical padding and margin are computed from the container width. It's quite a ugly solution and I don't know if you'll be able to use it but well, it works: http://jsfiddle.net/bFWT9/

<!DOCTYPE html>
<html>
    <head>
        <title></title>
    </head>
    <body>
        <div>It works!</div>
    </body>
</html>

html, body, div {
    height: 100%;
}
body {
    margin: 0;
}
div {
    box-sizing: border-box;
    margin-top: -75%;
    padding-top: 75%;
    background: #d35400;
    color: #fff;
}
MatTheCat
  • 18,071
  • 6
  • 54
  • 69
  • thrilled to see the only (?) scenario where margin behaviour as per spec is desired – Oleg Aug 10 '16 at 04:49
6
<div>It's working fine.....</div>

div
{
     height: calc(100vh - 8vw);
    background: #000;
    overflow:visible;
    color: red;
}

Check here this css code right now support All browser without Opera

just check this

Live

see Live preview by jsfiddle

See Live preview by codepen.io

MD Ashik
  • 9,117
  • 10
  • 52
  • 59
0

Doing this with a CSS Grid is pretty easy. The trick is to set the grid's height to 100vw, then assign one of the rows to 75vw, and the remaining one (optional) to 1fr. This gives you, from what I assume is what you're after, a ratio-locked resizing container.

Example here: https://codesandbox.io/s/21r4z95p7j

You can even utilize the bottom gutter space if you so choose, simply by adding another "item".

Edit: StackOverflow's built-in code runner has some side effects. Pop over to the codesandbox link and you'll see the ratio in action.

body {
  margin: 0;
  padding: 0;
  background-color: #334;
  color: #eee;
}

.main {
  min-height: 100vh;
  min-width: 100vw;
  display: grid;
  grid-template-columns: 100%;
  grid-template-rows: 75vw 1fr;
}

.item {
  background-color: #558;
  padding: 2px;
  margin: 1px;
}

.item.dead {
  background-color: transparent;
}
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="src/index.css" />
  </head>

  <body>
    <div id="app">
      <div class="main">
        <div class="item">Item 1</div>
        <!-- <div class="item dead">Item 2 (dead area)</div> -->
      </div>
    </div>
  </body>
</html>
Artif3x
  • 4,391
  • 1
  • 28
  • 24