侧边栏模块
特点和亮点
这个侧边栏导航模块具有以下特点:
- 视觉冲击力
- 使用深蓝色渐变背景,提供高对比度和视觉冲击力
- 精心设计的阴影效果增强立体感
- 响应式设计
- 在桌面端固定显示(宽度280px,高度100vh)
- 在移动端自动隐藏,并显示一个悬浮的菜单按钮
- 流畅动画
- 侧边栏滑入/滑出动画使用cubic-bezier曲线实现平滑过渡
- 导航项目有级联动画效果,依次显示
- 菜单按钮位置变化动画
- 半透明遮罩
- 移动端展开时显示带模糊效果的半透明遮罩
- 点击遮罩可关闭侧边栏
- 精美细节
- 自定义滚动条样式
- 导航项目悬停效果
- 活跃项目左侧指示条
- 用户资料区域设计
这个侧边栏设计既美观又实用,适合用于各种Web应用和管理系统。在移动设备上,用户可以通过点击左上角的菜单按钮展开侧边栏,再次点击按钮或点击遮罩层可以关闭侧边栏。
截图
代码
<style>
.sidebar-sbox .sidebar{width:280px;height:100vh;position:fixed;top:0;left:0;background:linear-gradient(135deg,#1a237e 0,#283593 100%);color:#fff;box-shadow:4px 0 15px rgba(0,0,0,.2);z-index:1002;transition:transform .4s cubic-bezier(.4,0,.2,1);display:flex;flex-direction:column;overflow-y:auto;overflow-x:hidden}
.sidebar-sbox .sidebar-header{padding:25px 20px;display:flex;align-items:center;border-bottom:1px solid rgba(255,255,255,.1)}
.sidebar-sbox .sidebar-header .logo{font-size:24px;font-weight:700;letter-spacing:1px;display:flex;align-items:center}
.sidebar-sbox .sidebar-header img{width:100%}
.sidebar-sbox .nav-menu{padding:20px 0;flex:1;display: unset;}
.sidebar-sbox .nav-section{margin-bottom:15px}
.sidebar-sbox .nav-section a{color:unset}
.sidebar-sbox .nav-section-title{padding:10px 25px;font-size:12px;text-transform:uppercase;letter-spacing:1px;color:rgba(255,255,255,.6);font-weight:600}
.sidebar-sbox .nav-item{padding:12px 25px;display:flex;align-items:center;cursor:pointer;transition:all .2s ease;position:relative}
.sidebar-sbox .nav-item:hover{background:rgba(255,255,255,.1)}
.sidebar-sbox .nav-item.active{background:rgba(255,255,255,.15)}
.sidebar-sbox .nav-item.active::before{content:'';position:absolute;left:0;top:0;height:100%;width:4px;background:#fff;border-radius:0 2px 2px 0}
.sidebar-sbox .nav-item-icon{width:20px;height:20px;margin-right:15px;opacity:.85}
.sidebar-sbox .nav-item-text{font-size:15px;font-weight:500}
.sidebar-sbox .nav-item-badge{margin-left:auto;background:rgba(255,255,255,.2);padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600}
.sidebar-sbox .sidebar-footer{padding:15px 25px;border-top:1px solid rgba(255,255,255,.1);display:flex;align-items:center}
.sidebar-sbox .sidebar-footer a{color:unset}
.sidebar-sbox .user-info{display:flex;align-items:center;flex:1}
.sidebar-sbox .user-avatar{width:36px;height:36px;border-radius:50%;background:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;margin-right:12px;overflow:hidden}
.sidebar-sbox .user-avatar img{width:100%;height:100%;object-fit:cover}
.sidebar-sbox .user-name{font-size:14px;font-weight:500}
.sidebar-sbox .user-status{font-size:12px;opacity:.7;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:120px}
.sidebar-sbox .logout-btn{width:32px;height:32px;border-radius:50%;background:rgba(255,255,255,.1);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .2s}
.sidebar-sbox .logout-btn:hover{background:rgba(255,255,255,.2)}
.sidebar-sbox .sidebar-toggle{position:fixed;top:20px;left:20px;width:45px;height:45px;border-radius:10px;background:#1a237e;color:#fff;display:none;align-items:center;justify-content:center;cursor:pointer;z-index:1001;box-shadow:0 4px 10px rgba(0,0,0,.2);transition:all .3s ease}
.sidebar-sbox .sidebar-toggle:hover{background:#283593}
.sidebar-sbox .sidebar-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);backdrop-filter:blur(2px);z-index:1001;opacity:0;visibility:hidden;transition:all .3s ease}
@media (max-width:991px){.sidebar-sbox .sidebar{transform:translateX(-100%)}
.sidebar-sbox .sidebar-toggle{display:flex}
.sidebar-sbox .content{margin-left:0;padding:20px}
.sidebar-sbox.sidebar-open .sidebar{transform:translateX(0)}
.sidebar-sbox.sidebar-open .sidebar-overlay{opacity:1;visibility:visible}
.sidebar-sbox.sidebar-open .sidebar-toggle{left:300px}
}
@keyframes fadeIn{from{opacity:0}
to{opacity:1}
}
@keyframes slideIn{from{transform:translateX(-20px);opacity:0}
to{transform:translateX(0);opacity:1}
}
.sidebar-sbox .nav-item{animation:slideIn .3s ease forwards;opacity:0}
.sidebar-sbox .nav-item:nth-child(1){animation-delay:.1s}
.sidebar-sbox .nav-item:nth-child(2){animation-delay:.15s}
.sidebar-sbox .nav-item:nth-child(3){animation-delay:.2s}
.sidebar-sbox .nav-item:nth-child(4){animation-delay:.25s}
.sidebar-sbox .nav-item:nth-child(5){animation-delay:.3s}
.sidebar-sbox .nav-item:nth-child(6){animation-delay:.35s}
.sidebar-sbox .nav-item:nth-child(7){animation-delay:.4s}
.sidebar-sbox .nav-item:nth-child(8){animation-delay:.45s}
.sidebar-sbox .sidebar::-webkit-scrollbar{width:5px}
.sidebar-sbox .sidebar::-webkit-scrollbar-track{background:rgba(255,255,255,.05)}
.sidebar-sbox .sidebar::-webkit-scrollbar-thumb{background:rgba(255,255,255,.2);border-radius:3px}
.sidebar-sbox .sidebar::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.3)}
.sidebar-sbox .content-header{margin-bottom:30px}
.sidebar-sbox .content-header h1{font-size:28px;font-weight:700;margin-bottom:10px;color:#333}
.sidebar-sbox .content-header p{color:#666;font-size:16px;line-height:1.6}
.sidebar-sbox .card{background:#fff;border-radius:10px;box-shadow:0 4px 15px rgba(0,0,0,.05);padding:25px;margin-bottom:25px}
.sidebar-sbox .card h2{font-size:20px;margin-bottom:15px;color:#333}
.sidebar-sbox .card p{color:#666;line-height:1.6}
</style>
<div class="sidebar-sbox">
<div class="sidebar-toggle" id="sidebarToggle">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</div>
<!-- 移动设备覆盖 -->
<div class="sidebar-overlay" id="sidebarOverlay"></div>
<!-- 边栏导航 -->
<div class="sidebar" id="sidebar">
<div class="sidebar-header">
<div class="logo">
<img src="{:set('logo','set')}" alt="{:set('title','set')}">
</div>
</div>
<div class="nav-menu">
<div class="nav-section">
<div class="nav-section-title">主导航</div>
{volist name=":Db::name('link')->where(['open'=>1,'wz'=>1])->order('px desc')->select()" id="vo"}
<a rel="{$vo.rel}" href="{$vo.lianjie}" {if $vo.xin}target="_blank"{/if}>
<div class="nav-item {if $hover == explode(',', $vo['hover'])[0] || $hover == explode(',', $vo['hover'])[1]}active{/if}">
<div class="nav-item-icon">
<i class="fa {$vo.pic}"></i>
</div>
<div class="nav-item-text">{$vo.name}</div>
</div>
</a>
{/volist}
</div>
<div class="nav-section">
<div class="nav-section-title">我的</div>
{if user('id')}
<a href="{:index('/user/collection.html')}">
<div class="nav-item {if $hover == 'user_collection'}active{/if}">
<div class="nav-item-icon">
<i class="fa fa-heart"></i>
</div>
<div class="nav-item-text">我的收藏</div>
<div class="nav-item-badge">{:db_count('shoucang',['uid'=>user('id')])}</div>
</div>
</a>
<a href="{:index('/user/add.html')}">
<div class="nav-item {if $hover == 'user_add'}active{/if}">
<div class="nav-item-icon">
<i class="fa fa-paper-plane"></i>
</div>
<div class="nav-item-text">申请收录</div>
</div>
</a>
<a href="{:index('/user')}">
<div class="nav-item {if $hover == 'user_index'}active{/if}">
<div class="nav-item-icon">
<i class="fa fa-user"></i>
</div>
<div class="nav-item-text">个人中心</div>
</div>
</a>
{else/}
<a href="{:index('/login.html')}">
<div class="nav-item {if $hover == 'page_login'}active{/if}">
<div class="nav-item-icon">
<i class="fa fa-heart"></i>
</div>
<div class="nav-item-text">登录</div>
</div>
</a>
<a href="{:index('/reg.html')}">
<div class="nav-item {if $hover == 'page_reg'}active{/if}">
<div class="nav-item-icon">
<i class="fa fa-cloud"></i>
</div>
<div class="nav-item-text">注册</div>
</div>
</a>
{/if}
</div>
</div>
{if user('id')}
<div class="sidebar-footer">
<div class="user-info">
<div class="user-avatar">
<img src="{:user('head')}">
</div>
<div>
<div class="user-name">{:user('name')}</div>
<div class="user-status">{:dingyi(user('description'),'这个人很懒,还没有个性签名~')}</div>
</div>
</div>
<a href="{:url('api/logout')}">
<div class="logout-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
<polyline points="16 17 21 12 16 7"></polyline>
<line x1="21" y1="12" x2="9" y2="12"></line>
</svg>
</div>
</a>
</div>
{/if}
</div>
<script>
const sidebarSbox = document.querySelector('.sidebar-sbox');
const sidebarToggle = document.getElementById('sidebarToggle');
const sidebarOverlay = document.getElementById('sidebarOverlay');
const ohElement = document.querySelector('.oh');
function toggleSidebar() {
sidebarSbox.classList.toggle('sidebar-open');
}
sidebarToggle.addEventListener('click', toggleSidebar);
sidebarOverlay.addEventListener('click', toggleSidebar);
const navItems = document.querySelectorAll('.nav-item');
navItems.forEach(item => {
item.addEventListener('click', () => {
if (window.innerWidth <= 991) {
setTimeout(() => {
sidebarSbox.classList.remove('sidebar-open');
}, 300);
}
// Remove active class from all items
navItems.forEach(i => i.classList.remove('active'));
// Add active class to clicked item
item.classList.add('active');
});
});
window.addEventListener('resize', () => {
if (window.innerWidth > 991) {
sidebarSbox.classList.remove('sidebar-open');
}
});
</script>
</div>