skip to Main Content
const {useState} = React;

const App = () => {
  const [isMinimized, setIsMinimized] = useState(false);

  const _setClasses = () => {
    if (isMinimized) return "container container-minimized";
    return "container";
  };

  return (
    <div className="App">
      <div className={_setClasses()}>
        <p>Foo</p>
        <p>Bar</p>
        <p>Foobar</p>
        <div
          onClick={() => setIsMinimized(!isMinimized)}
          className="minimize-element"
        >
          <span />
        </div>
      </div>
    </div>
  );
}

ReactDOM.render(
    <App />,
    document.getElementById("root")
);
.App {
  font-family: sans-serif;
  text-align: center;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

.container {
  transition: height 2s ease-out;
  width: 100%;
  background-color: hotpink;
  top: 0;
  left: 0;
  position: fixed;
  box-shadow: 0px 3px 3px -2px rgba(0, 0, 0, 0.2),
    0px 3px 4px 0px rgba(0, 0, 0, 0.14), 0px 1px 8px 0px rgba(0, 0, 0, 0.12);
  max-height: 60%;
  overflow: hidden;
  flex-direction: column;
}

.container-minimized {
  height: 55px;
}

.minimize-element {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 5px;
  background-color: yellowgreen;
  padding-top: 4px;
  padding-bottom: 4px;
  position: absolute;
  bottom: 0;
}

.minimize-element:hover {
  cursor: pointer;
}

.minimize-element > span {
  background-color: red;
  width: 35px;
  height: 6px;
  border-radius: 7px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.development.js"></script>
<div id="root"></div>

I want to animate from a max-height which is set in percentage to a fixed height which is set in pixel.

Here is also a codesandbox displaying the problem: https://codesandbox.io/s/holy-snowflake-f6p5l9?file=/src/styles.css:0-907

Is there a way to accomplish that?

2

Answers


  1. Not with CSS as far as I know. You can make it work if you move from a static height to another static height: height:100px; -> height:200px;

    It also works if you transition the max-height itself: max-height:35%; -> max-height:55px;, but it will shrink from the full 35 percent, even though you may only see about 12% height on the page.

    You may need some JS here.

    Login or Signup to reply.
  2. Very close! It’s just a matter of:

    1. Transitioning the max-height property
    2. Setting the max-height property to the appropriate values
      • When open: 100%
      • When closed: 55px

    It’s worth noting that the parent styles will affect the behaviour of the percentages this answer discusses that the max-height is often based on the parent’s height.

    const {useState} = React;
    
    const App = () => {
      const [isMinimized, setIsMinimized] = useState(false);
    
      const _setClasses = () => {
        if (isMinimized) return "container container-minimized";
        return "container";
      };
    
      return (
        <div className="App">
          <div className={_setClasses()}>
            <p>Foo</p>
            <p>Bar</p>
            <p>Foobar</p>
            <div
              onClick={() => setIsMinimized(!isMinimized)}
              className="minimize-element"
            >
              <span />
            </div>
          </div>
          <Body />
        </div>
      );
    }
    
    const Body = () => {
      return (
        <div className="MainBody">
          <p>p1</p>
          <p>p2</p>
          <p>p3</p>
          <p>p4</p>
          <p>p5</p>
          <p>another paragraph</p>
          <p>another paragraph</p>
          <div>some final content</div>
        </div>
      )
    }
    
    ReactDOM.render(
        <App />,
        document.getElementById("root")
    );
    .App {
      font-family: sans-serif;
      text-align: center;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
    }
    
    .container {
      transition: max-height 2s ease-in-out;
      width: 100%;
      background-color: hotpink;
      top: 0;
      left: 0;
      position: fixed;
      box-shadow: 0px 3px 3px -2px rgba(0, 0, 0, 0.2),
        0px 3px 4px 0px rgba(0, 0, 0, 0.14), 0px 1px 8px 0px rgba(0, 0, 0, 0.12);
      max-height: 100%;
      overflow: hidden;
      flex-direction: column;
    }
    
    .container-minimized {
      max-height: 55px;
    }
    
    .minimize-element {
      width: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      margin-top: 5px;
      background-color: yellowgreen;
      padding-top: 4px;
      padding-bottom: 4px;
      position: absolute;
      bottom: 0;
    }
    
    .minimize-element:hover {
      cursor: pointer;
    }
    
    .minimize-element > span {
      background-color: red;
      width: 35px;
      height: 6px;
      border-radius: 7px;
    }
    
    .MainBody {
      margin-top: 55px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.development.js"></script>
    <div id="root"></div>

    EDIT: It’s also worth considering that the fixed position height should be considered when having adjacent content. In the snippet below I’ve added a div of class MainBody and set the margin-top: 55px which will mean that the first few elements are not hidden behind the container element.

    const {useState} = React;
    
    const App = () => {
      const [isMinimized, setIsMinimized] = useState(false);
    
      const _setClasses = () => {
        if (isMinimized) return "container container-minimized";
        return "container";
      };
    
      return (
        <div className="App">
          <div className={_setClasses()}>
            <p>Foo</p>
            <p>Bar</p>
            <p>Foobar</p>
            <div
              onClick={() => setIsMinimized(!isMinimized)}
              className="minimize-element"
            >
              <span />
            </div>
          </div>
          <Body />
        </div>
      );
    }
    
    const Body = () => {
      return (
        <div className="MainBody">
          <p>p1</p>
          <p>p2</p>
          <p>p3</p>
          <p>p4</p>
          <p>p5</p>
          <p>another paragraph</p>
          <p>another paragraph</p>
          <div>some final content</div>
        </div>
      )
    }
    
    ReactDOM.render(
        <App />,
        document.getElementById("root")
    );
    .App {
      font-family: sans-serif;
      text-align: center;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
    }
    
    .container {
      transition: max-height 2s ease-in-out;
      width: 100%;
      background-color: hotpink;
      top: 0;
      left: 0;
      position: fixed;
      box-shadow: 0px 3px 3px -2px rgba(0, 0, 0, 0.2),
        0px 3px 4px 0px rgba(0, 0, 0, 0.14), 0px 1px 8px 0px rgba(0, 0, 0, 0.12);
      max-height: 100%;
      overflow: hidden;
      flex-direction: column;
    }
    
    .container-minimized {
      max-height: 55px;
    }
    
    .minimize-element {
      width: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      margin-top: 5px;
      background-color: yellowgreen;
      padding-top: 4px;
      padding-bottom: 4px;
      position: absolute;
      bottom: 0;
    }
    
    .minimize-element:hover {
      cursor: pointer;
    }
    
    .minimize-element > span {
      background-color: red;
      width: 35px;
      height: 6px;
      border-radius: 7px;
    }
    
    .MainBody {
      margin-top: 55px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.development.js"></script>
    <div id="root"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search