1

Visually, it looks somewhat like this:

headerheaderheader
 mainmainmainmain
 col1col1col col2

I am trying to achieve two things here:

  1. have col2 be fixed on the screen when scrolling down.
  2. only keep col2 fixed when the header hits the columns. It's a fixed header.

I've tried adding position fixed/sticky but that doesn't seem to work in this case. That column simply disappears. My React components are structured this way:

<Header />
<Middleware />

//below is inside of Middleware
<main>
  <form className="booking-form"></form>
  <Selection/>
</main>

//below is inside of Selection
<div className="selection"></div>
<BookingDetail/>

//finally, inside of BookingDetail
<div className="booking-detail"></div>

This is what my html looks like when rendered:

<header> This is the fixed header </header>
<main class="form-container">
  <form class="booking-form"> takes up 100% horizontally </form> 
  <div class="selection"> takes up about 80% horizontally, below form </div>
  <div class="booking-detail"> takes up about 20% horizontally </div>
</main>

Finally, the css

.form-container {
   display: grid;
   grid-template-columns: repeat(24, 1fr);
}
.booking-form {
   grid-column: 3 / span 20;   // takes up entirety of row, see 'main' above
}
.selection {                  //left column (col1)
   grid-column: 3 / span 15;
}
.booking-detail {             //right column (col2), which I need fixed when the header hits.
   display: block;             //display is block as at a smaller break point it's 'display: none;'
   grid-column: 19 / -2;
}

EDIT: Kenan's answer works great except for a little bug I've been trying to fix. The contents inside of the 'selection' col (some divs with internal content) are unexpectedly resizing because of the scroll code and I cannot figure out how to fix it. These are its internal content (there are many of these)

<div className="business-and-timegrid-wrapper" key={index}>
   <Estabelecimento
      logoURL={item.logoURL}
      name={item.name}
      rating={item.rating}
      address={item.address}
    />
    {item && <TimeGridSelection item={item} date={dateForRenderingTimeGrid} />}
      </div>
------------------------------------
.business-and-timegrid-wrapper {
   padding: 1em;
   margin-bottom: -3vh;
   background-color: #fff;
   display: grid;
   grid-template-columns: repeat(2, 50%);
   border: 1px #ECECEC solid;
   box-shadow: 0px 3px 6px #00000029;
   opacity: 1;
}
uber
  • 4,163
  • 5
  • 26
  • 55

2 Answers2

1

Update

I don't know how much you know about React, but would writing JS the way you did affect my React app?

Well, writing JS the way I did would still work in React without any problems. But since you are using React, it puts everything inside a div element (the so-called root), so in some cases it might not work for the header element...

I created a simple React application and have put everything - I originally posted - there and adapted it accordingly. Unfortunately I don't have much knowledge about React, but basically it should give you an idea of how you can achieve this with React.


Original answer

If I understood you correctly, you can't achieve this with CSS alone (hopefully someone else can prove me wrong); so you need a little help from JavaScript here.

By the way, it is not usual to wrap the 'main' by a 'header'. (see HTML <main> Tag).

Try this one (Note that I used simple JavaScript in this example, but you can adjust it according to the framework of your choice):

JSFiddle: https://jsfiddle.net/od9jf4m7/

window.onload = function() {
    var pageHeaderElem = document.getElementById("page-header");
    var bookingDetailElem = document.getElementsByClassName("booking-detail")[0];
    var bookingDetailContentElem = document.getElementById("booking-detail-content");

    function checkBookingDetailContent() {
        bookingDetailContentElem.style.width = bookingDetailContentElem.parentElement.offsetWidth + 'px';
        bookingDetailContentElem.style.height = bookingDetailContentElem.parentElement.offsetHeight + 'px';
        if(bookingDetailElem.getBoundingClientRect().top < pageHeaderElem.offsetHeight) {
            if(!bookingDetailContentElem.classList.contains("fixed")) {
                bookingDetailContentElem.classList.add("fixed");
            }
        } else {
            bookingDetailContentElem.classList.remove("fixed");
        }
    }
    window.addEventListener("scroll", checkBookingDetailContent);
    window.addEventListener("resize", checkBookingDetailContent);
    checkBookingDetailContent();
}
* {
    box-sizing: border-box;
    color: #fff;
    padding: 0;
    margin: 0;
}

