仅当标题到达特定列时才如何修复列(使用CSS网格)? [英] How to fix a column (with css grid) only when the header hits a specific column?
问题描述
从视觉上看,它看起来像这样:
headerheaderheader
mainmainmainmain
col1col1col col2
我想在这里实现两件事:
- 必须
col2
在向下滚动时固定在屏幕上。 - 仅在标题时保持
col2
固定击中列。这是固定的标头。
我尝试了添加固定/粘性的位置,但在这种情况下似乎不起作用。该列将消失。我的React组件的结构是这样的:
< Header />
<中间件/>
//下面是中间件
< main>
< form className =" booking-form"< / form>
<选择/>
< / main>
//位于选择项内部
< div className = selection>< / div>
< BookingDetail />
//最后,在BookingDetail
内
这是我的html呈现时的样子:
< header>这是固定的标头< / header>。
< main class = form-container>
< form class = booking-form>水平地占据100%< / form>
< div class = selection>在水平< / div>下,水平占据大约80%。
< div class = booking-detail>在水平方向上约占20%< / div>
< / main>
最后,css
。表格容器{
display:grid;
grid-template-columns:repeat(24,1fr);
}
.booking-form {
grid-column:3 / span 20; //占据整行,请参见
上方的 main}
.selection {//左列(col1)
grid-column:3 / span 15;
}
.booking-detail {//右列(col2),当标题被击中时,我需要对其进行修复。
显示:块; //显示处于阻塞状态,因为在较小的断点处显示为:none;’
grid-column:19 / -2;
}
编辑:
Kenan的答案非常有用,除了我一直在尝试的一个小错误修理。由于滚动代码,选择列中的内容(某些具有内部内容的div)的大小意外地调整了大小,我无法解决该问题。这些是其内部内容(其中有很多)
< div className = business-and-timegrid-wrapper; key = {index}>
< Estabelecimento
logoURL = {item.logoURL}
名称= {item.name}
等级= {item.rating}
地址= {item.address }
/>
{item&& < TimeGridSelection item = {item} date = {dateForRenderingTimeGrid} />}
< / div>
------------------------------------
.business-and-timegrid -wrapper {
padding:1em;
底边保证金:-3vh;
background-color:#fff;
显示:网格;
grid-template-columns:repeat(2,50%);
边框:1px #ECECEC实体;
框阴影:0px 3px 6px#00000029;
不透明度:1;
}
更新
我不知道您对React有多少了解,但是会以您确实影响React应用程序的方式编写JS吗?
好吧,以我的方式编写JS仍然可以在React中正常工作。但是由于您正在使用React,它将所有内容放入div元素(所谓的 root
)中,因此在某些情况下它可能不适用于header元素...
我创建了一个简单的React应用程序,并将所有内容(我最初发布的内容)放在了其中,并进行了相应的调整。不幸的是,我对React并不了解很多,但是基本上它应该使您了解如何使用React来实现。
- 演示: https://react-sticky-stackoverflow-63876698.stackblitz.io
- 源代码: https:// stackblitz .com / edit / react-sticky-stackoverflow-63876698?file = BookingDetail.js
原始答案
如果我对您的理解是正确的,那么仅凭CSS就无法实现这一目标(希望其他人可以证明我错了);因此,您需要在这里从JavaScript中获得一些帮助。
顺便说一句,通常不会用 header将 main包装起来。 (请参见 HTML< main>标记)。
尝试一下(请注意,在此示例中,我使用了简单的JavaScript,但是可以根据您选择的框架进行调整):
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);
函数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(固定);
}
} else {
bookingDetailContentElem.classList.remove( fixed);
}
}
window.addEventListener( scroll,checkBookingDetailContent);
window.addEventListener( resize,checkBookingDetailContent);
checkBookingDetailContent();
}
* {
框-sizing:边框框;
颜色:#fff;
填充:0;
保证金:0;
}
html,正文{
display:block;
宽度:100%;
背景:黑色;
身高:200%;
}
#page-header {
背景:蓝色;
高度:100像素;
头寸:粘性;
top:0;
z-index:2;
}
.form-container {
display:flex;
flex-direction:列;
头寸:粘性;
}
.form-container .booking-form {
背景:红色;
高度:250像素;
}
.form-container .col-wp {
height:500px;
溢出:隐藏;
}
.form-container .col-wp .selection {
背景:绿色;
浮动:左;
宽度:80%;
身高:100%;
}
.form-container .col-wp .booking-detail {
width:20%;
身高:100%;
float:正确;
}
#booking-detail-content {
背景:橙色;
z-index:1;
}
#booking-detail-content.fixed {
位置:固定;
top:100像素;
}
< html>
< body>
< header id = page-header>
这是我的标头
< / header>
< main class = form-container>
< form class = booking-form>水平地占据100%< / form>
< div class = col-wp>
< div class = selection>沿水平方向占据约80%< / div>
< div class = booking-detail>
< div id = booking-detail-content>
水平占据约20%的空间
< / div>
< / div>
< / div>
< / main>
< / body>
< / html>
Visually, it looks somewhat like this:
headerheaderheader
mainmainmainmain
col1col1col col2
I am trying to achieve two things here:
- have
col2
be fixed on the screen when scrolling down. - 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;
}
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.
- Demo: https://react-sticky-stackoverflow-63876698.stackblitz.io
- Source code: https://stackblitz.com/edit/react-sticky-stackoverflow-63876698?file=BookingDetail.js
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>
这篇关于仅当标题到达特定列时才如何修复列(使用CSS网格)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!