Я хочу иметь макет липких карточек с использованием сетки. Вот чего мне удалось добиться:
for (const cards of document.querySelectorAll(".cards")) {
let i = 0;
for (const card of cards.children) {
if (card.classList.contains("card")) {
card.style.top = `calc(5vh + ${i} * var(--card-top-offset))`;
i += 1;
}
}
cards.style.setProperty(
"grid-template-rows",
`repeat(${i}, var(--card-h))`,
);
}
:root {
--card-top-offset: 3rem;
--card-h: 36rem;
}
.cards {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
gap: calc(var(--card-h) / 2);
align-items: baseline;
}
.card {
position: sticky;
top: 0;
height: var(--card-h);
transition: all 0.5s;
}
<div class = "cards">
<div class = "card" style = "background-color: rgb(252 165 165);">1</div>
<div class = "card" style = "background-color: rgb(147 197 253);">2</div>
<div class = "card" style = "background-color: rgb(134 239 172);">3</div>
<div class = "card" style = "background-color: rgb(253 224 71);">4</div>
<div class = "card" style = "background-color: rgb(249 168 212);">5</div>
</div>
Первые четыре карты работают нормально, однако пятая отклеивается раньше, чем я ожидал. Я думаю, это связано с тем, что родительский элемент cards
заканчивается. Есть ли способ добиться такого поведения с помощью CSS-сетки? Я нашел несколько других подходов, но они включали жесткое кодирование определенных высот для некоторых элементов, и я бы хотел этого избежать.
По словам Мозиллы:
Липко позиционированный элемент — это элемент, вычисленное значение позиции которого является липким. Он считается относительно позиционированным до тех пор, пока содержащий его блок не пересечет указанный порог (например, если для параметра top установлено значение, отличное от auto) в корне потока (или контейнере, внутри которого он прокручивается), и в этот момент он считается «застрявшим» до тех пор, пока не встретится с противоположный край содержащего его блока.
Ваша последняя карта перекрывается, когда:
встречая противоположный край содержащего его блока.
Вот как работает клей. Единственное решение — увеличить высоту контейнера, но в конце он все равно будет перекрываться из-за липкого поведения. Если вы хотите использовать позицию: липкий, решение будет таким, как показано ниже; Как видите, это все еще не то, чего вы хотите достичь (я верю :)).
document.addEventListener("DOMContentLoaded", () => {
for (const cards of document.querySelectorAll(".cards")) {
let i = 0;
for (const card of cards.children) {
if (card.classList.contains("card")) {
card.style.top = `calc(5vh + ${i} * var(--card-top-offset))`;
i += 1;
}
}
cards.style.setProperty(
"grid-template-rows",
`repeat(${i}, var(--card-h))`
);
}
});
:root {
--card-top-offset: 3rem;
--card-h: 36rem;
}
.cards {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
gap: calc(var(--card-h) / 2);
align-items: baseline;
}
.card {
position: sticky;
top: 0;
height: var(--card-h);
}
/* Add a bottom padding to the container to prevent overlap */
.cards::after {
content: '';
display: block;
height: calc(var(--card-h) + var(--card-top-offset));
}
.card:nth-child(1){
background-color: red;
}
.card:nth-child(2){
background-color: blue;
}
.card:nth-child(3){
background-color: green;
}
.card:nth-child(4){
background-color: violet;
}
.card:nth-child(5){
background-color: black;
}
<div class = "cards">
<div class = "card">1</div>
<div class = "card">2</div>
<div class = "card">3</div>
<div class = "card">4</div>
<div class = "card">5</div>
</div>
Я бы посоветовал вам не использовать фиксированную позицию и использовать другой подход:
const cards = document.querySelectorAll('.card');
const offset = 20; // Set your desired offset here
function updateCardPositions() {
const scrollTop = window.scrollY;
cards.forEach((card, index) => {
const cardOffset = parseInt(card.style.getPropertyValue('--offset-card'));
const topPosition = Math.max(0, scrollTop - cardOffset);
card.style.top = `${topPosition}px`;
});
}
window.addEventListener('scroll', updateCardPositions);
window.addEventListener('resize', updateCardPositions);
updateCardPositions(); // Initial position update
// Adjust container height to prevent cards from disappearing
const container = document.querySelector('.container');
container.style.height = `${cards.length * offset}px`;
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f0f0f0;
height:300vh;
}
.container {
max-width: 800px;
margin: 50px auto;
padding: 20px;
}
.card {
background-color: white;
border: 1px solid #ccc;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px; /* Space between cards */
position: relative;
transition: transform 0.3s ease;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
z-index: 1; /* Ensure cards stack properly */
}
.card h2 {
margin-top: 0;
}
.card p {
margin-bottom: 0;
}
<div class = "container">
<div class = "card" style = "--offset-card: 0;">
<h2>Card 1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
<div class = "card" style = "--offset-card: 80px;">
<h2>Card 2</h2>
<p>Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
<div class = "card" style = "--offset-card: 160px;">
<h2>Card 3</h2>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
<div class = "card" style = "--offset-card: 260px;">
<h2>Card 4</h2>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
</div>
<div class = "card" style = "--offset-card: 340px;">
<h2>Card 5</h2>
<p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
Подстраивайте под свои нужды :)
Можете ли вы добавить его в фрагмент кода? Я просто устал копировать и вставлять....