html, body {
    display: block;
    width: 100%;
    background: black;
    height: 200%;
}

#page-header {
    background: blue;
    height: 100px;
    position: sticky;
    top: 0;
    z-index: 2;
}

.form-container {
    display: flex;
    flex-direction: column;
    position: sticky;
}

.form-container .booking-form {
    background: red;
    height: 250px;
}

.form-container .col-wp {
    height: 500px;
    overflow: hidden;
}

.form-container .col-wp .selection {
    background: green;
    float: left;
    width: 80%;
    height: 100%;
}

.form-container .col-wp .booking-detail {
    width: 20%;
    height: 100%;
    float: right;
}

#booking-detail-content {
    background: orange;
    z-index: 1;
}

#booking-detail-content.fixed {
    position: fixed;
    top: 100px;
}
<html>
    <body>
    <header id="page-header">
        This is my header
    </header>
    <main class="form-container">
        <form class="booking-form">takes up 100% horizontally</form>
        <div class="col-wp">
            <div class="selection">takes up about 80% horizontally</div>
            <div class="booking-detail">
                <div id="booking-detail-content">
                    takes up about 20% horizontally
                </div>
            </div>
        </div>
    </main>
    </body>
</html>
Kenan Güler
  • 1,868
  • 5
  • 16
  • thank you for pointing out the issue with the header tag. It was actually a mistake I made while writing it here. I don't know how much you know about React, but would writing JS the way you did affect my React app? – uber Sep 14 '20 at 13:05
  • @kiabbott Okay, I see. I just created a small React app (see the link in the answer). I didn't want to include the source code here, since it would be too much. But basically not much has changed from my original answer. Have a look at it. Feel free to ask, if you have any questions. – Kenan Güler Sep 14 '20 at 15:56
  • this was beautiful! Thanks. Do you have any resources in mind when it comes to learning more about these kinds of problems? – uber Sep 15 '20 at 20:21
  • 1
    @kiabbott These kinds of problems are mostly related to CSS. But as you can see, there are also cases, where CSS alone is unfortunately not sufficient to solve the problem. Regarding your question: if you have a sound knowledge of CSS and JavaScript, such problems should be easy to handle. These two resources for example always accompany me: [CSS-Tricks](https://css-tricks.com/), [W3Schools](https://www.w3schools.com/) - Last but not least: Practice makes perfect. – Kenan Güler Sep 16 '20 at 20:20
  • I'm sorry I'm gonna have to be a bother; I haven't figured out an issue with this in the past 2 days. The green col (as per your coloration) is undergoing some internal resizing and I can't figure out why. It's the many divs I have inside of it that somehow are being affected by the scroll code. I edited the question to reflect this. – uber Sep 18 '20 at 14:34
  • @kiabbott My code was only an example and not really optimized for performance or stability in general. Could you please upload a running but delimited version of your app somewhere (e.g. stackblitz) where the bug you describe can be reproduced? I would then do my best to solve the problem and also try to optimize the performance. Cheers. – Kenan Güler Sep 19 '20 at 16:35
  • @kiabbott Glad you solved it! Nonetheless, I continued to work on my last solution, since I didn't like it very much. :D Check my other answer. The code is cleaner and runs much more smoothly this time. If you have any further questions, feel free to drop me a comment here. Cheers. – Kenan Güler Sep 20 '20 at 01:01
1

The green col (as per your coloration) is undergoing some internal resizing and I can't figure out why. It's the many divs I have inside of it that somehow are being affected by the scroll code. I edited the question to reflect this.

Well, I apologize for not taking into account that although you originally used CSS grid layout, I used flex layout in my solution instead. So, this time I have exclusively used the grid layout. Since my previous answer was accepted, I didn't want to touch it anymore, hence this second answer here.

Check this out:

References:

Kenan Güler
  • 1,868
  • 5
  • 16