18

I have used CSS Grid to lay out a difficult grid layout where grid items have varying heights and widths. The height of the grid rows is set to 1fr so that it is proportional to the height of the grid. Some grid items have a grid-row: span 2 or grid-row: span 3.

The grid element is absolutely positioned inside of wrapper with padding on it in order to maintain the aspect ratio.

This has all worked perfectly in Chrome and Firefox and even in IE with the help of the -ms- prefix.

In Safari, it's a different story:

However, in Safari the grid row does not seem to be calculated the same way — the height of the rows is much, much shorter in Safari than any other browser, which ruins the layout. Why is this?

Removing position absolute from the grid element doesn't change the row height. But it seems that putting height: 0 on the grid wrapper does something that makes the row height behave the same in Safari as it does in Chrome and Firefox. What's the reason behind this?

Code:

Codepen: https://codepen.io/katrina-isabelle/pen/rRqvXq

.grid-wrapper {
  position: relative;
  padding-bottom: 60%;
}

.grid {
  display: grid;
  grid-gap: 2px;
  grid-template-columns: 29% 21% 21% 29%;
  grid-auto-rows: 1fr;
  position: absolute;
  width: 100%;
  height: 100%;
}

.grid-item {
  width: 100%;
  color: #ccc;
  background: #ccc;
}
.grid-item--1 {
  grid-row: span 2;
}
.grid-item--2 {
  grid-row: span 3;
}
.grid-item--3 {
  grid-row: span 2;
}
.grid-item--4 {
  grid-row: span 3;
}
.grid-item--5 {
  grid-row: span 2;
}
.grid-item--6 {
  grid-row: span 3;
}
.grid-item--7 {
  grid-row: span 2;
}
.grid-item--8 {
  grid-row: span 2;
}
.grid-item--9 {
  grid-row: span 1;
}
<div class="grid-wrapper">
  <div class="grid">
    <div class="grid-item grid-item--1">
      Grid item
    </div>
    <div class="grid-item grid-item--2">
      Grid item
    </div>
    <div class="grid-item grid-item--3">
      Grid item
    </div>
    <div class="grid-item grid-item--4">
      Grid item
    </div>
    <div class="grid-item grid-item--5">
      Grid item
    </div>
    <div class="grid-item grid-item--6">
      Grid item
    </div>
    <div class="grid-item grid-item--7">
      Grid item
    </div>
    <div class="grid-item grid-item--8">
      Grid item
    </div>
    <div class="grid-item grid-item--9">
      Grid item
    </div>
  </div>
</div>
kisabelle
  • 592
  • 1
  • 7
  • 17
  • If I remember well, Safari doesn't like the unit `%` you have used for `.grid`. In general I would use for grid layouts within safari `display: flex`. But that's just my personal preference. – Demian Mar 25 '19 at 23:35
  • @Demian Just wanted to note, if you inspect the elements you'll see that the `.grid` element does expand to fill the height of it's parent, it's the rows inside the grid that are not expanding. How would you recreate this layout in flex? – kisabelle Mar 26 '19 at 16:51
  • With parent flex and children inline-flex. – Demian Mar 26 '19 at 18:32
  • @Demian Would love to see an example. I just tried `display: flex` on `.grid` and `display: inline-flex` on `.grid-items` and it broke the layout – kisabelle Mar 26 '19 at 18:48

3 Answers3

23

I've been having a similar issue in Safari 12+, as I was also using padding to force aspect ratios in a grid based layout. I'm not sure if this is exact same problem you were having, but the fix below works for me on your pen in Safari.

TLDR: Put display:grid on the div surrounding your grid container. Here it is in action: https://codepen.io/harrison-rood/pen/rNxXWPb

After tearing my hair out for hours on this, I decided to try placing display:grid on the wrapper around my main grid, and it worked perfectly! I have no idea why this would fix it, but my guess would be that it gives Safari some more context on the parent container and that allows height:100% to refer to the grid context instead of the parent, similar to how Chrome and Firefox handle this by default. This was so frustrating to me that I felt obligated to create a SO account just so I could post this! Hope it helps!

hrood
  • 401
  • 3
  • 6
  • 2
    Thanks for sharing this solution! As I mentioned in my OP you can also add `height: 0` to fix it. Very mysterious. I think `display: grid` feels like a better approach but either way it never hurts to have multiple options – kisabelle Sep 04 '20 at 18:53
  • Super weird right? I'd love to know WHY this works but as of yet I haven't been able to nail it down. – hrood Sep 12 '20 at 17:46
  • Wow this worked for me too! Very weird indeed but thanks for finding the solution! – Sacha Dec 30 '20 at 12:27
2

Instead of height: 100% on the grid container (.grid), use height: 100vh.

Or, if you really want to use percentages, then make sure the parent has a defined height. Some browsers still adhere to an old rule about percentage heights, namely:

An element with a percentage height must have a parent with a defined height as a reference point or the percentage height will be ignored.

More details here:

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • I mentioned in the second paragraph that I'm trying to maintain the aspect ratio of the grid, so `100vh` is not appropriate for my use case. Defining the height in pixels means that I would have to create many media queries to maintain the aspect ratio, which is why I used the percentage padding trick. I would rather use the `height: 0` trick than have to write all those media queries – kisabelle Mar 26 '19 at 16:47
  • `height: 100vh` is a percentage, but it's relative to the viewport. The other option I presented is also a percentage, but implemented in accordance with spec rules. – Michael Benjamin Mar 26 '19 at 17:00
  • So the parent (`.grid-wrapper`) doesn't have a defined height because the height is being set by the padding – this is how the aspect ratio is maintained. Any ideas on how I can maintain the aspect ratio if I'm defining the height of the parent or the `.grid`? – kisabelle Mar 26 '19 at 17:11
  • Also, to clarify, the grid is displayed at a width of 100% so that's why the aspect ratio would not be maintained if the height is relative to the viewport height. – kisabelle Mar 26 '19 at 17:13
0

(Posting as an answer in order to include pictures.) I'm getting these results with Safari and Chrome (Vivaldi), after following your suggested fix with setting height: 0. As you say, this expands the height of the divs from a nearly collapsed state in Safari.

I'm wondering: Is it the solution on the left you are aiming for, or should it be like on the right? If the alternative on the left is your goal you could get the same results with setting grid-auto-rows: auto on .grid. I guess in both cases (the height: 0 and grid-auto-rows: auto) you are somehow effectively escaping calculation of height as fractions of the .grid-wrappers height.

I can't say why Safari does this in such a different way, but - pragmatically - I would personally consider using grid areas instead of spans to place the elements - at least if the layout is fairly given.

enter image description here

jensmtg
  • 506
  • 5
  • 23
  • The one on the right is the desired layout. In the one on the left, it looks like you copied my SCSS but didn't enable the SCSS preprocessor – kisabelle Mar 26 '19 at 16:41
  • Could you provide an example using grid areas instead of spans? I'm new to grid and unfamiliar with that concept – kisabelle Mar 26 '19 at 16:49