1

Is there a way to have grid cells whose width is based on fr units that dynamically adjust their height so that they stay square?

Also, I was hoping to do this without JS

The below fiddle has some example code. The divs with the class 'sqaure' are the ones which I want to dynamically adjust their height to match their width (which is 1fr so it changes)

https://jsfiddle.net/bpk0sLvL/403/

.holder {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 4px;
  row-gap: 4px;
}

.box {
  background-color: #ccc;
}

.wide {
  grid-column-start: 1;
  grid-column-end: 3;
}
<div class="holder">
  <div class="box wide">
    <p>This can be any height</p>
    <p>All these divs are sized based on fr, so I want to have the two square divs stay square as they dynamically resize </p>
  </div>
  <div class="box sqaure">
    This needs to be a sqaure
  </div>
  <div class="box sqaure">
    This needs to be a square as well
  </div>
</div>
George Kendros
  • 792
  • 3
  • 10
  • 23

1 Answers1

1

You need to:

  1. identify the width of .square; and
  2. ensure that the height of .square is equal to that width.

You can identify the width of .square with one line of javascript:

var squareWidth = document.getElementsByClassName('square')[0].offsetWidth;

You can ensure the height of .square is equal to that width with two lines of javascript:

var holder = document.getElementsByClassName('holder')[0];
holder.style.gridTemplateRows = 'auto ' + squareWidth + 'px';

Working Example:

function calculateSquareHeight() {

    var holder = document.getElementsByClassName('holder')[0];
    var squareWidth = document.getElementsByClassName('square')[0].offsetWidth;
    holder.style.gridTemplateRows = 'auto ' + squareWidth + 'px';
}

window.addEventListener('load', calculateSquareHeight, false);
window.addEventListener('resize', calculateSquareHeight, false);
.holder {
display: grid;
grid-template-columns: 1fr 1fr;
grid-column-gap: 4px;
grid-row-gap: 4px;
}

.box {
background-color: #ccc;
}

.wide {
grid-column-start: 1;
grid-column-end: 3;
}
<div class="holder">
<div class="box wide">
<p>This can be any height</p>
<p>All these divs are sized based on fr, so I want to have the two square divs stay square as they dynamically resize </p>
</div>

<div class="box square">
This needs to be a square
</div>

<div class="box square">
This needs to be a square as well
</div>
</div>
Rounin
  • 27,134
  • 9
  • 83
  • 108
  • Sorry. I realize now I should have made it clear in the original question that I was hoping for a method to do this with CSS alone.suggested method (setting height to 0 and padding to 100) – George Kendros May 16 '18 at 13:22
  • It's okay - I gathered that you were looking for a pure CSS approach. I often suggest CSS approaches where others suggest jQuery or Javascript approaches. But I posted the script above, because as far as I am aware there is no satisfactory CSS approach. I'm aware of the padding "trick", but it's a hack and not always ideal. What I'd really like to see is a **ratio function** in CSS, so you could write: `height: ratio(1/1);` – Rounin May 16 '18 at 15:05
  • 1
    Agreed, I actually ended up doing it in JS after trying the padding hack and seeing how its so temperamental. I think having a css function like that would be cool. Or even having ew and eh units which mimicked vh and vw, except for the current element. If we had that, then we could at least build the ratio with the calc function. – George Kendros May 16 '18 at 19:05
  • Yes, agreed - `ew` and `eh` lengths would be a very smart innovation. And maybe even `pw` and `ph` lengths (referring to the element's immediate parent) too. – Rounin May 16 '18 at 19:33