Реализация верхнего меню

347
20 января 2017, 08:21

На днях набросал код верхнего меню без использования скриптов. Всё работает на ура, но правильно ли это? Дело в том, что я использовал для стилизации input type="checkbox", pointer-events: none; и много чего ещё. Имеет ли такая реализация место в проектах или всё же лучше использовать JS для таких ситуаций?

Код меню:

body { 
  font-family: Tahoma, Arial 
} 
.topbar { 
  display: flex; 
  position: fixed; 
  top: 0; 
  left: 0; 
  width: 100%; 
  height: 40px; 
  background-color: white; 
  border-bottom: 2px solid rgba(0, 0, 0, 0.08); 
} 
.topbar__button-open-leftmenu { 
  display: block; 
  width: 24px; 
  height: 24px; 
  padding: 8px; 
  cursor: pointer; 
} 
.topbar__button-open-leftmenu:hover { 
  border-bottom: 2px solid #1C90F3; 
} 
.topbar__button-open-leftmenu svg path { 
  fill: #333; 
} 
.topbar__button-open-leftmenu:hover svg path { 
  fill: #000; 
} 
.topbar__memu { 
  display: flex; 
  list-style: none; 
  padding: 0; 
  margin: 0 auto 0 0; 
  opacity: 1; 
  transform: translateX(0); 
  transition: all 0.4s ease; 
  pointer-events: auto; 
} 
#topbar__checked-search:checked ~ .topbar__memu { 
  transform: translateX(-10%); 
  opacity: 0; 
  pointer-events: none; 
} 
.topbar__memu-item { 
  display: block; 
  height: 40px; 
  padding: 0 10px; 
  line-height: 40px; 
  font-size: 0.8rem; 
  color: #333; 
  text-decoration: none; 
} 
.topbar__memu-item:hover { 
  color: #000; 
  border-bottom: 2px solid #1C90F3; 
} 
.topbar__button-open-search { 
  display: block; 
  position: relative; 
  width: 40px; 
  height: 40px; 
} 
.topbar__button-open-search:hover { 
  background-color: #f5f5f5; 
} 
.topbar__button-open-search svg { 
  position: absolute; 
  top: 10px; 
  left: 10px; 
  width: 20px; 
  height: 20px; 
} 
.topbar__button-open-search svg path { 
  fill: #333; 
} 
.topbar__button-open-search:hover svg path { 
  fill: #000; 
} 
.topbar__button-open-search svg#icon-serach-close { 
  opacity: 1; 
  transition: all 0.4s ease; 
} 
.topbar__button-open-search svg#icon-serach-open { 
  opacity: 0; 
  transition: all 0.4s ease; 
} 
#topbar__checked-search:checked ~ .topbar__button-open-search svg#icon-serach-close { 
  opacity: 0; 
  transition: all 0.4s ease; 
} 
#topbar__checked-search:checked ~ .topbar__button-open-search svg#icon-serach-open { 
  opacity: 1; 
  transition: all 0.4s ease; 
} 
#topbar__checked-search { 
  display: none; 
} 
.topbar__search { 
  display: block; 
  position: absolute; 
  left: 50%; 
  top: 0; 
  width: 60%; 
  height: 30px; 
  padding: 5px; 
  opacity: 0; 
  transform: translateX(-40%); 
  transition: transform 0.4s ease, opacity 0.4s ease; 
  pointer-events: none; 
} 
#topbar__checked-search:checked ~ .topbar__search { 
  transform: translateX(-50%); 
  opacity: 1; 
  pointer-events: auto; 
} 
.topbar__search-input { 
  display: block; 
  width: calc(100% - 40px); 
  height: 30px; 
  padding: 0 30px 0 10px; 
  border: none; 
  border-radius: 3px; 
  background-color: #f4f4f4; 
  font-family: inherit; 
  outline: none; 
  transition: background 0.2s ease; 
} 
.topbar__search-input:focus { 
  background-color: #eeeeee; 
} 
.topbar__search-button { 
  display: block; 
  position: absolute; 
  top: 11px; 
  right: 12px; 
  width: 18px; 
  height: 18px; 
  padding: 0; 
  background: none; 
  border: none; 
  cursor: pointer; 
} 
.topbar__search-button svg path { 
  fill: #333; 
} 
.topbar__search-button:hover svg path { 
  fill: #000; 
} 
.topbar__search-panel { 
  display: block; 
  position: fixed; 
  top: 42px; 
  left: 0px; 
  width: 100%; 
  height: calc(100vh - 42px); 
  background-color: rgba(0, 0, 0, 0.6); 
  opacity: 0; 
  pointer-events: none; 
  transition: opacity 0.4s ease; 
} 
#topbar__checked-search:checked ~ .topbar__search-panel { 
  opacity: 1; 
  pointer-events: auto; 
} 
.topbar__search-panel-list { 
  display: block; 
  position: absolute; 
  top: 10px; 
  left: 50%; 
  width: 60%; 
  padding: 5px 0; 
  border-radius: 2px; 
  transform: translateX(-50%) translateY(-20%); 
  background-color: white; 
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); 
  transition: transform 0.4s ease; 
} 
#topbar__checked-search:checked ~ .topbar__search-panel .topbar__search-panel-list { 
  transform: translateX(-50%) translateY(0%); 
} 
.topbar__search-panel-list:before { 
  display: block; 
  content: 'Результаты поиска:'; 
  font-size: 0.8rem; 
  padding: 3px 10px; 
  margin: 0 0 5px 0; 
  color: #acacac; 
  border-bottom: 1px solid #f2f2f2; 
} 
.topbar__search-panel-list-item { 
  display: block; 
  font-size: 0.8rem; 
  padding: 3px 10px; 
  color: #333; 
  text-decoration: none; 
} 
.topbar__search-panel-list-item:hover { 
  background-color: #f4f4f4; 
} 
/* Leftmenu */ 
 
