Home > Software design >  How to dynamically change position: property in CSS (or JavaScript) when content is near other conte
How to dynamically change position: property in CSS (or JavaScript) when content is near other conte

Time:07-12

OK, so I have some list items on the page inside a ul, and I have a footer sticky-positioned in CSS.

When the list items reach near the bottom of the page, the footer becomes overlapped with the list items. This is expected but not wanted. What I want is for the footer to become position: relative with no top and left property values set so that the list items keep growing and the footer keeps being pushed further down the page.

See the attached image: enter image description here

How can I achieve this?

<section>
  <ul>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
  </ul>
</section>
<footer>
  <p>Hello.</p>
</footer>

footer {
  position: sticky;
  bottom: 0;
}

I'd prefer to do this without JavaScript, but if I must resort to this...

CodePudding user response:

You approach this issue way too complicated. Forget the position and think about how you can push an element to the bottom inside a container with a min-height: 100vh

Simply use min-height: 100vh on the body (don't forget to reset the default margin). That way the body as the wrapping element will always at least fill out the viewport's height, even if there is not enough content.

Then you take advantage of Flexbox while you use flex-direction: column to maintain the default block level behavior.

inside Flexbox you can use margin: auto to consume all available space. If you apply margin-top: auto to the footer, you will push it to the very bottom if there is not enough content to fill the viewport:

//script only for visualization purpose
var btn = document.querySelector('button'),
    ul = document.querySelector('ul');

btn.addEventListener('click', function() {
  ul.insertAdjacentHTML('beforeend', '<li>Test</li>');
})
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

footer {
  margin-top: auto;
}
<section>
  <button>Add another List-Item</button>
  <ul>
    <li>Test</li>
    <li>Test</li>
  </ul>
</section>
<footer>
  <p>Hello.</p>
</footer>

CodePudding user response:

I would use the flex-grow rule. See https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow

The element will expand as much as it can to fill the viewport. However, it needs to be in a flex container, means that the parent element must be in display: flex. I added a flex-direction to keep the layout as needed.

html, body {
  height: 100%;
}
body {
  display: flex;
  flex-direction: column;
}
header {
  border: 2px solid khaki;
}
section {
  flex-grow: 1;
}
footer {
  border: 2px solid paleturquoise;
}
<body>
<header>
  <p>Header</p>
</header>
<section>
  <ul>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
    <li>Test</li>
  </ul>
</section>
<footer>
  <p>Footer</p>
</footer>
</body>

  • Related