本站当前使用主题(2026-8-28)为Blowfish-第一次修改 完成 侧边栏去除 尺寸适应及导航闭环

Bludit Blowfish 主题深度改造复盘笔记|去侧边栏+全屏内容+导航下拉分类闭环

此主题是作者移植的,主题本身很优秀 但不适合我对过度复杂内容及多栏布局的审美 所以我决定宽屏

一、改造背景 & 原始问题

本次针对 Bludit CMS Blowfish 主题 进行布局重构与导航功能闭环优化,原始存在三大核心问题:

  1. 右侧侧边栏冗余:默认自带右侧边栏,挤占主体内容宽度,文章/首页阅读区域狭窄,视觉体验差。
  2. 顶部导航功能残缺:主题原生导航仅输出「静态页面」,无法展示博客分类栏目,无CMS级栏目管理能力。
  3. 分类展示逻辑冲突:原生分类仅在侧边栏插件输出,删除侧边栏后所有分类栏目直接消失,无替代展示方案。

二、分步改造流程 & 踩坑复盘(核心可复用)

阶段1:彻底移除右侧边栏,拓宽全站内容宽度

bludit-blowfish/
├── index.php
找到 sidebar.php 引入代码 注释,此时侧边栏就会消失 但还只是第一步

1.1 问题根源

仅注释 sidebar.php 引入代码无效,Bootstrap栅格空DOM容器仍占位,内容宽度无法自适应拓宽。

1.2 最终解决方案(修改 index.php 布局栅格)

  • 文章页(带目录):原有 3(目录)+6(内容)+3(侧边空列) → 改为 3(目录)+9(内容),删除右侧空列
  • 首页/普通页面(无目录):原有 8(内容)+3(侧边空列+偏移) → 改为 12(全屏内容),彻底删除右侧栅格容器

1.3 无效方案弃用记录

网上通用的「阅读宽度优化CSS」无效,原因是主题DOM选择器不匹配,直接舍弃,无需冗余样式代码。

阶段2:顶部导航改造,实现分类栏目动态调用

2.1 核心难点(高频踩坑点)

  • Bludit 子模板 navbar.php 作用域受限,无法直接调用 Categories::getAll(),直接白屏(PHP致命错误)。
  • 子模板无法直接读取 $dbCategories 全局变量,报错空白。
  • 子模板调用插件 siteSidebar() 方法会导致程序状态错乱、全站白屏。

2.2 最终最优兼容方案(纯 navbar.php 单文件实现,不改动index)

通过 $GLOBALS['plugins'] 全局读取插件,复用原生Categories插件输出,正则解析分类列表,规避所有模板作用域报错问题:

  • 不调用危险模板类、不修改主文件、无PHP报错
  • 自动剥离分类文章计数后缀 (1)(3)
  • 自动匹配当前分类页面,实现导航active高亮

阶段3:导航栏目下拉收纳闭环(解决导航撑爆问题)

3.1 需求

分类数量不固定,平铺导航会冲破页面,需单按钮下拉收纳所有栏目,永久适配任意数量分类。

3.2 实现逻辑

  1. 先PHP收集所有分类存入数组,不直接平铺输出
  2. 套用 Bootstrap4 Dropdown 结构,顶部仅展示「分类 ≡」按钮
  3. 所有分类收纳下拉菜单内,彻底解决导航溢出问题

阶段4:自定义JS+CSS修复交互与样式BUG

4.1 交互问题

主题未加载Bootstrap Popper核心JS,原生下拉点击无响应。

解决方案:手写极简独立JS,无需依赖第三方库,实现:点击展开/收起、点击页面空白关闭下拉、无障碍属性适配。

4.2 样式问题

默认下拉白背景、浅色文字,深色主题下完全看不清。

解决方案:重写下拉全套样式,适配Blowfish深色主题,优化hover、active高亮状态,视觉统一。

三、最终完成效果(全部达标)

  1. 布局优化:彻底移除右侧侧边栏,首页、文章页内容全屏拓宽,阅读体验大幅提升。
  2. 导航功能闭环:顶部导航 = 博客入口 + 静态页面 + 分类下拉菜单 + 社交图标 + 搜索+主题切换,完整CMS导航结构。
  3. 无限适配栏目:任意数量分类均收纳下拉内,导航永不撑爆、永不错位。
  4. 动态自动更新:后台新增/删除/修改分类,导航自动同步,无需手动改代码。
  5. 状态正常:访问对应分类页面,下拉条目自动高亮,交互逻辑完整。
  6. 全兼容:不破坏主题原主题色切换、移动端折叠、插件钩子、页面布局逻辑。

四、可复用核心代码清单

4.1 index.php 布局优化核心(去侧边栏、拓宽内容)

修改Bootstrap栅格:无目录页面 col-md-8 → col-md-12,有目录页面 col-md-6 → col-md-9,删除右侧边栏栅格容器。

