Навигация – одно из самых проблематичных мест при реализации качественного адаптивного дизайна. В качестве предисловия к этой статье я настоятельно рекомендую изучить следующие материалы от Брэда Фроста: набор адаптивных навигационных паттернов и комплексные навигационные паттерны. В этой статье я раскрою два метода переключения (toggle), предназначенных для создания адаптивной навигации в WordPress.
Общие адаптивные навигационные паттерны в WordPress
Вообще, есть довольно много различных подходов к созданию адаптивной навигации. Наряду с подходом «ничего не делать», метод переключения является одним из наиболее популярных методов реализации навигации, виденных мной в темах WordPress.
Метод переключения обычно представлен кнопкой с текстом или иконкой «гамбургера», заменяющей встроенный метод навигации, когда размер экрана ужимается до определенного размера. Триггер для метода переключения – то, на чем я хочу сфокусировать свое внимание.
Первый метод переключения – изменение размеров c помощью jQuery на базе ширины окна
Я использовал метод, очень похожий на описанный далее, еще с тех пор, как я увидел его в _s теме более года назад. По существу, триггер обрабатывается путем определения ширины окна с помощью $( window ).width(). Я разберу несколько обновленную версию этого кода ниже, а пока вы можете увидеть этот метод в действии на Github Gist.
Когда ширина окна превышает 600px, используется класс main-navigation, а когда ширина окна становится меньше 600px, для меню используется класс main-small-navigation. Кроме того, h1, используемый для вспомогательного текста (что сделано с целью удобства просмотра), меняется при переключении меню и является текстом, связанным с функцией jQuery .click.
Именно поэтому меню может быть превращено в активируемый по клику переключаемый метод навигации для небольших экранов.
Это достаточно удобное решение, однако используется оно не так часто. У него есть определенная сложность – необходимо тщательно подгонять пиксельное значение той границы, за которой меню будет изменяться. Этот метод будет идеальным, если вы формируете родительскую тему из стартеров, таких как _s, однако в идеале лучше воспользоваться родительскими темами, поддерживающими дочерние темы и детальную настройку. Мы можем сделать фиксированные значения фильтруемыми с помощью PHP, используя wp_localize_script.
Интеграция wp_localize_script для достижения гибкости
Ниже приведен пример альтернативного JS-файла и соответствующего подключения, использующего wp_localize_script для последующей PHP-фильтрации фиксированных значений.
/** * Обрабатывает переключение основного навигационного меню для небольших экранов. * small_menu_vars.size используется вместо "600" или других фиксированных пиксельных значений – оно определяется при помощи wp_localize_script в функциях */ jQuery( document ).ready( function( $ ) { var $masthead = $( '#masthead' ), timeout = false; $.fn.smallMenu = function() { $masthead.find( '.site-navigation' ).removeClass( 'main-navigation' ).addClass( 'main-small-navigation' ); $masthead.find( '.site-navigation h1' ).removeClass( 'assistive-text' ).addClass( 'menu-toggle' ); $( '.menu-toggle' ).click( function() { $masthead.find( '.menu' ).toggle(); $( this ).toggleClass( 'toggled-on' ); } ); }; // Определяем ширину области просмотра при первой загрузке if ( $( window ).width() < small_menu_vars.size ) $.fn.smallMenu(); // Определяем ширину области просмотра, когда пользователь изменил размеры окна // браузера $( window ).resize( function() { var browserWidth = $( window ).width(); if ( false !== timeout ) clearTimeout( timeout ); timeout = setTimeout( function() { if ( browserWidth < small_menu_vars.size ) { $.fn.smallMenu(); } else { $masthead.find( '.site-navigation' ).removeClass( 'main-small-navigation' ).addClass( 'main-navigation' ); $masthead.find( '.site-navigation h1' ).removeClass( 'menu-toggle' ).addClass( 'assistive-text' ); $masthead.find( '.menu' ).removeAttr( 'style' ); } }, 200 ); } ); } );
Вы можете использовать переменную small_menu_vars.size вместо зафиксированного ранее пиксельного значения. Эта переменная способна использовать динамические данные благодаря великолепной функции wp_localize_script, которая так прекрасно была рассмотрена Pippin Williamson в прошлом году. Я считаю, что такой вариант использования может оказаться достаточно полезным, особенно если его применять в родительских темах.
Если перенестись к нашему примеру, то, чтобы использовать эту переменную, мы должны соответствующим образом настроить нашу переменную с помощью wp_localize_script. Вот код, который покажется вам знакомым, если вы прочли руководство Williamson:
<?php /** * Регистрируем скрипты для темы и подключаем их на сайте. * * @since 0.1.0. */ add_action( 'wp_enqueue_scripts', 'krogs_theme_scripts' ); function krogs_theme_scripts() { wp_register_script( 'small-menu', get_template_directory_uri() . '/js/small-menu.js', array( 'jquery' ), '20120206', true ); wp_localize_script('small-menu', 'small_menu_vars', array( 'size' => apply_filters( 'krogs_theme_small_menu_size', 600 ) ) ); wp_enqueue_script( 'small-menu' ); }
Заметили фильтр? Именно здесь и начинается самое интересное. Теперь мы можем сделать число, которое раньше нам нужно было фиксировать вручную, фильтруемым из дочерних тем. Вот пример фильтра:
<?php /** * функция krogs_child_theme_new_menu_size. * */ add_filter( 'krogs_theme_small_menu_size', 'krogs_child_theme_new_menu_size' ); function krogs_child_theme_new_menu_size( $size ) { $size = 450; return 450; }
Теперь ваши дочерние темы могут легко изменить точку перехода для адаптивной навигации без отключения старого файла и подключения нового.
Второй метод переключения – JavaScript и медиа-запросы CSS
Предыдущий скрипт действительно завязан на jQuery, и если ваш проект не требует подключения этой библиотеки (что маловероятно в наши дни), то в таком случае вы можете взглянуть на альтернативное решение. Или, возможно, у вас возникла идея обработки точки перехода более качественным способом с помощью CSS медиа-запросов.
Последняя навигационная итерация в теме _s использует JavaScript реализацию, позволяющую идентифицировать текущее состояние разметки страницы и сделать CSS-основанное переключаемое меню очень простым.
Для начала давайте посмотрим на разметку навигации.
<header id="masthead" class="site-header" role="banner"> <div class="site-branding"> <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1> <h2 class="site-description"><?php bloginfo( 'description' ); ?></h2> </div> <nav id="site-navigation" class="main-navigation" role="navigation"> <h1 class="menu-toggle"><?php _e( 'Menu', '_s' ); ?></h1> <div class="screen-reader-text skip-link"><a href="#content" title="<?php esc_attr_e( 'Skip to content', '_s' ); ?>"><?php _e( 'Skip to content', '_s' ); ?></a></div> <?php wp_nav_menu( array( 'theme_location' => 'primary' ) ); ?> </nav><!-- #site-navigation --> </header><!-- #masthead -->
Первое, что вы должны заметить: класс menu-toggle стоит в h1 с самого начала. Все, что сделает наш Javascript – это активирует функцию click для h1, используя переключаемый класс. Само переключаемое меню (h1) скрыто по умолчанию с помощью display: none; и меняется с помощью медиа-запроса для ширины max-width: 600px на display: block;. В то же самое время наше стандартное меню скрыто по умолчанию и отображается только тогда, когда активирован переключаемый класс.
/* Небольшое меню */ .menu-toggle { display: none; cursor: pointer; } @media screen and (max-width: 600px) { .menu-toggle, .main-navigation.toggled .nav-menu { display: block; } .main-navigation ul { display: none; } }
Код Javascript, который делает это, содержится в самом низу файла. В первых 15 строках (или где-то так) стоит проверка, что различные части меню существуют, и если их нет, то выполнение Javascript останавливается.
Переменная button определяется путем получения h1 в #site-navigation.
/** * navigation.js * * Обрабатывает переключение меню для небольших экранов. */ ( function() { var container, button, menu; container = document.getElementById( 'site-navigation' ); if ( ! container ) return; button = container.getElementsByTagName( 'h1' )[0]; if ( 'undefined' === typeof button ) return; menu = container.getElementsByTagName( 'ul' )[0]; // Скрывает кнопку переключения меню, если меню пустое, и возвращает раннее значение if ( 'undefined' === typeof menu ) { button.style.display = 'none'; return; } if ( -1 === menu.className.indexOf( 'nav-menu' ) ) menu.className += ' nav-menu'; button.onclick = function() { if ( -1 !== container.className.indexOf( 'toggled' ) ) container.className = container.className.replace( ' toggled', '' ); else container.className += ' toggled'; }; } )();
Обратите внимание, что в коде нет фиксированных значений для ширины, т.е. нет фиксированной точки переключения для навигации. Все это задано в CSS. Поскольку решения принимаются в CSS, переход от одного меню к другому получается очень быстрым.
Гибкость для тем
Этот метод является более гибким, поскольку значения для точек перехода заданы в CSS. Однако было бы несколько странным переписывать медиа-запросы в дочерней теме, чтобы скорректировать границу перехода.
Какой метод лучше?
Я считаю, что практически во всех ситуациях второй метод без jQuery, включающий в себя обработку через CSS, выигрывает, поскольку он гибкий, быстрый и отличается отличной поддержкой.
Однако некоторые темы могут быть структурированы так, что переписывание CSS медиа-запросов будет представлять собой значительную сложность, потому в таком случае предпочтительным вариантом будет использование jQuery решения и wp_localize_script.
Некоторые темы могут уже изначально использовать что-то, напоминающее первый метод – в данном случае стоит помнить про обратную совместимость. В таком случае можно будет легко добавить гибких границы перехода с помощью wp_localize_script.
Если же вы не используете родительскую тему с реализованным методом навигации, то в таком случае самый простой выход – воспользоваться стартером _s.