使用 SASS 与 CSS Grid 实现鼠标悬停动态布局变换效果

最终效果概述

  1. 页面为 3x3 的彩色格子网格;
  2. 当鼠标悬停任意格子,所在的行和列被放大;
  3. 使用纯 CSS 实现,无需 JavaScript;
  4. 利用 SASS 的模块能力大幅减少冗余代码。

HTML 结构

我们使用非常基础的结构,9 个 .item 放在 .container 容器中:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./index.css">
</head>
<body>
    <div class="container">
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
    </div>
</body>
</html>

SASS + CSS Grid 样式详解

1. 设置基本布局

css 复制代码
body {
  background-color: #23262d;
}

.container {
  width: 480px;
  height: 400px;
  margin: 50px auto;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  gap: 10px;
  transition: 0.5s;
}

我们为 .container 设置了一个固定尺寸的 3x3 网格 ,并加了 transition 来实现动画过渡。

2. 为每个格子设置不同颜色

css 复制代码
@for $i from 1 through 9 {
  .item:nth-child(#{$i}) {
    background: hsl($i * 40deg, 100%, 60%);
  }
}

利用 HSL 色彩空间,我们为每个格子设置了不同色相,让它们具有渐变的彩虹效果。

3. 交互式动态布局(核心逻辑)

css 复制代码
@use "sass:list";
@use "sass:math";

@for $i from 1 through 9 {
  .container:has(.item:nth-child(#{$i}):hover) {
    $r: math.floor(math.div($i - 1, 3) + 1);
    $c: ($i - 1) % 3 + 1;
    $arr: 1fr 1fr 1fr;
    $rows: list.set-nth($arr, $r, 2fr);
    $cols: list.set-nth($arr, $c, 2fr);
    grid-template-columns: $cols;
    grid-template-rows: $rows;
  }
}

解释一下这段代码的巧妙之处:

  • @for 循环处理每一个 .item;
  • 通过 SASS 的数学模块计算出第几个格子对应的行(r)和列(c);
  • 使用 list.set-nth() 将第 r 行和第 c 列的比例设为 2fr,其他保持 1fr
  • 利用 :has() 选择器监听每个格子的 hover 状态,进而修改 .container 的布局。

完整代码

index.scss

css 复制代码
@use "sass:list";
@use "sass:math";

body {
  background-color: #23262d;
}

.container {
  width: 480px;
  height: 400px;
  margin: 0 auto;
  margin-top: 50px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  gap: 10px;
  transition: 0.5s;
}


@for $i from 1 through 9 {
  .item:nth-child(#{$i}) {
    background: hsl($i * 40deg, 100%, 60%);
  }

  // 选择子元素,更改父元素:当容器的子元素被鼠标移入时,父元素样式生效
  .container:has(.item:nth-child(#{$i}):hover) {
    // 移入某个子元素时,改变父元素的行列比例
    $r: math.floor(math.div($i - 1, 3) + 1);
    $c: ($i - 1) % 3 + 1;
    $arr: 1fr 1fr 1fr;
    $rows: list.set-nth($arr, $r, 2fr); // 将第 $c 行的宽度改为 2fr
    $cols: list.set-nth($arr, $c, 2fr); // 将第 $c 列的宽度改为 2fr
    grid-template-columns: $cols;
    grid-template-rows: $rows;
  }
}

总结

技术点 说明
CSS Grid 实现基本的行列布局和比例控制
SASS 循环 + 模块 自动生成 9 套不同的布局规则
:has() 选择器 CSS4 的新特性,实现"父级根据子级状态变化"
transition 平滑过渡布局变化

浏览器兼容性提示

:has() 是一个 CSS4 选择器 ,目前主流浏览器如 Chrome、Edge 和 Safari 已支持,但 Firefox 仍不支持(截至 2025 年)。部署到生产环境前,请根据用户群体权衡。

相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95271 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大1 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师1 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学1 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端