4.2 navbar.php 分类下拉完整代码

<?php
// 从已启用的Categories插件提取分类链接,复用插件本身输出
$catUlHtml = '';
$plugins = $GLOBALS['plugins'];
$navCatItems = [];

if (isset($plugins['siteSidebar'])) {
    foreach ($plugins['siteSidebar'] as $plugin) {
        $pluginOut = $plugin->siteSidebar();
        if (strpos($pluginOut,'plugin-categories') !== false) {
            if(preg_match('/<ul>(.*?)<\/ul>/s',$pluginOut,$matches)){
                $catUlHtml = $matches[1];
            }
            break;
        }
    }
}

if (!empty($catUlHtml)) {
    preg_match_all('/<li>\s*<a\s+href="([^"]+)">([^<]+)<\/a>/',$catUlHtml,$liMatches,PREG_SET_ORDER);
    if (!empty($liMatches)) {
        foreach ($liMatches as $item) {
            $catHref = $item[1];
            $catRawTitle = $item[2];
            $catTitle = preg_replace('/\s*\(\d+\)$/','',$catRawTitle);

            $activeClass = '';
            if (isset($WHERE_AM_I, $url) && $WHERE_AM_I === 'category') {
                $slugCheck = explode('/', rtrim($catHref,'/'));
                $slugCheck = end($slugCheck);
                if ($url->slug() === $slugCheck) {
                    $activeClass = ' active';
                }
            }
            $navCatItems[] = [
                'href' => $catHref,
                'title' => $catTitle,
                'active' => $activeClass
            ];
        }
    }
}

// 渲染Bootstrap4下拉组件,只占导航栏一个位置
if (!empty($navCatItems)):
?>
<li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" href="#" id="catDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
        分类 ≡
    </a>
    <div class="dropdown-menu dropdown-menu-right" aria-labelledby="catDropdown">
        <?php foreach ($navCatItems as $c): ?>
            <a class="dropdown-item<?php echo $c['active']; ?>" href="<?php echo htmlspecialchars($c['href'],ENT_QUOTES); ?>">
                <?php echo blowfish_text($c['title']); ?>
            </a>
        <?php endforeach; ?>
    </div>
</li>
<?php endif; ?>

4.3 自定义下拉JS(页面底部 </body> 前插入,无依赖)

<script>
// 极简dropdown兼容脚本,适配Bootstrap4下拉DOM结构
document.addEventListener('DOMContentLoaded', function () {
    const toggle = document.getElementById('catDropdown');
    const menu = toggle?.nextElementSibling;
    if(!toggle || !menu) return;

    function closeDropdown(){
        toggle.setAttribute('aria-expanded','false');
        menu.classList.remove('show');
    }

    toggle.addEventListener('click', function(e){
        e.preventDefault();
        const expanded = toggle.getAttribute('aria-expanded') === 'true';
        if(expanded){
            closeDropdown();
        }else{
            toggle.setAttribute('aria-expanded','true');
            menu.classList.add('show');
        }
    });

    // 点击页面空白区域关闭下拉
    document.addEventListener('click',function(e){
        if (!toggle.contains(e.target) && !menu.contains(e.target)){
            closeDropdown();
        }
    });
});
</script>

4.4 深色主题下拉适配CSS(追加到style.css末尾)

/* 下拉菜单基础样式,适配深色导航 */
.dropdown-menu {
    background-color: #22262a !important;
    border: 1px solid rgba(255,255,255,0.12);
}

/* 下拉条目文字颜色 */
.navbar-dark .dropdown-item {
    color: rgba(255,255,255,0.85);
}

/* hover悬浮效果 */
.navbar-dark .dropdown-item:hover {
    background-color: rgba(255,255,255,0.08);
    color: #ffffff;
}

/* 当前激活分类高亮 */
.dropdown-item.active {
    background-color: rgba(255,255,255,0.16);
    color: #ffffff;
}

/* 下拉展开强制显示 */
.dropdown-menu.show {
    display: block;
}

4.5 直接调用分类插件且动态输出栏目

demo1