.leftmenu { 
  display: block; 
  position: fixed; 
  top: 42px; 
  left: 0px; 
  width: 100%; 
  height: calc(100vh - 42px); 
  background-color: rgba(0, 0, 0, 0.6); 
  opacity: 0; 
  pointer-events: none; 
  transition: opacity 0.4s ease; 
} 
#topbar__checked-leftmenu:checked + .leftmenu { 
  opacity: 1; 
  pointer-events: auto; 
} 
.leftmenu__list { 
  display: block; 
  position: absolute; 
  left: -200px; 
  width: 200px; 
  height: 100%; 
  margin: 0; 
  padding: 0; 
  background-color: white; 
  transition: left 0.4s ease; 
} 
#topbar__checked-leftmenu:checked + .leftmenu .leftmenu__list { 
  left: 0; 
} 
.leftmenu__list-item { 
  display: block; 
  padding: 6px 12px; 
  font-size: 0.8rem; 
  color: #333; 
  text-decoration: none; 
} 
.leftmenu__list-item:hover { 
  background-color: #f4f4f4; 
} 
.leftmenu__hidemenu { 
  display: block; 
  position: absolute; 
  left: 200px; 
  top: 0; 
  width: calc(100% - 200px); 
  height: 100%; 
}
<div class="topbar"> 
  <label for="topbar__checked-leftmenu" class="topbar__button-open-leftmenu"> 
    <svg viewBox="0 0 32 32"> 
      <path d="M 16 6 C 14.895431 6 14 6.8954305 14 8 C 14 9.1045695 14.895431 10 16 10 C 17.104569 10 18 9.1045695 18 8 C 18 6.8954305 17.104569 6 16 6 z M 16 14 C 14.895431 14 14 14.895431 14 16 C 14 17.104569 14.895431 18 16 18 C 17.104569 18 18 17.104569 18 16 C 18 14.895431 17.104569 14 16 14 z M 16 22 C 14.895431 22 14 22.895431 14 24 C 14 25.104569 14.895431 26 16 26 C 17.104569 26 18 25.104569 18 24 C 18 22.895431 17.104569 22 16 22 z"></path> 
    </svg> 
  </label> 
  <input type="checkbox" id="topbar__checked-search"> 
  <ul class="topbar__memu"> 
    <li><a href="" class="topbar__memu-item">Пункт 1</a> 
    </li> 
    <li><a href="" class="topbar__memu-item">Пункт 2</a> 
    </li> 
    <li><a href="" class="topbar__memu-item">Пункт 3</a> 
    </li> 
  </ul> 
  <div class="topbar__search"> 
    <input type="text" class="topbar__search-input" placeholder="Найти..."> 
    <button class="topbar__search-button"> 
      <svg version="1" viewBox="0 0 24 24" enable-background="new 0 0 24 24"> 
        <path d="M 9 2 C 5.1 2 2 5.1 2 9 C 2 12.9 5.1 16 9 16 C 10.722428 16 12.28779 15.386196 13.5 14.375 L 14 14.875 L 14 15.6875 L 20.3125 22 L 22 20.3125 L 15.6875 14 L 14.8125 14 L 14.34375 13.53125 C 15.372135 12.314388 16 10.738606 16 9 C 16 5.1 12.9 2 9 2 z M 9 4 C 11.8 4 14 6.2 14 9 C 14 11.8 11.8 14 9 14 C 6.2 14 4 11.8 4 9 C 4 6.2 6.2 4 9 4 z"></path> 
      </svg> 
    </button> 
  </div> 
  <label for="topbar__checked-search" class="topbar__button-open-search"> 
    <svg id="icon-serach-close" version="1" viewBox="0 0 24 24" enable-background="new 0 0 24 24"> 
      <path d="M 9 2 C 5.1 2 2 5.1 2 9 C 2 12.9 5.1 16 9 16 C 10.722428 16 12.28779 15.386196 13.5 14.375 L 14 14.875 L 14 15.6875 L 20.3125 22 L 22 20.3125 L 15.6875 14 L 14.8125 14 L 14.34375 13.53125 C 15.372135 12.314388 16 10.738606 16 9 C 16 5.1 12.9 2 9 2 z M 9 4 C 11.8 4 14 6.2 14 9 C 14 11.8 11.8 14 9 14 C 6.2 14 4 11.8 4 9 C 4 6.2 6.2 4 9 4 z"></path> 
    </svg> 
    <svg id="icon-serach-open" viewBox="0 0 32 32"> 
      <path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;-inkscape-font-specification:Bitstream Vera Sans" d="M 8.71875 7.28125 L 7.28125 8.71875 L 14.5625 16 L 7.28125 23.28125 L 8.71875 24.71875 L 16 17.4375 L 23.28125 24.71875 L 24.71875 23.28125 L 17.4375 16 L 24.71875 8.71875 L 23.28125 7.28125 L 16 14.5625 L 8.71875 7.28125 z" 
      color="#000" overflow="visible" font-family="Bitstream Vera Sans"></path> 
    </svg> 
  </label> 
  <div class="topbar__search-panel"> 
    <div class="topbar__search-panel-list"> 
      <a href="#" class="topbar__search-panel-list-item">Обои для рабочего стола</a> 
      <a href="#" class="topbar__search-panel-list-item">Новости</a> 
      <a href="#" class="topbar__search-panel-list-item">StackOverflow</a> 
    </div> 
  </div> 
