1

I am creating a table with sticky columns using css position: sticky. I want to style the columns differently when they are "stuck". My first project involves styling the first column or .wdtscroll td:nth-child(1) when the second column partially slides over it. Here is the javascript

const stickyElm = document.querySelector('.wdtscroll td')

const observer = new IntersectionObserver( 
  ([e]) => e.target.classList.toggle('isSticky', e.intersectionRatio < 1),
  {threshold: [1]}
);

observer.observe(stickyElm)

Here is the jsfiddle: https://jsfiddle.net/g421kjcx/

While it is certainly not perfect, I have accomplished this by setting its left position at -1px so as soon as you start scrolling the table horizontally, it is styled. As you can see this is working but only for the top cell.

When I use this code on my website, it does not work and I get a warning stating: "TypeError: Argument 1 of IntersectionObserver.observe is not an object."

When I looked it up, it seems Object.observe is obsolete.

How would I go about using this javascript without using Object.observe, and how can I target all td's in the first column.

Bonus question: How would I style the second column or .wdtscroll td:nth-child(2) when it is stuck, even though it will never scroll past the viewport.

Thank you!

noobdev
  • 11
  • 2

1 Answers1

1

Here is the jsfiddle: https://jsfiddle.net/g421kjcx/

Here is my response to your fiddle: https://jsfiddle.net/5nfb2qdy/4/

I answered a range of questions you put in this post:

As you can see this is working but only for the top cell. ...how can I "target" all td's in the first column.

1) the target of the observer is a single element (in this case). This means you can't rely on it for styling multiple elements. Instead, do it this way:

([e]) => {
    let all_td = document.querySelectorAll('.wdtscroll td:first-child')
    all_td.forEach(entry =>
        entry.classList.toggle('isSticky', e.intersectionRatio < 1)
    )
}

When I use this code on my website, it does not work and I get a warning stating: "TypeError: Argument 1 of IntersectionObserver.observe is not an object."

2) This is most likely because the JavaScript is running BEFORE the elements referred to even exist on the page. If this block of code is in the <head></head> part of the page, only a slight revision is needed to make it work:

window.onload = function(){
    observer.observe(stickyElm)
}

By wrapping the observer activation in the onload, it won't run before the page finishes rendering. The other option is to move all of this JavaScript to the end of the page just before your </body></html>

Bonus question: How would I style the second column or .wdtscroll td:nth-child(2) when it is stuck, even though it will never scroll past the viewport.

3) Maybe like this?

([e]) => {
    let all_td = document.querySelectorAll('.wdtscroll td:nth-child(1)')
    let all_2nd_td = document.querySelectorAll('.wdtscroll td:nth-child(2)')
    all_td.forEach(entry =>
        entry.classList.toggle('isSticky', e.intersectionRatio < 1)
    )
    all_2nd_td.forEach(entry =>
        entry.classList.toggle('isSticky', e.intersectionRatio < 1)
    )
}

Also add this to the end of the CSS:

.wdtscroll tr td:nth-child(2).isSticky {
  background-color: pink;
}

4) Not a response to any of your questions but I noticed some problems with your CSS in general. Here are the things I changed:

CSS

/* added td to the selectors of the next 2 rules */
.wdtscroll tr:nth-child(even) td { background-color: #f2f2f2; }

.wdtscroll tr:hover td { background-color: #ddd; }


/* added tr to the selector list to override the background color set above */
.wdtscroll tr td.isSticky{
  background-color: salmon;
}

5) Lastly, a critique of the approach used to do the class assignments on the elements. You may have good reason to assign class attributes on each td of each tr. This can also be achieved more simply by assigning class attributes to the table itself with rules that apply styles to td:nth-child(1) and td:nth-child(2) with only 2 CSS rules. This would eliminate the need to loop through every row of the table in the JavaScript and leverage the feature of CSS to style bulk elements.

CSS:

.wdtscroll.isSticky tr td:nth-child(1) {
  background-color: salmon;
}
.wdtscroll.isSticky tr td:nth-child(2) {
  background-color: pink;
}

JavaScript:

// get the sticky element
const stickyElm = document.querySelector('.wdtscroll td')
const tableElm = document.querySelector('.wdtscroll')

const observer = new IntersectionObserver( 
    ([e]) => {
        tableElm.classList.toggle('isSticky', e.intersectionRatio < 1)
    },
  {threshold: [1]}
);

window.onload = function(){
    observer.observe(stickyElm)
}

How's that for a nice, neat, and tidy solution? :) Final fiddle: https://jsfiddle.net/5nfb2qdy/5/