文章

桌面端侧边栏折叠功能说明

桌面端侧边栏折叠功能说明

功能概述

本博客现已支持桌面端手动折叠侧边栏功能,让你在需要更宽阅读区域时折叠侧边栏,需要导航时再展开。

使用方法

折叠/展开侧边栏

在桌面端(屏幕宽度 ≥ 850px),将鼠标悬停在侧边栏顶部区域时,会显示一个折叠按钮:

  • 点击按钮:折叠侧边栏,获得更大的内容区域
  • 再次点击:展开侧边栏,恢复导航功能
  • 精确触发: 只在侧边栏顶部约 120px 范围内悬停才会显示按钮
  • 默认隐藏: 按钮默认不可见,保持界面简洁

自动记忆状态

系统会自动记住你的偏好设置:

  • 折叠状态会保存到浏览器的 localStorage
  • 下次访问时会自动恢复到你上次的设置
  • 清除浏览器缓存会重置此设置

技术实现

1. 折叠按钮

在侧边栏顶部添加了折叠按钮:

1
2
3
<button id="sidebar-collapse" class="btn" aria-label="Collapse Sidebar">
  <i class="fas fa-angle-double-left"></i>
</button>

2. CSS 样式

  • 触发区域: 在侧边栏顶部设置 120px 高的隐藏触发区域
  • 精确触发: 只有鼠标悬停在顶部区域时才显示按钮
  • 默认隐藏: 按钮默认透明隐藏,保持界面简洁
  • 双重悬停: 触发区域悬停或按钮自身悬停都会显示
  • 折叠动画: 折叠时侧边栏向左滑出视野
  • 内容扩展: 主内容区域自动扩展占满全屏
  • 图标旋转: 按钮图标会旋转 180 度提示状态

3. JavaScript 逻辑

  • 监听折叠按钮点击事件
  • 切换 data-sidebar-collapsed 属性
  • 使用 localStorage 保存用户偏好
  • 页面加载时恢复上次的状态

4. 响应式设计

  • 桌面端(≥ 850px): 显示折叠按钮,支持手动折叠
  • 移动端(< 850px): 隐藏折叠按钮,保持原有的自动折叠逻辑

响应式行为

屏幕宽度侧边栏行为
≥ 850px固定显示,可手动折叠
< 850px自动隐藏,点击菜单按钮展开

兼容性

  • ✅ Chrome / Edge
  • ✅ Firefox
  • ✅ Safari
  • ✅ 移动端浏览器

注意事项

  1. 首次使用: 默认状态下侧边栏是展开的
  2. 状态保存: 状态保存在本地浏览器,不同设备/浏览器需要单独设置
  3. 清除缓存: 清除浏览器数据会重置折叠状态
  4. 移动端: 移动端不使用此功能,保持原有的响应式设计

本地测试

访问本地服务器查看效果:http://127.0.0.1:4000/

文件修改清单

  1. _includes/sidebar.html - 添加折叠按钮
  2. assets/css/jekyll-theme-chirpy.scss - 添加折叠样式
  3. _javascript/modules/components/sidebar.js - 添加折叠逻辑

详细实现步骤

如果你也想在自己的博客中添加类似功能,可以按照以下步骤操作:

步骤 1: 修改侧边栏模板

编辑 _includes/sidebar.html 文件,在侧边栏顶部添加折叠按钮和触发区域:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- The Side Bar -->

<aside aria-label="Sidebar" id="sidebar" class="d-flex flex-column align-items-end">
  <!-- Desktop collapse trigger area -->
  <div id="sidebar-collapse-trigger" title="悬停显示折叠按钮"></div>
  
  <!-- Desktop collapse button -->
  <button id="sidebar-collapse" class="btn" aria-label="Collapse Sidebar" title="折叠侧边栏">
    <i class="fas fa-angle-double-left"></i>
  </button>
  <!-- .sidebar-collapse -->

  <header class="profile-wrapper">
    <!-- ... 原有代码 ... -->
  </header>
  
  <!-- ... 其余代码 ... -->
</aside>

关键点:

  • sidebar-collapse-trigger: 隐藏的触发区域,只在侧边栏顶部,鼠标悬停时才显示按钮
  • 按钮 ID 必须为 sidebar-collapse,以便 JavaScript 能够定位
  • 使用 Font Awesome 图标 fa-angle-double-left 表示折叠
  • 添加 aria-labeltitle 提升可访问性