</div> 
<input type="checkbox" id="topbar__checked-leftmenu"> 
<div class="leftmenu"> 
  <ul class="leftmenu__list"> 
    <li><a href="#" class="leftmenu__list-item">Пункт 1</a> 
    </li> 
    <li><a href="#" class="leftmenu__list-item">Пункт 2</a> 
    </li> 
    <li><a href="#" class="leftmenu__list-item">Пункт 3</a> 
    </li> 
  </ul> 
  <label for="topbar__checked-leftmenu" class="leftmenu__hidemenu"></label> 
</div>

Если кто знает, как реализовать такое более качественно, то буду рад поучиться :)

Answer 1

В современном web приложении js кода непомерно много, и, моё мнение - если есть возможность писать без js - пишите без js. В том числе и меню.

  1. Если вы напишете на css меню - оно будет быстрее.
  2. Вероятность краша программы, который остановит всю работу приложения будет существенно снижена.
  3. Написать css меню быстрее чем на js.

Когда стоит написать меню js.
Вам надо написать крутое меню которое имеет ряд функционала (нажатие по кнопки как описано выше, задержка при потере курсора мыши, итд).

Но все простые всплывашки если можно обойтись без js надо писать без js. Это не только моё мнение, детально, почему стоит уменьшить объём js кода рассказано в этой статье.

