В качестве альтернативы принятому ответу, здесь два разных подхода, над которыми я работал ...
#menuList li
- это контейнер для списка пунктов меню <a>
, которые имеют смежные <ul>
суб- Пункты меню. Для облегчения выбора с помощью CSS я назначил класс .menu-item
этим <a>
.
CSS logi c для обеих версий по существу одинаковы:
- установить
.menu-item
смежные ul
элементы подменю, скрытые по умолчанию - определить
:hover
цвета - определить цвета для выбранного
.menu-item
и смежных ul
(либо :focus
, либо .selected
истинно) - make
.menu-item
смежные ul
элементы подменю, видимые при выборе .menu-item
(то же самое)
Разница: для CSS только мы используем селектор :focus
, для CSS с Javascript мы используем класс .selected
.
CSS только (автоматически c фокус и размытие )
<a>
получает фокус при нажатии (например, кнопка, ввод и т. д. c . :focus
это истина ). Когда пользователь щелкает / касается вне выделенного элемента, он снова автоматически теряет фокус (получает размытие и :focus
равно false , как в : not (: focus) = ' размытие '). Мы можем использовать селектор CSS :focus
для обработки пользовательских кликов и изменения элементов, MDN: ': focus' .
CSS с Javascript ( focus и blur по запросу)
OP хочет, чтобы выбранный .menu-item
и прилегающие к нему ul
подменю оставались видимыми до тех пор, пока пользователь специально отменяет выбор снова. Это невозможно сделать с помощью селектора :focus
, поэтому мы игнорируем этот селектор и используем вместо него класс .selected
для обработки требований focus и blur , MDN: HTMLElement. blur () .
Javascript logi c довольно прост:
Прикрепите «щелчок» - eventListener
( MDN: Элемент: событие щелчка ) в основной контейнер #menuList
обработка:
- когда выбирается
.menu-item
, и это в настоящее время .selected
, затем размытие it (menuItemBlur()
) - иначе
- когда у нас есть ранее выбранный
.menu-item
open, blur тот первый (menuItemBlur()
) - а затем фокус вновь выбранный
.menu-item
(menuItemFocus()
)
Изменения в коде OP
- удалены ненужные CSS
- удалены ненужные
class
атрибуты из HTML - изменено
href="#"
в <#menuList li a>
на href="javascript:void(0)"
, чтобы предотвратить создание записи в истории браузера (пункты подменю будут по-прежнему Я создаю запись).
Приведенный ниже фрагмент сильно прокомментирован и не требует пояснений.
'use-strict';
var activeItem; // Holds the currently '.selected''.submenu' (null/undefined if none)
// Attach 'click' event listener to the #menuList
document.getElementById('menuList')
.addEventListener('click', function(e) { menuItemToggle(e.target) });
function menuItemToggle(el) {
if (el.classList.contains('menu-item2')) { // When a '.menu-item' gets clicked (not its kids)
if (el.classList.contains('selected')) { // and it is the '.selected''.menu-item'
menuItemBlur(el); // then close it and remove focus()
}
else {
if (activeItem) // When there is a currently selected '.menu-item'
menuItemBlur(activeItem); // then deactivate it
menuItemFocus(el); // Now activate the clicked `.menu-item`
};
};
function menuItemBlur(el) {
el.classList.remove("selected"); // Set the '.menu-item' to not '.selected'
activeItem = null; // and remove the reference to it
el.blur(); // Remove focus from element for CSS ':focus'
// ...extend with other 'Blur' stuff...
};
function menuItemFocus(el) {
el.classList.add("selected"); // Set the '.menu-item' to '.selected'
activeItem = el; // and save a reference to it
// ...extend with other 'Focus' stuff...
};
};
.sidebar {
position: fixed;
width: 250px;
height: 100%;
left: 0px;
top: 0;
background: #1b1b1b;
font-family: sans-serif;
}
.menu-bar {
background: #1b1b1b;
height: 60px;
display: flex;
align-items: center;
padding-left: 42px;
}
.side-text {
color: #c5c5c5;
font-weight: bold;
font-size: 20px;
}
nav ul {
background: #1b1b1b;
height: 100%;
width: 100%;
list-style: none;
margin-left: 0;
padding-left: 0;
}
nav ul li {
line-height: 40px;
}
nav ul li a {
position: relative;
color: #c5c5c5;
text-decoration: none;
font-size: 14px;
padding-left: 43px;
font-weight: normal;
display: block;
width: 100%;
}
nav ul ul {
position: static;
display: none;
}
nav ul ul li a {
font-family: sans-serif;
font-size: 13px;
color: #e6e6e6;
padding-left: 80px;
font-weight: lighter;
}
/*************/
/* ADDED CSS */
/*************/
/* All classes starting with "menu-item" */
[class^="menu-item"] + ul { display: none } /* hide adjacent UL */
[class^="menu-item"]:hover { color: #255daa } /* hover color */
a + ul li a:hover { color: #c5c5c5; background-color: #1b1b1b }
/*
menu-item adjacent sub-menu-items hover colors
Here the generic form is used, but it would
probably be more clear to be specific and use:
- either .menu-item1:focus + ul li a:hover
- or .menu-item2.selected + ul li a:hover
*/
/*
':focus' version
This version uses the CSS ':focus' without any Javascript.
Main difference with the '.selected' version below is that when the
user clicks outside the '.menu-item', the '.menu-item' looses focus
and therefore gets hidden again (as :focus is no longer true).
*/
.menu-item1:focus,
.menu-item1:focus + ul { color: #e6e6e6; background-color: #255DAA } /* focus colors */
.menu-item1:focus + ul { display: block } /* show adjacent UL */
/*
'.selected' version, with Javascript.
Basically the same CSS, but now using class '.selected' instead of ':focus'.
Closing occurs only on user specific 'click'.
*/
.menu-item2.selected,
.menu-item2.selected + ul { color: #e6e6e6; background-color: #255DAA } /* focus colors */
.menu-item2.selected + ul { display: block } /* show adjacent UL */
/*********************/
/* for demo use only */
/*********************/
nav h3 {
color: rgba(100, 149, 237,.9); /* CornflowerBlue */
font-style: italic;
padding-left: 43px;
}
.anchor {
color: white;
padding-left: 43px;
}
.content {
font-size: 1.5rem;
margin: 5rem 300px;
}
/* preferred globals */
html,body { box-sizing: border-box; width: 100%; max-width: 100% }
*::before,*::after, * { box-sizing: inherit }
body { margin: 0 }
<nav class="sidebar">
<div class="menu-bar">
<label class="side-text">MENU</label>
</div>
<h3>test</h3>
<a class="anchor" href="javascript:void(0)">some '.sidebar' <a></a>
<ul id="menuList">
<h3>:focus version</h3>
<li>
<a class="menu-item1" href="javascript:void(0)">Staff</a>
<ul>
<li><a href="#">New Staff</a></li>
<li><a href="#">View Staff</a></li>
</ul>
</li>
<li>
<a class="menu-item1" href="javascript:void(0)">Notes</a>
<ul>
<li><a href="#">New Note</a></li>
<li><a href="#">Edit Notes</a></li>
</ul>
</li>
<li>
<a class="menu-item1" href="javascript:void(0)">Tasks</a>
<ul>
<li><a href="#">New Tasks</a></li>
<li><a href="#">Edit Task</a></li>
</ul>
</li>
<h3>.selected version</h3>
<li>
<a class="menu-item2" href="javascript:void(0)">Staff</a>
<ul>
<li><a href="#">New Staff</a></li>
<li><a href="#">View Staff</a></li>
</ul>
</li>
<li>
<a class="menu-item2" href="javascript:void(0)">Notes</a>
<ul>
<li><a href="#">New Note</a></li>
<li><a href="#">Edit Notes</a></li>
</ul>
</li>
<li>
<a class="menu-item2" href="javascript:void(0)">Tasks</a>
<ul>
<li><a href="#">New Tasks</a></li>
<li><a href="#">Edit Task</a></li>
</ul>
</li>
</ul>
</nav>
<div class="content">
<h3><b>Note</b></h3>
<p>
This demo uses two different approaches interchangeably creating a quirky behaviour,
which under normal circumstances would not exist.
</p>
<p>To reproduce:</p>
<ul>
<li>select a <i>':focus version'</i> menu item first
<li>then select a <i>'.selected version'</i> menu item
</ul>
<p>
As you can see, the selected <i>':focus version'</i> loses focus and a second
'click' is needed to activate the <i>'.selected version'</i> menu item.
This is because the first click event of the <i>'.selected version'</i> gets consumed by the blur event
of the <i>':focus version'</i>.
</p>
<p>Just so you know...</p>
</div>