步骤 2: 添加 CSS 样式

编辑 assets/css/jekyll-theme-chirpy.scss 文件,在文件末尾添加以下样式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/* Desktop sidebar collapse functionality */
$sidebar-collapsed-width: 0;

// 添加一个悬停触发区域
#sidebar-collapse-trigger {
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 120px; // 只在顶部 120px 范围内触发
  z-index: 99;
  cursor: pointer;
}

// Collapse button styling
#sidebar-collapse {
  display: none;
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  padding: 0.25rem 0.5rem;
  background-color: var(--sidebar-btn-bg);
  color: var(--sidebar-btn-color);
  border: 1px solid var(--sidebar-border-color);
  border-radius: 0.375rem;
  font-size: 0.875rem;
  cursor: pointer;
  transition: all 0.3s ease;
  z-index: 100;
  opacity: 0; // 默认透明隐藏

  &:hover {
    background-color: var(--sidebar-hover-bg);
    transform: scale(1.1);
    opacity: 1; // 悬停时显示
  }

  i {
    transition: transform 0.3s ease;
  }
}

// Desktop sidebar collapsed state
@media all and (min-width: 850px) {
  #sidebar-collapse,
  #sidebar-collapse-trigger {
    display: block;
  }

  // 当鼠标悬停在侧边栏顶部区域时显示按钮
  #sidebar-collapse-trigger:hover ~ #sidebar-collapse {
    opacity: 1;
  }

  // 按钮自身悬停时也保持显示
  #sidebar-collapse:hover {
    opacity: 1;
  }

  body[data-sidebar-collapsed='true'] {
    #sidebar {
      transform: translateX(-$sidebar-width);
    }

    #main-wrapper {
      margin-left: 0;
    }

    #sidebar-collapse i {
      transform: rotate(180deg);
    }
  }
}

样式说明:

  • #sidebar-collapse-trigger: 隐藏的触发区域,只在侧边栏顶部 120px 范围
  • #sidebar-collapse: 折叠按钮的基本样式,包括位置、颜色、过渡动画
  • opacity: 0: 默认透明隐藏,保持界面简洁
  • #sidebar-collapse-trigger:hover ~ #sidebar-collapse: 当鼠标悬停在顶部区域时显示按钮
  • #sidebar-collapse:hover: 按钮自身悬停时也保持显示
  • @media all and (min-width: 850px): 仅在桌面端显示按钮和触发区域
  • body[data-sidebar-collapsed='true']: 折叠状态下的样式规则
    • 侧边栏向左平移隐藏 (translateX(-$sidebar-width))
    • 主内容区左边距归零,占满全屏
    • 图标旋转 180 度变为向右箭头

步骤 3: 实现 JavaScript 逻辑

编辑 _javascript/modules/components/sidebar.js 文件,修改内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
 * Expand or close the sidebar in mobile screens.
 */

const ATTR_DISPLAY = 'sidebar-display';
const STORAGE_KEY = 'sidebar-collapsed';

class SidebarUtil {
  static isExpanded = false;

  static toggle() {
    if (SidebarUtil.isExpanded === false) {
      document.body.setAttribute(ATTR_DISPLAY, '');
    } else {
      document.body.removeAttribute(ATTR_DISPLAY);
    }

    SidebarUtil.isExpanded = !SidebarUtil.isExpanded;
  }

  // Desktop collapse functionality
  static initDesktopCollapse() {
    const collapseBtn = document.getElementById('sidebar-collapse');
    if (!collapseBtn) return;

    // Restore saved state
    const isCollapsed = localStorage.getItem(STORAGE_KEY) === 'true';
    if (isCollapsed) {
      document.body.setAttribute('data-sidebar-collapsed', 'true');
    }

    // Toggle collapse on button click
    collapseBtn.addEventListener('click', () => {
      const currentState = document.body.getAttribute('data-sidebar-collapsed');
      const newState = currentState !== 'true';
      
      if (newState) {
        document.body.setAttribute('data-sidebar-collapsed', 'true');
      } else {
        document.body.removeAttribute('data-sidebar-collapsed');
      }
      
      // Save state to localStorage
      localStorage.setItem(STORAGE_KEY, newState);
    });
  }
}

