admin管理员组

文章数量:1355658

I've been loving position: sticky. It solves most, if not all, of the issues without resorting to JavaScript. But, I've hit a wall. I need to make an element that is nested inside a couple of <div> to be sticky. We know that position: sticky works as a blend of position: relative and position: fixed, therefore it will anchor to its first parent.

From MDN:

The element is positioned according to the normal flow of the document, and then offset relative to its nearest scrolling ancestor and containing block (nearest block-level ancestor)

In this case, I want to make a header sticky relative to the window and not the container. The HTML makes it difficult for me to restructure it outside nested <div>

Is this possible without JavaScript?

Here's the code:

<div class="attendance">
<!-- Here's the header I want to make sticky to the window, and not to div.attendance-->
    <header class="text-center sticky">Monday 11/22/2019</header>
<!-- Header above -->
    <div class="date-config">
        <div class="form-group">
            <input type="checkbox" id="workable" /> No Work<br />
        </div>

        <div class="form-group">
            <label for="notes">Notes:</label>
            <textarea id="notes" class="form-control"></textarea>
        </div>
        <label for="markall">Mark all as>
        <select id="markall" class="form-control">
            <option></option>
            <option>Absent</option>
            <option>Present</option>
        </select>
    </div>

    <div class="student-attendance">
      Hello :)   
    </div>

</div>

Any ideas?

P.S: I've found this, but it uses JavaScript.

Edit: Here's an awful, but working example (Beware! It's in Spanish - Look for the dates! They won't stick to the window!).

I've been loving position: sticky. It solves most, if not all, of the issues without resorting to JavaScript. But, I've hit a wall. I need to make an element that is nested inside a couple of <div> to be sticky. We know that position: sticky works as a blend of position: relative and position: fixed, therefore it will anchor to its first parent.

From MDN:

The element is positioned according to the normal flow of the document, and then offset relative to its nearest scrolling ancestor and containing block (nearest block-level ancestor)

In this case, I want to make a header sticky relative to the window and not the container. The HTML makes it difficult for me to restructure it outside nested <div>

Is this possible without JavaScript?

Here's the code:

<div class="attendance">
<!-- Here's the header I want to make sticky to the window, and not to div.attendance-->
    <header class="text-center sticky">Monday 11/22/2019</header>
<!-- Header above -->
    <div class="date-config">
        <div class="form-group">
            <input type="checkbox" id="workable" /> No Work<br />
        </div>

        <div class="form-group">
            <label for="notes">Notes:</label>
            <textarea id="notes" class="form-control"></textarea>
        </div>
        <label for="markall">Mark all as>
        <select id="markall" class="form-control">
            <option></option>
            <option>Absent</option>
            <option>Present</option>
        </select>
    </div>

    <div class="student-attendance">
      Hello :)   
    </div>

</div>

Any ideas?

P.S: I've found this, but it uses JavaScript.

Edit: Here's an awful, but working example (Beware! It's in Spanish - Look for the dates! They won't stick to the window!).

Share Improve this question edited Nov 30, 2018 at 3:37 Jose A asked Nov 30, 2018 at 2:59 Jose AJose A 11.2k12 gold badges85 silver badges124 bronze badges 4
  • 2 can you also post your existing CSS so that we can run the code and see the current result? – yqlim Commented Nov 30, 2018 at 3:14
  • @YongQuan: Sure! It's awful (Huge, and it's going to break your PC), but I added a jsfiddle with the exact code. – Jose A Commented Nov 30, 2018 at 3:38
  • position: sticky is not supported in IE11. So be aware of that. Ideal approach would be to use position: fixed and let other element flow with defined margin-top. – Dinesh Pandiyan Commented Nov 30, 2018 at 3:38
  • @DineshPandiyan: Thanks ;) This is more of an enhanced feature, so it's ok if it doesn't work with older browsers. – Jose A Commented Nov 30, 2018 at 3:40
Add a ment  | 

2 Answers 2

Reset to default 3

Ok! First I'd like to apologize as this question wasn't possible to be answered without rendering the HTML. Fortunately, I have found the solution.

TL;DR In this case, no, you need JavaScript. You will need to implement a translateY transform in the element to achieve this. I don't know if the problem is that the parent element has a transform property and it causes this bug or there's something else causing the issue.

Explanation:

I'm currently using a carousel JS library called tiny slider. I'm displaying form elements instead of images, (Building a responsive table; Had issues when I tried using CSS Grids). So far, so good. The problem started when I wanted to set sticky the date headers.

I went with the modern approach of setting position:sticky, but that didn't work. The elements would get clogged in a certain position and it wouldn't move or stick. I started researching online (which ended up asking this same question), and the HTML itself. I did find that there were many parent <div>s that were created by tiny-slider. My theory was that it was getting attached to one of those parents.

Therefore, I decided to try the old tactic of bining position:fixed with a scroll event. But, that didn't work. Going back online and Google-Fuing a bit, there seems to be an old bug [1] [2] [3] that whenever a translate is applied to one of the parents an out-of-root container is created and position:fixed doesn't work as expected.

I have a hunch that this may be one of the reasons why sticky didn't work, but according to this answer, it doesn't seem like it.

I kept thinking for a while, and resorted to use a transform CSS property with translateY. I made a small experiment in the browser, and it worked!

Hence, I ended up implementing the scroll eventListener and listening to the header's parent's position, and applying getBoundingClientRect() to get the offset. If I had applied it to the element itself, it would have given me the translated position which I applied through CSS.

I was skeptical that this could be a performance bottleneck for mobile browsers. Therefore, I checked that the transform function was called inside a requestAnimationFrame and it had applied a will-change property in the CSS stylesheet.

I ran the code with a 4x CPU Slowdown in Google Chrome, and had good results

本文标签: htmlHow can I make an element sticky relative to the window without JavaScript (If Possible)Stack Overflow