You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:为Grid Item展开及重排添加平滑过渡动画

给Grid元素重排加平滑过渡的解决办法

你原代码里的过渡没生效,核心原因是CSS Grid的grid-column是离散属性,浏览器没法在不同的网格跨度之间做平滑过渡,写transition: grid-column根本没用。下面给你两种可行的实现方案:

方案一:用内部容器过渡+动态改Grid列(推荐,效果自然)

思路:给每个Grid元素套个内部容器,点击时先让Grid临时变成1列(触发过渡),再让目标元素的内部容器占满整行,视觉上就有平滑展开的效果,同时其他元素会自动填充位置。

修改后的代码

HTML(加了内部容器)

<div class="grid-container">
    <div class="grid-item">
        <div class="item-content">Div 1</div>
    </div>
    <div class="grid-item">
        <div class="item-content">Div 2</div>
    </div>
    <div class="grid-item">
        <div class="item-content">Div 3</div>
    </div>
    <div class="grid-item">
        <div class="item-content">Div 4</div>
    </div>
    <div class="grid-item">
        <div class="item-content">Div 5</div>
    </div>
    <div class="grid-item">
        <div class="item-content">Div 6</div>
    </div>
    <div class="grid-item">
        <div class="item-content">Div 7</div>
    </div>
</div>

CSS

.grid-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    padding: 10px;
    grid-auto-flow: dense; /* 自动填充空缺 */
    transition: grid-template-columns 0.3s ease; /* Grid列变化的过渡 */
}

.grid-item {
    background: transparent;
    padding: 0;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}

.item-content {
    background-color: #ddd;
    padding: 20px;
    text-align: center;
    width: 100%;
    transition: all 0.3s ease;
}

/* 展开时Grid临时改成1列 */
.grid-container.expanded-mode {
    grid-template-columns: 1fr;
}

/* 展开的元素内部容器占满整行 */
.grid-item.expanded .item-content {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: 10;
}

JavaScript

const gridContainer = document.querySelector('.grid-container');
const gridItems = document.querySelectorAll('.grid-item');

gridItems.forEach(item => {
    item.addEventListener('click', () => toggleExpand(item));
});

function toggleExpand(element) {
    const isAlreadyExpanded = element.classList.contains('expanded');
    
    // 先清空所有展开状态
    gridItems.forEach(item => item.classList.remove('expanded'));
    gridContainer.classList.remove('expanded-mode');
    
    if (!isAlreadyExpanded) {
        // 先让Grid切换成1列,等过渡触发后再给元素加展开类
        gridContainer.classList.add('expanded-mode');
        setTimeout(() => element.classList.add('expanded'), 10);
    }
}

方案二:用CSS动画模拟Grid重排(不用改HTML结构)

思路:直接用CSS动画模拟元素从1列扩展到整行的宽度变化,动画结束后再应用真实的Grid布局,视觉上实现平滑过渡。

修改后的代码(保留你原HTML)

CSS

.grid-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    padding: 10px;
    grid-auto-flow: dense;
}

.grid-item {
    background-color: #ddd;
    padding: 20px;
    text-align: center;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}

/* 展开动画:从1列宽度变到整行 */
@keyframes expandItem {
    0% {
        width: calc(33.333% - 7px); /* 减去gap的平均宽度 */
    }
    100% {
        width: 100%;
    }
}

/* 收缩动画 */
@keyframes shrinkItem {
    0% {
        width: 100%;
    }
    100% {
        width: calc(33.333% - 7px);
    }
}

.grid-item.expanding {
    animation: expandItem 0.3s forwards;
    z-index: 10;
    position: absolute;
    left: 10px; /* 对应Grid的padding值 */
}

.grid-item.shrinking {
    animation: shrinkItem 0.3s forwards;
}

.grid-item.expanded {
    grid-column: 1 / -1; /* 真实占据整行 */
    position: static;
}

JavaScript

const gridItems = document.querySelectorAll('.grid-item');
let activeExpandedItem = null;

gridItems.forEach(item => {
    item.addEventListener('click', () => toggleExpand(item));
});

function toggleExpand(element) {
    // 如果点击的是已经展开的元素,就收缩它
    if (activeExpandedItem === element) {
        element.classList.add('shrinking');
        element.addEventListener('animationend', function endAnim() {
            element.classList.remove('shrinking', 'expanded');
            element.style.position = '';
            element.style.left = '';
            element.removeEventListener('animationend', endAnim);
        });
        activeExpandedItem = null;
        return;
    }

    // 先收缩之前展开的元素
    if (activeExpandedItem) {
        activeExpandedItem.classList.add('shrinking');
        activeExpandedItem.addEventListener('animationend', function endAnim() {
            activeExpandedItem.classList.remove('shrinking', 'expanded');
            activeExpandedItem.style.position = '';
            activeExpandedItem.style.left = '';
            activeExpandedItem.removeEventListener('animationend', endAnim);
        });
    }

    // 展开当前元素
    element.classList.add('expanding');
    element.addEventListener('animationend', function endAnim() {
        element.classList.remove('expanding');
        element.classList.add('expanded');
        element.style.position = '';
        element.style.left = '';
        element.removeEventListener('animationend', endAnim);
    });
    activeExpandedItem = element;
}

为啥原代码过渡没效果?

CSS Grid的grid-column是离散的布局属性,它的值是网格轨道的跨度(比如span 1、1/-1),不是连续的数值,浏览器没法在这些离散值之间做平滑的插值计算,所以你写的transition: grid-column完全不会生效。

内容的提问来源于stack exchange,提问作者Ferry Edpan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 18:58:10