export function sidebarExpand() {
  document
    .getElementById('sidebar-trigger')
    .addEventListener('click', SidebarUtil.toggle);

  document.getElementById('mask').addEventListener('click', SidebarUtil.toggle);
  
  // Initialize desktop collapse
  SidebarUtil.initDesktopCollapse();
}

逻辑说明:

  1. 常量定义:
    • STORAGE_KEY: localStorage 的键名,用于保存状态
    • ATTR_DISPLAY: 移动端侧边栏显示属性
  2. initDesktopCollapse() 方法:
    • 页面加载时从 localStorage 读取上次的状态
    • 如果上次是折叠状态,自动应用 data-sidebar-collapsed 属性
    • 监听按钮点击事件,切换折叠状态
    • 保存新状态到 localStorage
  3. sidebarExpand() 函数:
    • 保留原有的移动端折叠功能
    • 新增调用 SidebarUtil.initDesktopCollapse() 初始化桌面端功能

步骤 4: 重新构建项目

完成修改后,需要重新构建 JavaScript 和 Jekyll 站点:

1
2
3
4
5
6
7
8
# 1. 重新构建 JavaScript
npx rollup -c --bundleConfigAsCjs

# 2. 重新构建网站
bundle exec jekyll build

# 3. 启动本地服务器测试
bundle exec jekyll serve

步骤 5: 测试验证

  1. 打开浏览器: 访问 http://127.0.0.1:4000/
  2. 检查按钮: 确认侧边栏右上角显示折叠按钮(双左箭头图标)
  3. 测试折叠: 点击按钮,侧边栏应该向左滑出,内容区域变宽
  4. 测试展开: 再次点击,侧边栏滑回,恢复导航
  5. 测试记忆: 刷新页面,确认状态保持不变
  6. 响应式测试: 调整浏览器宽度,确认移动端 (< 850px) 按钮隐藏

核心实现原理

1. 状态管理

使用 HTML5 的 data-* 属性管理状态:

  • 移动端:sidebar-display 属性(通过 body 标签控制)
  • 桌面端:data-sidebar-collapsed 属性(通过 body 标签控制)

2. CSS Transform 动画

利用 CSS transform 实现平滑的滑入/滑出效果:

1
2
3
4
5
6
7
#sidebar {
  transform: translateX(-$sidebar-width); // 隐藏到左侧
}

#main-wrapper {
  margin-left: $sidebar-width; // 默认留出侧边栏宽度
}

3. LocalStorage 持久化

使用 localStorage 保存用户偏好:

1
2
3
4
5
// 保存状态
localStorage.setItem('sidebar-collapsed', 'true');

// 读取状态
const isCollapsed = localStorage.getItem('sidebar-collapsed') === 'true';

4. 响应式断点

通过 CSS Media Query 区分桌面端和移动端:

1
2
3
4
5
6
@media all and (min-width: 850px) {
  // 桌面端样式
  #sidebar-collapse {
    display: block;
  }
}

技术要点总结

技术用途说明
HTML Button折叠按钮用户交互入口
CSS Transform动画效果侧边栏滑入/滑出
CSS Media Query响应式区分桌面端/移动端
JavaScript Event事件监听点击事件处理
LocalStorage状态持久化记住用户偏好
Font Awesome图标显示视觉提示

常见问题

Q1: 按钮不显示?

A: 检查浏览器宽度是否 ≥ 850px,并确认 CSS 已正确编译。

Q2: 折叠后内容被遮挡?

A: 检查 #main-wrappermargin-left 是否正确设置为 0

Q3: 状态没有保存?

A: 检查浏览器是否允许 localStorage,或尝试清除缓存后重试。

Q4: 移动端也显示按钮?

A: 确认 CSS Media Query 的断点设置是否正确。

扩展功能建议

如果你有更多需求,可以考虑以下扩展:

  1. 快捷键支持: 添加键盘快捷键(如 Ctrl + B)快速折叠
  2. 动画速度配置: 允许用户自定义动画速度
  3. 多侧边栏支持: 如果博客有多个侧边栏,可以分别控制
  4. 状态同步: 使用 URL 参数或 Cookie 实现跨设备同步
  5. 辅助功能: 添加 ARIA 属性,提升无障碍访问体验

参考资料

© 2024- lfj