-1

I want to create an HTML page with:

  • A fixed-width, full-height Navigation pane on the left
  • A square element in the centre of the remaining area

I want this square to be as big as possible, expanding to fill the area not taken up by the navigation pane.

I have a JavaScript solution for this (see below and as a jsFiddle), but I'm hoping that it is possible to do this as a CSS only solution.


<!DOCTYPE html>
<html lang=en>
<head>
  <style>
    html, body {
      margin: 0;
      height: 100%;
      background-color: #fff;
    }
    nav {
      height: 100%;
      width: 96px;
      background-color: #666;
    }
    main {
      position: absolute;
      background-color: #000;
      color: #fff;
    }
  </style>  
</head>

<body>
<nav>
  Navigation
</nav>

<main>
  This should be square
</main>

<script>
;(function createSquareArea() {
  var main = document.querySelector("main")
  var nav = document.querySelector("nav")
  var navWidth = nav.getBoundingClientRect().width
  var debounceDelay = 100
  var timeout

  window.onresize = windowResized
  maintainRatio()

  function windowResized() {
    if (timeout) {
      window.clearTimeout(timeout)
    }
    timeout = window.setTimeout(maintainRatio, debounceDelay)
  }

  function maintainRatio() {
    timeout = 0

    var windowHeight = window.innerHeight
    var mainWidth = window.innerWidth - navWidth
    var minDimension = Math.min(windowHeight, mainWidth)

    var left = (mainWidth - minDimension) / 2 + navWidth
    var top = (windowHeight - minDimension) / 2

    main.style.left = left + "px"
    main.style.top = top + "px"
    main.style.width = minDimension + "px"
    main.style.height = minDimension + "px"
  }
})()
</script>
</body>
</html>
James Newton
  • 6,623
  • 8
  • 49
  • 113
  • This is different from the [Maintain Aspect Ratio question] (http://stackoverflow.com/questions/20590239/maintain-aspect-ratio-of-div-but-fill-screen-width-and-height-in-css) that you linked to, in that it requires a vertical navigation pane, so viewport units cannot be used directly. – James Newton Jan 27 '16 at 21:10

3 Answers3

2

JSFiddle: https://jsfiddle.net/ymzq6zm0/7/

HTML

<nav>
  Navigation
</nav>

<main>
  <div class="sc">
    This should be square
  </div>
</main>

CSS

   html, body {
      margin: 0;
      height: 100%;
      background-color: #fff;
    }
    .wrapper {
      display: flex;
      align-items: center;
      height: 100%;
    }
    nav {
      float: left;
      height: 100%;
      width: 96px;
      background-color: #666;
    }
    main {
      float: left;
      width: calc(100% - 96px);
      height: 100vmin;
      max-height: calc(100vw - 96px);
    }
    .sc {
      margin: 0 auto;
      background-color: #000;
      color: #fff;
      height: 100vmin;
      width: 100vmin;
      max-width: 100%;
      max-height: calc(100vw - 96px);
    }

How it works

Our main objective here is to:

  • Center align .sc
  • Align .sc vertically center
  • Make sure .sc is always a sqaure
  • Make .sc responsive

The square is highly responsive as it changes its height and width according to the window's or view port's height and width. We need to use vw (viewport's width) and vmin (lowest value between viewport's height and width). Read more about these units here: https://css-tricks.com/viewport-sized-typography/

To make .sc a square, we need to make sure its width and height are always equal. Since the ratio of height and width of viewport is not always the same, we need to find out the lowest value between these two and assign them to .sc which can be done using the vmin unit mentioned above.

The square should always remain centered in the remaining area after the navigation on the left, never cross the remaining area and resize accordingly.

This can be accomplished the following codes:

    nav {
      float: left;
      height: 100%;
      width: 96px;
      background-color: #666;
    }
    main {
      float: left;
      width: calc(100% - 96px);
      height: 100vmin;
      max-height: calc(100vw - 96px);
    }
    .sc {
      margin: 0 auto;
      background-color: #000;
      color: #fff;
      height: 100vmin;
      width: 100vmin;
      max-width: 100%;
      max-height: calc(100vw - 96px);
    }

main is the remaining area after nav. We make sure of this by using the calc property to subtract the nav width from 100%.

The .sc is placed inside main and we have added the extra max-width and max-height properties to make sure .sc always resizes itself according to main.

max-height: calc(100vw - 96px); property of .sc is always equal to width: calc(100% - 96px); property of main. They both calculate the same values.

By adding max-width: 100%; to .sc we make sure it's maximum width is equal to that of main.

Now since, both the max-height and max-width along with width and height of .sc remain the same, it will always be a square.

At the end we put both nav and main inside .wrapper which is a flexbox and has align-items: center; property. This will ensure that the square is always vertically centered with respect to the nav.

Yug Kapoor
  • 785
  • 5
  • 10
1

This can be accomplished with viewport units.

HTML

<div class='page-wrapper'>
  <nav>

  </nav>
  <div class='content'>
    <div class='square'>

    </div>
  </div>
</div>

CSS

body, html
{
  height: 100%;
}

.page-wrapper
{
  display: flex;
  height: 100%;
  width: 100%;
}

nav
{
  height: 100%;
  width: 200px;
  background-color: #444;
}

.content
{
  flex-grow: 1;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
}

.square
{
  width: 100vh;
  height: 100vh;
  background-color: #111;
  max-width: calc( 100vw - 200px );
  max-height: calc( 100vw - 200px );
}

See this jsFiddle https://jsfiddle.net/ryannwarner/hugt40cm/

Ryan Warner
  • 1,354
  • 1
  • 10
  • 7
0

Viewport units and calc can do a lot of this but I'm not sure on your final desired result.

If you want both dimension to recalculate you will need javascript.

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
  background-color: #fff;
}
nav {
  height: 100%;
  width: 96px;
  background-color: #666;
}
main {
  position: absolute;
  background-color: lightgreen;
  color: #fff;
  top: 0;
  left: 96px;
  height: calc(100vw - 96px);
  max-height: 100vh;
  width: calc(100vw - 96px);
  max-width: 100vh;
}
<nav>
  Navigation
</nav>

<main>
  This should be square
</main>

JSfiddle demo with no max-height...I think you can see the problem with a CSS method.

Paulie_D
  • 107,962
  • 13
  • 142
  • 161
  • Your green element remains a square, but it is always flush to the edge of the Navigation pane, rather than centred. – James Newton Jan 27 '16 at 21:37
  • How much space do you want...you haven't stated. It's just a matter of adjusting the calc values to adjust for any spacing. As I said, we don't know what this is supposed to look like. In any case, if the size is determined by *either* height **or** width (whichever is smaller) you will need js to calculate. – Paulie_D Jan 27 '16 at 21:43
  • I provided a [jsFiddle](https://jsfiddle.net/ymzq6zm0/1/) that shows exactly how I want this to behave. – James Newton Jan 27 '16 at 21:45
  • No...you showed a rectangle...not a square. Making the square is simple enough but you haven't stated any min/max requirements as to size. The fiddle is unclear there. – Paulie_D Jan 27 '16 at 21:46
  • The black **square** in my jsFiddle is always as tall and as wide as possible. If the white rectangle that contains it is tall, then the square is the full width. If the white rectangle is wide, then the square is the full height. The square is "as big as possible, expanding to fill the area not taken up by the navigation pane." Are you seeing something different? – James Newton Jan 27 '16 at 21:50