Vor einiger Zeit wurde in der Joomla Community gefragt, ob man ein Offcanvas-Menü im Cassiopeia Template einbauen kann. Ich habe dann auf die Schnelle ein bisschen Code geschrieben (https://gist.github.com/drmenzelit/152a1954d73bcbe126194965e43c97f4), das prinzipiell funktioniert. Aber es kamen immer mehr Fragen, Wünsche und Verbesserungsideen dazu.
In diesem Beitrag stelle ich eine verbesserte Version des Offcanvas-Menüs vor, mit Logo und eine extra Modulposition. Es gibt zwei Varianten vom Menü:
- offcanvas.php: für ein einfaches Menü ohne Unterpunkte
- offcanvas-metismenü.php: für ein Dropdown Menü
In beiden Varianten ist jetzt die Besonderheit, dass das Logo aus dem Template und Module, die in der Position offcanvas veröffentlicht sind, im Offcanvas-Menü angezeigt werden. Die Klasse d-lg-none sorgt dafür, dass diese Elemente nur im Offcanvas Modus angezeigt werden. Die Klasse ist passend zur navbar-expand-lg gewählt. Diese Klassen können natürlich beliebig geändert werden.
Die Dateien werden unter templates/cassiopeia/html/mod_menu/ angelegt.
Einfaches Offcanvas
offcanvas.php
Im Menü Modul das Layout offcanvas wählen.
<?php
/**
* @package Joomla.Site
* @subpackage mod_menu
*
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\ModuleHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
HTMLHelper::_('bootstrap.offcanvas');
$app = Factory::getApplication('site');
$template = $app->getTemplate(true);
$sitename = htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8');
if ($template->params->get('logoFile')) {
$logo = HTMLHelper::_('image', Uri::root(false) . htmlspecialchars($template->params->get('logoFile'), ENT_QUOTES), $sitename, ['loading' => 'eager', 'decoding' => 'async'], false, 0);
} elseif ($template->params->get('siteTitle')) {
$logo = '<span title="' . $sitename . '">' . htmlspecialchars($template->params->get('siteTitle'), ENT_COMPAT, 'UTF-8') . '</span>';
} else {
$logo = HTMLHelper::_('image', 'logo.svg', $sitename, ['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'], true, 0);
}
?>
<nav class="navbar navbar-expand-lg">
<button class="navbar-toggler navbar-toggler-right" type="button" data-bs-toggle="offcanvas" data-bs-target="#navbar<?php echo $module->id; ?>" aria-controls="navbar<?php echo $module->id; ?>" aria-expanded="false" aria-label="<?php echo Text::_('MOD_MENU_TOGGLE'); ?>">
<span class="icon-menu" aria-hidden="true"></span>
</button>
<div class="offcanvas offcanvas-start" id="navbar<?php echo $module->id; ?>">
<div class="offcanvas-header">
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<div class="d-lg-none mb-3">
<a class="brand-logo" href="/<?php echo Uri::root(true); ?>/">
<?php echo $logo; ?>
</a>
</div>
<?php require ModuleHelper::getLayoutPath('mod_menu', 'default'); ?>
<div class="d-lg-none mt-3">
<?php
$modules = ModuleHelper::getModules('offcanvas');
foreach ($modules as $module) {
echo ModuleHelper::renderModule($module, []);
}
?>
</div>
</div>
</div>
</nav>
Desktop Ansicht:
Mobile Ansicht:
Mobile Ansicht geöffnet:
In der Position offcanvas habe ich das Suchindex Modul veröffentlicht:
Dropdown Offcanvas
offcanvas-metismenu.php
Im Menü Modul das Layout offcanvas-metismenu wählen.
<?php
/**
* @package Joomla.Site
* @subpackage mod_menu
*
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\ModuleHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
HTMLHelper::_('bootstrap.offcanvas');
$app = Factory::getApplication('site');
$template = $app->getTemplate(true);
$sitename = htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8');
if ($template->params->get('logoFile')) {
$logo = HTMLHelper::_('image', Uri::root(false) . htmlspecialchars($template->params->get('logoFile'), ENT_QUOTES), $sitename, ['loading' => 'eager', 'decoding' => 'async'], false, 0);
} elseif ($template->params->get('siteTitle')) {
$logo = '<span title="' . $sitename . '">' . htmlspecialchars($template->params->get('siteTitle'), ENT_COMPAT, 'UTF-8') . '</span>';
} else {
$logo = HTMLHelper::_('image', 'logo.svg', $sitename, ['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'], true, 0);
}
?>
<nav class="navbar navbar-expand-lg">
<button class="navbar-toggler navbar-toggler-right" type="button" data-bs-toggle="offcanvas" data-bs-target="#navbar<?php echo $module->id; ?>" aria-controls="navbar<?php echo $module->id; ?>" aria-expanded="false" aria-label="<?php echo Text::_('MOD_MENU_TOGGLE'); ?>">
<span class="icon-menu" aria-hidden="true"></span>
</button>
<div class="offcanvas offcanvas-start" id="navbar<?php echo $module->id; ?>">
<div class="offcanvas-header">
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<div class="d-lg-none mb-3">
<a class="brand-logo" href="/<?php echo Uri::root(true); ?>/">
<?php echo $logo; ?>
</a>
</div>
<?php require __DIR__ . '/dropdown-metismenu.php'; ?>
<div class="d-lg-none mt-3">
<?php
$modules = ModuleHelper::getModules('offcanvas');
foreach ($modules as $module) {
echo ModuleHelper::renderModule($module, []);
}
?>
</div>
</div>
</div>
</nav>
Mobile Ansicht mit Dropdown:
Das passende CSS dazu:
.offcanvas.show {
background-color: var(--cassiopeia-color-primary);
background-image: linear-gradient(135deg,var(--cassiopeia-color-primary),var(--cassiopeia-color-hover));
}
@media (min-width: 992px) {
.offcanvas-start {
width: 100%;
}
}
@media (max-width: 991.98px) {
.offcanvas .metismenu.mod-menu .metismenu-item > ul {
position: relative;
width: 100%;
margin-top: 1rem;
}
.offcanvas .metismenu.mod-menu .mm-collapse {
background-color: transparent;
}
.offcanvas .metismenu.mod-menu .metismenu-item > a {
color: #fff;
}
}
.offcanvas-header > *:only-child {
margin-left: auto;
}
Hier kann man auch beliebig Änderungen machen, z.B. andere Hindergrundfarbe für den Offcanvas-Bereich. Falls man einen helleren Hintergrund wählt, sollte man die Klasse btn-close-white entfernen.
Weitere Möglichkeiten können in der Dokumentation von Bootstrap gelesen werden:
https://getbootstrap.com/docs/5.3/components/offcanvas/
https://getbootstrap.com/docs/5.3/components/navbar/#offcanvas