Answer 2

Использование <input type="checkbox" /> + <label> — это в первую очередь хак. У данного приема есть, по-моему, только одно использование без нарушения семантики — это кастомные чекбоксы и радиокнопки. Во всех остальных случаях, использование такого приема при возможности сделать семантическую разметку является плохим тоном, потому что:

  1. Страдает доступность; ваше меню недоступно при помощи клавиатуры, а следовательно и для экранных читалок. Незрячих людей или людей с проблемами со зрением, которые пользуются специальным софтом и устройствами, гораздо больше, чем может казаться, а в некоторых западных странах доступность является государственным требованием.

  2. Появляется дополнительная разметка.

  3. Модульность кода ставится под сомнение, поскольку появляются дополнительные жестко связанные между собой элементы.

  4. Чекбокс используется вне формы и не по назначению (т. е. не служит для отправки массива данных на сервер), что, вероятно, может вызвать проблемы в какой-нибудь CMS, которая автоматически оборачивает элементы формы тегом <form> (первое, что приходит в голову).

P.S. прятать меню за кнопкой-гамбургером само по себе сомнительное UI-решение.

Answer 3

По мне, такое решение - не совсем оправдано. Оно может иметь место в качестве материала для общего развития, тренировок, но не для релизного проекта. Почему? Потому что это велосипед, хак, который сложно контролировать, в том плане, если вы открыли где-нибудь пункт меню, то как связать это с остальными элементами? Через JS, очевидно. А раз использование этого подразумевает скрипты, то проще и решить это скриптами. Тем более, что для меню это пара строчек.
- Доводы в пользу того, что мол а как же мобильные юзвери - нынешние мобилки помощнее среднего пк пару лет назад, поедать код тоннами они научены, не думаю, что стоит экономить на наносекундах, получая в ответ негибкое, плохо масштабируемое решение.
- Про то что контент не индексируется, это бред, гуголь давно всему научился.
- "Если JS" упадет - это приведет к останову всей страницы. Тоже сомнительно. Не в том плане, что не приведет, а в том, что непоставленная скобка, что в JS, что в CSS приведет к неправильной работе компонентов, отсюда - проблема выедена из яйца. (Да и мы ведь не кидаем код в продакшн, предварительно не протестив его, верно?)
- "JS требует времени на разработку" - css does the same. CSS также нуждается во времени на верстку, разработку, подгонку, разница лишь в том, что JS предоставляет куда более обширный инструментарий, позволяя решать идентичные задачи быстрее.

READ ALSO
content не работает в less

content не работает в less

Есть такой код:

276
Как работает alignas()?

Как работает alignas()?

Никак не могу понять как работает alignas()Почему расстояние равно 2016, а без него 24?

310
Вылетает QWebEngineView

Вылетает QWebEngineView

ЗдравствуйтеПишу небольшой клиент вк и мне надо для авторизации открыть сайт для подтверждения

397