果味博客卡片系统 - 技术文档
果味博客卡片系统 - 技术文档
系统架构
层级结构
品牌层 (Brand Layer)
├── 颜色系统 (Color System) ← _variables.scss
│ ├── 8种水果色
│ └── 4种渐变配置
│
├── 组件层 (Component Layer) ← _post-card.scss
│ ├── 卡片容器 (.posts)
│ ├── 卡片本体 (.post-card)
│ ├── 封面区域 (.card-cover)
│ ├── 内容区域 (.card-content)
│ ├── 标题 (.card-title)
│ ├── 标签 (.card-tags)
│ ├── 元数据 (.card-meta)
│ ├── 摘要 (.card-excerpt)
│ └── 底部 (.card-footer)
│
└── 模板层 (Template Layer) ← blog.html
├── 循环遍历文章
├── 渲染卡片
└── 处理可选字段
CSS 类层次
顶级容器
.posts {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: var(--space-6);
padding: var(--space-5) 0;
margin: 0;
}
响应式断点:
>768px: 自动 3+ 列480-768px: 自动 1-2 列<480px: 1 列
卡片主体
.post-card {
/* 布局 */
display: flex;
flex-direction: column;
height: 100%;
/* 外观 */
background: var(--body-bg);
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
border: 1px solid rgba(255, 255, 255, 0.5);
/* 动画 */
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
悬停效果:
transform: translateY(-12px)- 上浮box-shadow: 0 20px 50px rgba(0, 0, 0, 0.15)- 增强阴影border-color: var(--fruit-peach)- 边框变色
封面区域
.card-cover {
width: 100%;
height: 200px;
background: linear-gradient(135deg, var(--fruit-mango), var(--fruit-peach), var(--fruit-orange));
background-size: cover;
background-position: center;
background-attachment: fixed;
overflow: hidden;
transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
特殊处理:
background-blend-mode: overlay- 与背景图融合::after- 渐变叠加层::before- 装饰表情符号
标签系统
.tag {
display: inline-flex;
align-items: center;
padding: 4px 12px;
border-radius: 20px;
letter-spacing: 0.5px;
transition: all 0.3s ease;
/* 根据位置着色 */
&:nth-child(1) { background: rgba(255, 215, 0, 0.2); color: var(--fruit-mango); }
&:nth-child(2) { background: rgba(255, 107, 157, 0.2); color: var(--fruit-strawberry); }
&:nth-child(3) { background: rgba(255, 149, 0, 0.2); color: var(--fruit-orange); }
&:nth-child(n+4) { background: rgba(124, 179, 66, 0.2); color: var(--fruit-kiwi); }
}
响应式设计细节
断点定义
// 桌面:1200px+
@media (max-width: 1200px) {
// 3列 → 2列
}
// 平板:768px-1200px
@media (max-width: 768px) {
grid-template-columns: 1fr; // 改为单列
gap: var(--space-5);
}
// 手机:480px以下
@media (max-width: 480px) {
gap: var(--space-4);
padding: var(--space-4);
-webkit-line-clamp: 2; // 摘要从3行变2行
}
移动优化
- 字体大小:自动缩小
- 间距:自动减少
- 图片高度:保持固定(200px)
- 动画:禁用某些复杂效果
Jekyll 集成
Front Matter 字段
---
layout: post
title: String # 必须
date: DateTime # 必须
tags: [String] # 可选,数组
excerpt: String # 可选,摘要
cover_image: String # 可选,封面图路径
image: String # 可选,备用图路径
toc: Boolean # 可选,目录
---
模板逻辑
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog16.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">mysql</span>
<span class="tag">unity</span>
<span class="tag">软件开发</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog15.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">软件开发</span>
<span class="tag">数字孪生</span>
<span class="tag">unity</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog14.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">openvino</span>
<span class="tag">Qwen</span>
<span class="tag">unity</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog13.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">软件开发</span>
<span class="tag">cron表达式</span>
<span class="tag">Web</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog12.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">时间序列预测</span>
<span class="tag">边缘AI</span>
<span class="tag">机会网络</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog11.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">联邦学习</span>
<span class="tag">仿真实验</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog10.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">科研</span>
<span class="tag">总结</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog9.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">C++</span>
<span class="tag">program</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog8.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">指数滑动平均法</span>
<span class="tag">加权质心定位</span>
<span class="tag">Mobile CrowdSensoring</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog7.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">BaiduMap</span>
<span class="tag">android</span>
<span class="tag">Mobile CrowdSensoring</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog5.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">android</span>
<span class="tag">BaiduMap</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog4.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">Django</span>
<span class="tag">websocket</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog1.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">Mobile-CrowdSensoring</span>
<span class="tag">BaiduMap</span>
<span class="tag">android</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog3.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">BaiduMap</span>
<span class="tag">android</span>
<span class="tag">java</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog2.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">BaiduMap</span>
<span class="tag">android</span>
<span class="tag">java</span>
</div>
<!-- 其他内容 -->
</article>
<article class="post-card">
<!-- 封面:优先使用 cover_image,其次 image -->
<div class="card-cover"
style="background-image: url('/img/covers/blog6.jpg')"
>
</div>
<!-- 标签:限制显示3个 -->
<div class="card-tags">
<span class="tag">RL</span>
<span class="tag">Robot</span>
<span class="tag">pathplan</span>
</div>
<!-- 其他内容 -->
</article>
颜色系统详解
设计原则
- 温暖底色:以橙黄色系为主,传递活力感
- 冷色点缀:绿色和蓝色用于平衡
- 渐变过渡:使用 135deg 线性渐变创建动态感
- 可访问性:对比度 > 4.5:1(WCAG AA)
颜色使用规则
| 颜色 | 亮度 | 用途 | 对比度 |
|---|---|---|---|
| 芒果黄 | 高 | 主色调、亮点 | ✓ 好 |
| 桃子色 | 中-高 | 次主色、过渡 | ✓ 好 |
| 橙子色 | 中 | 强调、按钮 | ✓ 好 |
| 草莓红 | 中-高 | 标签、突出 | ✓ 好 |
| 樱桃红 | 中 | 深调、对比 | ✓ 好 |
| 西瓜红 | 低 | 特殊强调 | ✓ 好 |
| 猕猴桃绿 | 中 | 辅助、平衡 | ✓ 好 |
| 蓝莓蓝 | 中 | 补充、替代 | ✓ 好 |
深色模式适配
@media (prefers-color-scheme: dark) {
:root {
--body-color: var(--dark-body-color);
--body-bg: var(--dark-body-bg);
--heading-color: var(--dark-heading-color);
--link-color: var(--dark-link-color);
--border-color: var(--dark-border-color);
}
}
深色模式优化:
- 背景从白色改为
#1a1a2e - 文字颜色自动反转
- 阴影透明度增加
- 渐变强度调整
动画效果
使用的 easing 函数
cubic-bezier(0.34, 1.56, 0.64, 1)
这是一个过度缓动函数,特点:
- 略微超调(overshoot)
- 自然、有弹性的感觉
- 适合 UI 动画
过渡属性
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
涵盖的属性:
transform- 位置变化box-shadow- 阴影变化color- 文字颜色border-color- 边框颜色
性能考虑
优化点
- 使用 GPU 加速:
transform和opacity使用 GPU - 避免 layout trashing:使用
transform而不是top/left - 条件渲染:标签限制 3 个,防止 DOM 过多
- 选择器优化:使用简洁的类名和选择器
性能数据
- 首屏加载:无额外 JS,仅 CSS
- 重排开销:最小化(只使用
transform) - 动画帧率:60fps(通过 GPU 加速)
- 文件大小:
_post-card.scss: ~8KB(压缩后 ~2KB)_variables.scss增量:~1KB
浏览器特性检测
必需特性
display: grid- 所有现代浏览器CSS 变量- 所有现代浏览器background-blend-mode- 95% 浏览器支持transition- 所有浏览器
备选方案
- 不支持 Grid:降级到 Flexbox
- 不支持 CSS 变量:使用预定义值
- 不支持 blend-mode:使用
::after伪元素
调试技巧
常见问题
1. 卡片样式不生效?
# 清除缓存重新构建
rm -rf .jekyll-cache _site
bundle exec jekyll serve
2. 封面图不显示?
// 在浏览器控制台检查
console.log(document.querySelector('.card-cover').style.backgroundImage);
3. 响应式不工作?
/* 检查视口宽度 */
body::before {
content: 'Width: ' attr(data-width);
position: fixed;
top: 0;
left: 0;
}
扩展可能性
可以添加的功能
- 图片懒加载:使用
loading="lazy" - 阅读时间:显示预估阅读时间
- 评论计数:显示评论数量
- 分享按钮:添加社交分享
- 过滤器:按标签筛选
- 搜索:全文搜索功能
- 排序:按日期/热度排序
- 卡片变体:不同大小的卡片
代码示例
<!-- 添加阅读时间 -->
技术栈:Jekyll + SCSS + CSS Grid + CSS Variables 兼容性:IE 11+ (需要 polyfill) 无障碍:WCAG 2.1 AA 级别