4

The following is part of my small contribution to a post on auto height transitions:

html {
  display: grid;
}

body {
  display: flex;
  flex-direction: column;
}

.content {
  background: aqua;
  flex-basis: 0;
  overflow: hidden;
  transition: all 1s ease;
}

span:hover + .content {
  flex: 1;
}
<span>Hover over me!</span>

<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

<p>Rest of the page content...</p>

It works in all major browsers except Safari. Any CSS tweak to run it smoothly in Safari as well?

Mori
  • 8,137
  • 19
  • 63
  • 91

3 Answers3

1

In your code flex:1 expands to flex: 1 1 0%, thanks for the correction.
Your the demo does animate flex-grow but it works because there is free space for the content to grow. Make the flexbox flex-flow: column and remove fixed height height: 200px;.

.flex-container {
  width: 300px;
  /* uncomment height to start animating*/
  /*height: 200px;*/
  font-size: 32px;
  outline: 1px solid black;
  display: flex;
  flex-flow: column;
}

.flex-container div {
  flex-grow: 0;
}

.item1 {
  background: #e84d51;
}

.item2 {
  background: #7ed636;
}

.item3 {
  background: #2f97ff;
}

.animated {
  animation: test 4s infinite;
}

@keyframes test {
  0% {
    flex-grow: 0;
  }
  100% {
    flex-grow: 1;
  }
}
<div class="flex-container">
  <div class="item1">1</div>
  <div class="item2 animated">2</div>
  <div class="item3">3</div>
</div>

Now it doesn't animate because flex-grow is for distributing free space. If there is no free space, then changing flex-grow doesn't affect anything.


Your code sample in the opening post works because of the weird combination of display grid, percentage flex-basis and flex-grow values < 0:

<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    #grd {
      /* if you remove following line , 
      then the .content won't clip due to overflow */
      display: grid;
    }
    
    #flx {
      display: flex;
      flex-flow: column;
    }
    
    .content {
      background: aqua;
      flex-basis: 0%;
      flex-grow: 0.25;
      overflow: hidden;
    }
  </style>
</head>
<body>
  <div id=grd>
    <div id=flx>
      <span>Top</span>
      <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
        dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
      <p>Bottom</p>
    </div>
  </div>
</body>
</html>

Here flex-grow:0.25 shouldn't reduce the content size. ref. Somehow this happens on Chrome and not on Safari. If you remove display:grid, then overflow:hidden stops clipping the content. I don't think chrome is correct here cos flex-grow shouldn't reduce the .content size.

There is some difference I found how Chrome and safari switch attribute units while animating. Run following code on both chrome and safari:

<!DOCTYPE html>
<html lang="en">

<head>
  <script>
    window.setInterval(function () {
      init();
    }, 400);

    function init() {
      var content = document.querySelector('.content');
      var stat = window.getComputedStyle(content).getPropertyValue('flex-basis');
      var grow = window.getComputedStyle(content).getPropertyValue('flex-grow');
      var height = window.getComputedStyle(content).getPropertyValue('height');

      document.getElementById('stat').innerText = 'flex-basis:' + stat +
        '\n' + 'flex-grow:' + grow + '\n' + 'height: ' + height;
    }
  </script>
  <style>
    #grd {
      display: grid;
    }

    #flx {
      display: flex;
      flex-flow: column;
    }

    .content {
      background: aqua;
      flex-basis: 0;
      overflow: hidden;
      transition: all 6s ease;
    }

    span:hover+.content {
      flex: 1;
    }

    p {
      white-space: pre;
    }

  </style>
</head>

<body>
  <div id=grd>
    <div id=flx>
      <span>Hover over me!</span>

      <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
        labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
        aliquip ex
        ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
        nulla
        pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
        laborum.</div>

      <p>Rest of the page content...</p>
      <p id="stat">stat</p>
    </div>
  </div>
</body>

</html>

Observer flex-basis see how it switches from 0px to 0% instantly on chrome on animation start. But on Safari it switches at the end of animation. I don't know how it relates to the issue.

Solution: I still stick to animating flax-basis instead of flex-grow here. If fit-content is experimental and not desired then you can still use min-content and max-content. Unlike fit-content all browsers support them.

