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

如何实现两种CSS Grid布局间的平滑过渡效果?

如何实现Grid布局中元素跨列/行的平滑过渡

我能通过切换元素类实现两种Grid布局:普通类占1列1行,聚焦类占2列2行,但添加transition: all 1s完全无效——背景色这类属性能过渡,但Grid结构切换是瞬间完成的。想让元素在1秒内滑动到位,不是跳变。

原代码

JS

/* add/remove class to an element */
function changeClass(fromid, toclass) {
  var itemdb = document.getElementById(fromid);
  var object_class = itemdb.getAttribute("class");

  document.querySelectorAll('.item_focus').forEach(it => {
    it.classList.remove("item_focus");
    it.removeAttribute("style");
    it.classList.add("item");
    it.style.backgroundColor = "lime";
  })

  if(object_class === "item_focus") {
    itemdb.classList.add("item");
  }else {
    itemdb.removeAttribute("class");
    itemdb.classList.add(toclass);
    if(Number.isInteger(fromid/3)) {
      itemdb.style.gridColumn = "2 / span 2";
      itemdb.style.gridRow = fromid/3 + " / span 2";
    }
  }
}

CSS

.shop-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 25px;
padding: 25px 10% 25px 10%;
transition: .25s;
}

.item {
background-color: red;
grid-column: span 1;
grid-row: span 1;
width: 100%;
position:relative;
z-index: 5;
overflow: hidden;
cursor: pointer;
}

.item_focus {
background-color: red;
grid-column: span 2;
grid-row: span 2;
width: 100%;
position:relative;
z-index: 5;
overflow: hidden;
cursor: pointer;
}

HTML

<div class='shop-container'>
  <div class='item' id='1' onclick='changeClass("1", "item_focus")'>box 1</div>
  <div class='item' id='2' onclick='changeClass("2", "item_focus")'>box 2</div>
  <div class='item' id='3' onclick='changeClass("3", "item_focus")'>box 3</div>
  <div class='item' id='4' onclick='changeClass("4", "item_focus")'>box 4</div>
  <div class='item' id='5' onclick='changeClass("5", "item_focus")'>box 5</div>
  <div class='item' id='6' onclick='changeClass("6", "item_focus")'>box 6</div>
</div>

解决方案

核心逻辑

grid-column/grid-row属于离散的轨道定位属性,浏览器无法计算中间过渡状态,所以直接加transition没用。我们可以通过让容器自动填充空隙+给元素尺寸/层级加过渡来模拟平滑效果。

修改后的实现代码

HTML(无需改动)

<div class='shop-container'>
  <div class='item' id='1' onclick='changeClass("1", "item_focus")'>box 1</div>
  <div class='item' id='2' onclick='changeClass("2", "item_focus")'>box 2</div>
  <div class='item' id='3' onclick='changeClass("3", "item_focus")'>box 3</div>
  <div class='item' id='4' onclick='changeClass("4", "item_focus")'>box 4</div>
  <div class='item' id='5' onclick='changeClass("5", "item_focus")'>box 5</div>
  <div class='item' id='6' onclick='changeClass("6", "item_focus")'>box 6</div>
</div>

CSS(关键修改)

.shop-container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 25px;
  padding: 25px 10% 25px 10%;
  transition: all 0.5s ease;
  grid-auto-flow: dense; /* 让后面元素自动填充空隙,避免布局跳变 */
}

.item {
  background-color: red;
  grid-column: span 1;
  grid-row: span 1;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 给所有可过渡的属性加动画 */
  transition: all 1s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  z-index: 1;
  overflow: hidden;
  cursor: pointer;
}

.item_focus {
  grid-column: span 2;
  grid-row: span 2;
  z-index: 10; /* 聚焦元素置顶,避免被其他元素遮挡 */
  transition: all 1s cubic-bezier(0.4, 0, 0.2, 1);
}

JS(简化逻辑)

function changeClass(fromid, toclass) {
  const targetItem = document.getElementById(fromid);
  const isFocused = targetItem.classList.contains('item_focus');

  // 重置所有已聚焦的元素
  document.querySelectorAll('.item_focus').forEach(item => {
    item.classList.remove('item_focus');
    item.classList.add('item');
  });

  if (!isFocused) {
    targetItem.classList.add(toclass);
    // 保留第3、6个元素的特殊位置处理
    if (Number.isInteger(parseInt(fromid)/3)) {
      targetItem.style.gridColumn = "2 / span 2";
      targetItem.style.gridRow = `${parseInt(fromid)/3} / span 2`;
    }
  }
}

效果说明

  • 利用grid-auto-flow: dense让布局重排时自动填充空隙,避免元素突然跳动
  • 给.item的尺寸、层级等可计算属性加过渡,浏览器能生成中间动画帧,实现滑动效果
  • 用cubic-bezier曲线调整过渡节奏,比线性过渡更自然

内容的提问来源于stack exchange,提问作者Fred Fredrik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 14:52:32