CSS липкие карты с использованием сетки

Я хочу иметь макет липких карточек с использованием сетки. Вот чего мне удалось добиться:

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-сетки? Я нашел несколько других подходов, но они включали жесткое кодирование определенных высот для некоторых элементов, и я бы хотел этого избежать.

Можете ли вы добавить его в фрагмент кода? Я просто устал копировать и вставлять....

ProgramistaZaDyche 07.07.2024 18:01
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
1
1
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По словам Мозиллы:

Липко позиционированный элемент — это элемент, вычисленное значение позиции которого является липким. Он считается относительно позиционированным до тех пор, пока содержащий его блок не пересечет указанный порог (например, если для параметра 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>

Подстраивайте под свои нужды :)

Другие вопросы по теме