社交页面设计与架构解析
目录
前言
本文介绍个人网站社交页面的设计思路和架构实现。该页面采用类似Twitter的三栏布局,整合了微博/豆瓣广播、博客、专利、影视游戏书籍等多种社交内容,实现统一的信息聚合展示。
整体架构
页面布局设计
┌─────────────────────────────────────────────────────────────┐
│ 顶部导航 │
├────────────────┬─────────────────────────────────┬──────────┤
│ │ │ │
│ 左侧固定边栏 │ 主内容区域 │ 右侧固定 │
│ (Navigation) │ (Scrollable) │ (Widgets)│
│ │ │ │
│ • Home │ ┌─────────────────────────┐ │ │
│ • Blogs │ │ Profile Header │ │ GitHub │
│ • Patents │ ├─────────────────────────┤ │ │
│ • Travel │ │ Tab Navigation │ │ LinkedIn │
│ • Books │ ├─────────────────────────┤ │ │
│ • Movies │ │ Content Panels │ │ Email │
│ • Games │ │ (Broadcast/Blogs/etc) │ │ │
│ │ └─────────────────────────┘ │ │
│ │ │ │
└────────────────┴─────────────────────────────────┴──────────┘
技术栈
| 层级 | 技术选型 | 说明 |
|---|---|---|
| 布局框架 | CSS Flexbox/Grid | 三栏响应式布局 |
| 样式方案 | 原生CSS | 移动端适配 |
| 数据源 | Jekyll Data Files | _data/目录下的JSON |
| 页面生成 | Jekyll Layouts | 静态页面构建 |
| 交互逻辑 | Vanilla JavaScript | Tab切换、图片灯箱 |
数据架构设计
数据源整合
graph TD
subgraph _data目录
A[douban/2021-2026.json] --> G[social.md]
B[blogs/all.json] --> G
C[patents.json] --> G
D[books/all.json] --> G
E[movies/all.json] --> G
F[games/all.json] --> G
end
G --> H[页面渲染]
subgraph 数据类型
I[Broadcast: 豆瓣广播]
J[Blogs: 技术博客]
K[Patents: 专利列表]
L[Media: 图书/电影/游戏]
end
H --> I
H --> J
H --> K
H --> L
数据结构示例
# _data/douban/2026.json
- time: "2026-01-12 20:30"
content: "分享一段文字"
images:
- "https://image.xxx.com/1.jpg"
my_rating: 5
# _data/books/all.json
- title: "设计模式"
author: "GoF"
cover: "/images/books/xxx.jpg"
my_rating: 4
status: "已读"
前端实现细节
CSS架构
/* 三栏基础布局 */
.social-layout {
display: flex;
max-width: 1300px;
margin: 0 auto;
}
/* 左侧固定边栏 */
.social-left-sidebar {
position: fixed;
width: 280px;
height: 100vh;
}
/* 中间主内容 */
.social-main {
flex: 1;
margin-left: 280px; /* 左侧宽度 */
margin-right: 350px; /* 右侧宽度 */
min-height: 100vh;
}
/* 右侧固定边栏 */
.social-right-sidebar {
position: fixed;
right: 0;
width: 350px;
height: 100vh;
}
响应式断点
flowchart TB
A[屏幕宽度] --> B{>1280px}
B -->|是| C[完整三栏]
B -->|否| D{>1024px}
D -->|是| E[隐藏右侧边栏]
D -->|否| F{>768px}
F -->|是| G[隐藏左侧边栏]
F -->|否| H[单栏移动端]
C --> I[正常显示]
E --> J[main margin-right: 0]
G --> K[main margin-left: 80px]
H --> L[铺满屏幕]
Tab切换实现
document.addEventListener('DOMContentLoaded', function() {
const tabItems = document.querySelectorAll('.tab-item');
const panels = document.querySelectorAll('.content-panel');
tabItems.forEach(function(item) {
item.addEventListener('click', function(e) {
e.preventDefault();
var targetTab = this.getAttribute('data-tab');
// 更新Tab状态
tabItems.forEach(function(tab) {
tab.classList.remove('active');
});
this.classList.add('active');
// 切换内容面板
panels.forEach(function(panel) {
panel.classList.remove('active');
});
const activePanel = document.getElementById(targetTab + '-panel');
if (activePanel) activePanel.classList.add('active');
// 更新URL Hash
history.pushState(null, null, '#' + targetTab);
});
});
});
内容面板设计
广播面板 (Broadcast)
graph LR
A[请求数据] --> B[渲染卡片]
B --> C[图片网格]
C --> D[灯箱功能]
subgraph 卡片结构
E[头像] --> F[用户名]
F --> G[时间]
G --> H[内容]
H --> I[图片]
I --> J[互动数]
end
博客面板
┌──────────────────────────────────────┐
│ 博客卡片 │
├──────────────────────────────────────┤
│ 标题 │
│ ├── 文章标题(主标题) │
│ └── 副标题/描述(可选) │
├──────────────────────────────────────┤
│ 内容摘要 │
│ ├── 自动截取前200字 │
│ └── 支持自定义description字段 │
├──────────────────────────────────────┤
│ 元信息 │
│ ├── 日期 │
│ └── 标签/分类 │
└──────────────────────────────────────┘
媒体面板
/* 媒体网格布局 */
.media-grid {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.media-item {
display: flex;
flex-direction: column;
align-items: center;
width: 80px;
}
.media-item img {
width: 70px;
height: 100px;
object-fit: cover;
border-radius: 6px;
}
性能优化策略
图片懒加载
// 使用loading="lazy"属性
<img src="..." loading="lazy" alt="...">
// 或Intersection Observer实现
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
虚拟列表/分页
function loadMore(listId) {
const list = document.getElementById(listId);
const hiddenItems = Array.from(list.querySelectorAll('.expandable-item'))
.filter(el => el.style.display === 'none');
// 每次加载10条
for (let i = 0; i < Math.min(hiddenItems.length, 10); i++) {
hiddenItems[i].style.display = '';
}
// 隐藏按钮如果全部加载完成
const remaining = list.querySelectorAll('.expandable-item[style*="display: none"]');
if (remaining.length === 0) {
const btn = list.parentElement.querySelector('.load-more-btn');
if (btn) btn.style.display = 'none';
}
}
CSS优化
/* 使用CSS变量减少重复 */
:root {
--primary-color: #1d9bf0;
--bg-color: #fff;
--text-color: #0f1419;
}
/* 使用will-change优化动画 */
.hover-effect {
will-change: transform;
transition: transform 0.2s ease;
}
用户体验设计
交互反馈
| 场景 | 反馈方式 |
|---|---|
| Tab切换 | 立即切换,高亮当前 |
| 按钮点击 | hover状态 + active状态 |
| 图片加载 | loading占位 + fadein |
| 加载更多 | spinner动画 + 加载完成提示 |
| 图片灯箱 | 遮罩层 + 左右切换按钮 |
视觉层级
┌─────────────────────────────────────────────┐
│ 一级:主要内容 │
│ ├── 卡片标题(16px, bold) │
│ └── 卡片内容(14px, regular) │
├─────────────────────────────────────────────┤
│ 二级:辅助信息 │
│ ├── 日期/来源(13px, gray) │
│ └── 互动数据(13px, gray) │
├─────────────────────────────────────────────┤
│ 三级:装饰元素 │
│ ├── 分隔线(1px, #eff3f4) │
│ └── 背景色(#f7f9f9) │
└─────────────────────────────────────────────┘
扩展性考虑
插件化设计
// 面板配置
const panels = {
'posts': {
title: 'Broadcast',
dataSource: 'douban',
template: 'feed-item'
},
'blogs': {
title: 'Blogs',
dataSource: 'blogs',
template: 'blog-card'
},
'patents': {
title: 'Patents',
dataSource: 'patents',
template: 'patent-card'
},
'media': {
title: 'Media',
dataSource: ['books', 'movies', 'games'],
template: 'media-grid'
}
};
// 动态注册面板
function registerPanel(key, config) {
panels[key] = config;
renderTab(key, config);
}
主题切换
[data-theme="light"] {
--bg-color: #ffffff;
--text-color: #0f1419;
}
[data-theme="dark"] {
--bg-color: #000000;
--text-color: #e7e9ea;
}
总结
本文介绍了社交页面的核心设计:
| 方面 | 方案 |
|---|---|
| 布局 | Twitter风格三栏(固定+滚动+固定) |
| 数据 | Jekyll Data Files统一管理 |
| 交互 | Vanilla JS实现Tab切换和灯箱 |
| 响应式 | CSS Media Queries三档适配 |
| 性能 | 懒加载 + 分页加载 |
| 扩展 | 插件化面板注册 + 主题切换 |
该设计平衡了信息密度和用户体验,通过静态生成保证了加载性能,同时保留了良好的交互体验。
RedNote