html {
  display: grid;
}

body {
  display: flex;
  flex-direction: column;
}

.content {
  background: aqua;
  flex-basis: 0;
  overflow: hidden;
  transition: all 1s ease;

  /* limit the height */
  /* use either of these as per situation */
  max-height: fit-content;
  max-height: min-content;
  max-height: max-content;
}

span:hover+.content {
  flex: 1;
}


/* Safari 11+ */

@media not all and (min-resolution: 0.001dpcm) {
  @supports (-webkit-appearance: none) and (stroke-color: transparent) {
    span:hover + .content {
      flex-basis:100vh;
    }
  }
}


/* Safari 10.1 */

@media not all and (min-resolution: 0.001dpcm) {
  @supports (-webkit-appearance: none) and (not (stroke-color: transparent)) {
    span:hover + .content {
      flex-basis:100vh;
    }
  }
}


/* Safari 6.1-10.0 (but not 10.1) */

@media screen and (min-color-index: 0) and(-webkit-min-device-pixel-ratio:0) {
  @media {
    span:hover+.content {
      flex-basis: 100vh;
    }
  }
}
<span>Hover over me!</span>

<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
  in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

<p>Rest of the page content...</p>


We have to set max-height to intrinsic size to limit the height, otherwise it'll grow till end of the view port.

Note: I've tested the code on Safari 14.1 and Chrome 95 on iPadOS 15.1
To create Safari specific CSS I've referred https://www.browserstack.com/guide/create-browser-specific-css

the Hutt
  • 16,980
  • 2
  • 14
  • 44
  • "_On Safari `flex-grow` is not animable._" Please see [this demo](https://codepen.io/mori79/pen/RwLWZgM). "_In your code `flex: 1` expands to `flex: 1 1 0`_" Actually it expands to `flex: 1 1 0%`, and surprisingly they're different. "_You are not changing `flex-basis`_" I'm changing `flex-basis: 0` to `flex-basis: 0%` and `flex-grow: 0` to `flex-grow: 1`. That's how your demo works in non-Safari browsers. "_We have to set `max-height: fit-content` to limit the height_" We'd better stay away from experimental features. – Mori Dec 04 '21 at 09:05
  • Transition to `flex-basis: 100vh` causes the same problem as `max-height` does. Please see [this post](https://stackoverflow.com/a/8331169/478018) and its comments. – Mori Dec 05 '21 at 16:36
  • @Mori Your snippet in OP is working because of a known bug. https://bugs.chromium.org/p/chromium/issues/detail?id=1279171 Devs won't fix it. And are suggesting to use `flex-basis: auto` and `height: fit-content; ` – the Hutt Dec 14 '21 at 01:44
  • Change `display: grid` to `display: flex` and it still works in non-Safari browsers. – Mori Dec 14 '21 at 05:05
  • I think if you read the explanation this applies to containers that do mentioned second layout pass. And may not be specific to grid alone. – the Hutt Dec 14 '21 at 05:15
0

As you know, flex transition doesn't work since Safari 13.1 (Mac). But if you use the below code maybe it works.

html {
  display: grid;
}

body {
  display: flex;
  flex-direction: column;
}

.content {
  background: aqua;
  height: 0;
  overflow: hidden;
  transition: all 1000ms ease;
}

span:hover + .content {
  height: 100%;
}
<span>Hover over me!</span>

<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

<p>Rest of the page content...</p>

In the above snippet code, I change transition: all 1s easy; to transition: all 1000ms easy;.

I came to this conclusion based on This and this

Zahra Mirzaei
  • 729
  • 3
  • 7
0

Transition in safari has some problems that discussed here: css transitions not working in safari

It can't work for auto values and all can't be use. also -webkit- at the start should use. Here is my trick to solve this problem (Known problem: max-height is limited to 1000px):

.content {
  background: aqua;
  flex-basis: 0;
  max-height: 0;
  overflow: hidden;
  transition: all 1s ease;
  -webkit-transition: max-height 1s ease;
}

span:hover + .content {
  flex: 1;
  max-height: 1000px;
}
Amirreza Noori
  • 1,456
  • 1
  • 6
  • 20