纯CSS实现动态九宫格效果
分享一个实用的css技巧:用纯CSS实现动态九宫格效果。九个元素排列成3×3的网格,当鼠标悬停在某个元素上时,该元素会放大,其他元素自动缩小,保持整个容器大小不变。
这种效果很适合用在图片展示、产品陈列等场景,能够突出当前查看的内容,给用户更好的浏览体验。
核心原理
实现这个效果主要依赖几个CSS特性:
CSS Grid 布局:创建九宫格基础结构
CSS自定义属性:动态控制行列尺寸
:has() 伪类:检测子元素的悬停状态
transition:添加平滑的动画过渡
具体实现步骤
html结构
HTML部分很简单,就是一个容器包含九个项目:
<div class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
<div class="grid-item">9</div>
</div>CSS样式
下面是完整的CSS代码:
.grid-container {
/* 容器尺寸 */
width: 300px;
height: 300px;
/* Grid布局 */
display: grid;
/* 定义行高变量 */
--row-1: 1fr;
--row-2: 1fr;
--row-3: 1fr;
/* 应用行高变量 */
grid-template-rows: var(--row-1) var(--row-2) var(--row-3);
/* 定义列宽变量 */
--col-1: 1fr;
--col-2: 1fr;
--col-3: 1fr;
/* 应用列宽变量 */
grid-template-columns: var(--col-1) var(--col-2) var(--col-3);
/* 网格间距 */
gap: 5px;
/* 背景色 */
background-color: #f0f0f0;
/* 过渡动画 */
transition: all 0.3s ease;
}
/* 网格项基础样式 */
.grid-item {
display: flex;
align-items: center;
justify-content: center;
background-color: #4CAF50;
color: white;
cursor: pointer;
border-radius: 4px;
}
/* 交替背景色便于区分 */
.grid-item:nth-child(even) {
background-color: #2196F3;
}
/* 使用:has()伪类实现悬停效果 */
.grid-container:has(.grid-item:nth-child(1):hover) {
--row-1: 2fr;
--col-1: 2fr;
}
.grid-container:has(.grid-item:nth-child(2):hover) {
--row-1: 2fr;
--col-2: 2fr;
}
.grid-container:has(.grid-item:nth-child(3):hover) {
--row-1: 2fr;
--col-3: 2fr;
}
.grid-container:has(.grid-item:nth-child(4):hover) {
--row-2: 2fr;
--col-1: 2fr;
}
.grid-container:has(.grid-item:nth-child(5):hover) {
--row-2: 2fr;
--col-2: 2fr;
}
.grid-container:has(.grid-item:nth-child(6):hover) {
--row-2: 2fr;
--col-3: 2fr;
}
.grid-container:has(.grid-item:nth-child(7):hover) {
--row-3: 2fr;
--col-1: 2fr;
}
.grid-container:has(.grid-item:nth-child(8):hover) {
--row-3: 2fr;
--col-2: 2fr;
}
.grid-container:has(.grid-item:nth-child(9):hover) {
--row-3: 2fr;
--col-3: 2fr;
}代码解析
:has() 伪类的作用
:has() 伪类是实现这个效果的关键。它允许我们根据子元素的状态来为父元素设置样式。
比如这段代码:
.grid-container:has(.grid-item:nth-child(1):hover) {
--row-1: 2fr;
--col-1: 2fr;
}意思是:当网格容器中第一个子元素被悬停时,修改容器的CSS变量,让第一行和第一列占据更多空间。
CSS变量的动态更新
我们定义了六个CSS变量来控制三行三列的尺寸:
--row-1, --row-2, --row-3 控制行高
--col-1, --col-2, --col-3 控制列宽
默认情况下,所有行列都是1fr(平均分配空间)。当某个网格项被悬停时,对应的行和列变为2fr,其他行列自动调整以保持总尺寸不变。
过渡动画
通过transition: all 0.3s ease,当CSS变量值改变时,布局变化会有一个平滑的过渡效果,让交互更加自然。
Sass 简化版:
.box {
/* 定义父元素的框 */
width: 300px;
height: 300px;
/* 使用 grid 布局 */
display: grid;
/* 声明三个自定义属性 表示布局中三行的行高 */
--row1: 1fr;
--row2: 1fr;
--row3: 1fr;
/* 使用三个自定义属性 设置对应的行高 */
grid-template-rows: var(--row1) var(--row2) var(--row3);
/* 声明三个自定义属性 表示布局中三列的列宽 */
--col1: 1fr;
--col2: 1fr;
--col3: 1fr;
/* 使用三个自定义属性 设置对应的列宽 */
grid-template-columns: var(--col1) var(--col2) var(--col3);
/* 设置间距 */
grid-gap: 5px;
background: #f1f1f1;
/* 设置过渡动画效果 */
transition: all 0.25s linear;
}
/* 设置每个单元格的样式 */
.item {
display: flex;
align-items: center;
justify-content: center;
background: #42d392;
color: #fff;
cursor: pointer;
}
/* 设置不同的背景颜色 以作区分 */
.item:nth-child(2n) {
background-color: #1677ff;
}
/* 使用 Sass 提供的 循环语法 */
@for $i from 1 through 9 {
/* 使用 :has() 伪类选择器 结合 nth-child() 和 :hover 设置9个选择器 */
/* 实现当特定的子元素触发hover时 修改父元素中的样式 */
.box:has(.item:nth-child(#{$i}):hover) {
/* 计算当前hover的子元素 所在的行 */
$rowIndex: floor(calc(($i - 1) / 3) + 1);
/* 计算当前hover的子元素 坐在的列 */
$colIndex: ($i - 1) % 3 + 1;
/* 修改对应的自定义属性 从而修改对应的行高和列宽 */
/* 再加上父元素设置的过渡属性 形成了动态九宫格效果 */
--row#{$rowIndex}: 2fr;
--col#{$colIndex}: 2fr;
}
}浏览器兼容性说明
:has() 伪类是一个相对较新的CSS特性,目前主要在现代浏览器中得到支持:
Chrome 105+ ✅
Safari 15.4+ ✅
Firefox 121+ ✅
Edge 105+ ✅
如果需要兼容旧版浏览器,可以考虑使用JavaScript来实现类似效果。
实际应用建议
这个九宫格效果可以应用在很多场景:
你可以根据实际需求调整网格项的样式,比如替换数字为图片、图标或其他内容。
扩展思路
掌握了这个基础效果后,你还可以尝试:
调整放大的比例(不只是2fr)
添加缩放或旋转变换
结合模糊效果突出当前项
实现点击锁定放大的功能
这个纯CSS方案展示了现代CSS的强大能力,不需要JavaScript就能实现复杂的交互效果。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!