<?php
// 从已启用的Categories插件提取分类链接,复用插件本身输出,避免类调用报错
$catUlHtml = '';
if (isset($plugins['siteSidebar'])) {
    foreach ($plugins['siteSidebar'] as $plugin) {
        $pluginOut = $plugin->siteSidebar();
        // 匹配categories插件输出
        if (strpos($pluginOut,'plugin-categories') !== false) {
            // 只提取 <ul>...</ul> 部分
            if(preg_match('/<ul>(.*?)<\/ul>/s',$pluginOut,$matches)){
                $catUlHtml = $matches[1];
            }
            break;
        }
    }
}
// 把每一个 <li> 条目,输出成navbar需要的 nav-item nav-link
if (!empty($catUlHtml)) {
    // 拆分出每一个li
    preg_match_all('/<li>\s*<a\s+href="([^"]+)">([^<]+)<\/a>/',$catUlHtml,$liMatches,PREG_SET_ORDER);
    foreach ($liMatches as $item) {
        $catHref = $item[1];
        $catRawTitle = $item[2];
        // 去掉插件自带的计数后缀,例如 "(3)"
        $catTitle = preg_replace('/\s*\(\d+\)$/','',$catRawTitle);

        $activeClass = '';
        if ($WHERE_AM_I === 'category' && $url->slug() === basename($catHref)) {
            $activeClass = ' active';
        }
        echo '<li class="nav-item">';
        echo '<a class="nav-link'.$activeClass.'" href="'.$catHref.'">'.blowfish_text($catTitle).'</a>';
        echo '</li>';
    }
}
?>

demo2


<?php
// 从已启用的Categories插件提取分类链接,复用插件本身输出,避免类调用报错
$catUlHtml = '';
$plugins = $GLOBALS['plugins']; // 直接从全局符号表读取插件对象

if (isset($plugins['siteSidebar'])) {
    foreach ($plugins['siteSidebar'] as $plugin) {
        $pluginOut = $plugin->siteSidebar();
        // 匹配categories插件输出
        if (strpos($pluginOut,'plugin-categories') !== false) {
            // 只提取 <ul>...</ul> 部分
            if(preg_match('/<ul>(.*?)<\/ul>/s',$pluginOut,$matches)){
                $catUlHtml = $matches[1];
            }
            break;
        }
    }
}
// 把每一个 <li> 条目,输出成navbar需要的 nav-item nav-link
if (!empty($catUlHtml)) {
    // 拆分出每一个li
    preg_match_all('/<li>\s*<a\s+href="([^"]+)">([^<]+)<\/a>/',$catUlHtml,$liMatches,PREG_SET_ORDER);
    if (!empty($liMatches)) {
        foreach ($liMatches as $item) {
            $catHref = $item[1];
            $catRawTitle = $item[2];
            // 去掉插件自带的计数后缀,例如 "(3)"
            $catTitle = preg_replace('/\s*\(\d+\)$/','',$catRawTitle);

            $activeClass = '';
            if (isset($WHERE_AM_I, $url) && $WHERE_AM_I === 'category') {
                $slugCheck = explode('/', rtrim($catHref,'/'));
                $slugCheck = end($slugCheck);
                if ($url->slug() === $slugCheck) {
                    $activeClass = ' active';
                }
            }
            echo '<li class="nav-item">';
            echo '<a class="nav-link'.$activeClass.'" href="'.htmlspecialchars($catHref,ENT_QUOTES).'">'.blowfish_text($catTitle).'</a>';
            echo '</li>';
        }
    }
}
?>

4.6 增加公式前台解析

KaTeX 是目前最快的 LaTeX 渲染库,体积小、渲染速度快,完全满足博客常规公式需求。

只需要修改主题的 php/footer.php(或 index.php 底部 </body> 之前),插入以下代码:


<!-- KaTeX 样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
<!-- KaTeX 核心 JS -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
<!-- 自动扫描渲染插件 -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js"
  onload="renderMathInElement(document.body, {
    delimiters: [
      {left: '$$', right: '$$', display: true},   // 块级公式
      {left: '$', right: '$', display: false},     // 行内公式
      {left: '\\(', right: '\\)', display: false},
      {left: '\\[', right: '\\]', display: true}
    ],
    throwOnError: false
  });">
</script>

五、关键踩坑总结(避坑核心)

  1. Bludit子模板严禁直接调用插件方法:会直接白屏,必须通过全局GLOBALS读取。
  2. 栅格空DOM不删除,样式修改无效:去侧边栏必须删栅格容器,仅注释无用。
  3. 不要滥用主题原生API:子模板作用域有限,优先复用插件输出,规避类加载报错。
  4. Bootstrap下拉必须补全交互JS:仅靠CSS无法点击,主题默认缺失Popper。
  5. 默认下拉样式不兼容深色主题,必须手动重写配色。

六、改造最终闭环总结

本次改造实现了 Blowfish主题从“博客静态展示”到“完整CMS栏目站点” 的蜕变:

冗余侧边栏去除 → 内容视野最大化 → 缺失的分类导航补齐 → 栏目下拉收纳防溢出 → 交互样式适配修复 → 全站逻辑闭环、无BUG、可长期复用。

所有修改均为轻量化改造,不破坏主题原生功能、不新增插件、不产生冗余代码,适配主题更新,后续重装主题可直接复用全套方案。


以上为本人对问题的解决路径与总结,结果为AI总结 请谨慎判断!

general Bluditcms Blowfish
Share X (Twitter) Reddit LinkedIn