Chào mừng đến với Diễn Đàn Tin Học VN! Hãy chia sẽ những gì bạn biết, và đưa ra thắc mắc của bạn để được giải đáp.

Xem chủ đề cũ hơnGo downXem chủ đề mới hơn
phoenix51706
phoenix51706
Admin
Tổng số bài gửi : 171
Join date : 30/07/2010
https://diendantinhocvn.forumvi.com

Tạo menu responsive cho wordpress siêu đẹp Empty Tạo menu responsive cho wordpress siêu đẹp

23/11/21, 02:19 am
Khi thiết kế theme wordpress mình sử dụng theme trắng của underscore.me để thiết kế, nhưng gặp vấn đề ở cái menu của nó làm hơi bị chuối khiến mình thấy ngứa mắt. Vì vậy nên đã mày mò trên internet và cuối cùng lụm được một cái menu responsive ngon lành cành đào.

Dưới đây là toàn bộ những gì cần có và cần để có thể chạy được menu responsive.

Trước tiên cần phải điều chỉnh một chút xíu về nav walker trong wordpress bằng class dưới đây.

Code:
/**
 * Custom walker class.
 */
class Custom_Walker_Nav_Menu extends Walker_Nav_Menu {
 
    /**
     * Starts the list before the elements are added.
     *
     * Adds classes to the unordered list sub-menus.
     *
     * @param string $output Passed by reference. Used to append additional content.
     * @param int    $depth  Depth of menu item. Used for padding.
     * @param array  $args   An array of arguments. @see wp_nav_menu()
     */
    function start_lvl( &$output, $depth = 0, $args = array() ) {
        // Depth-dependent classes.
        $indent = ( $depth > 0  ? str_repeat( "\t", $depth ) : '' ); // code indent
        $display_depth = ( $depth + 1); // because it counts the first submenu as 0
        $classes = array(
            'sub-menu',
            //( $display_depth % 2  ? 'menu-odd' : 'menu-even' ),
            ( $display_depth >=2 ? 'sub-sub-menu' : '' ),
           // 'menu-depth-' . $display_depth
        );
        $class_names = implode( ' ', $classes );
 
        // Build HTML for output.
        $output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
    }
 
    /**
     * Start the element output.
     *
     * Adds main/sub-classes to the list items and links.
     *
     * @param string $output Passed by reference. Used to append additional content.
     * @param object $item   Menu item data object.
     * @param int    $depth  Depth of menu item. Used for padding.
     * @param array  $args   An array of arguments. @see wp_nav_menu()
     * @param int    $id     Current item ID.
     */
    function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        global $wp_query;
        $indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent
 
        // Depth-dependent classes.
        $depth_classes = array(
            //( $depth == 0 ? 'main-menu' : 'sub-menu' ),
            //( $depth == 0 ? 'main-menu-item' : 'sub-menu-item' ),
            //( $depth >=2 ? 'sub-sub-menu-item' : '' ),
            //( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
            //'menu-item-depth-' . $depth
        );
        $depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
 
        // Passed classes.
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );
 
        // Build HTML.
        //$output .= $indent . '<li class="' . $depth_class_names . ' ' . $class_names . '">';
        if($args->walker->has_children)
        {
            $output .= $indent . '<li class="menu-item menu-item-has-children">';
        }else{
            $output .= $indent . '<li class="menu-item">';
        }
        

        // Link attributes.
        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
        $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
        $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
        $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';
        //$attributes .= ' class="menu-link ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"';
 if($args->walker->has_children)
        {
            $attributes .= 'data-toggle="sub-menu"';
        }
 
        // Build HTML output and pass through the proper filter.
        $item_output = sprintf( '%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s',
            $args->before,
            $attributes,
            $args->link_before,
            apply_filters( 'the_title', $item->title, $item->ID ),
            ( $args->walker->has_children) ?  $args->link_after : '',
          
            $args->after
        );
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
}

Tiếp theo là chọn vị trí muốn hiển thị menu và dán code dưới đây vào

Code:
<header class="header">
        <div class="container">
            <section class="wrapper">
               <a href="/" class="brand"><i class="fa fa-book"></i> English</a>
               <button type="button" class="opened-menu">
                  <span></span>
                  <span></span>
                  <span></span>
               </button>
               <div class="overlay"></div>
                <nav class="navbar">
                        <button type="button" class="closed-menu">
                         <i class="fa fa-times"></i>
                        </button>
                        <?php
             wp_nav_menu(
                            array(
                                'container'     =>'',
                                'container_class'=>'',
                                'menu_class'    => 'menu',
                                'menu_id'       => '',
                                'items_wrap'    => '<ul class="%2$s">%3$s</ul>',
                                'link_after'    => '<i class="expand"></i>',
                                'fallback_cb'    => false,
                                'walker'        => new Custom_Walker_Nav_Menu()
                            )
             );
        ?>
               </nav>
            </section>
        </div>
    </header>

Và rồi css để hình hài menu responsive hiện ra

Code:
.brand {
  font-family: inherit;
  font-size: 1.75rem;
  font-weight: 700;
  line-height: inherit;
  border: none;
  outline: none;
  color: #e91e63;
  text-transform: uppercase;
  text-rendering: optimizeLegibility;
}
.header {
  left: 0;
  top: 0;
  width: 100%;
  height: auto;
  z-index: 999;
  border: none;
  outline: none;
  background-color: #FAFAF8;
  -webkit-box-shadow:0 4px 8px 0 rgb(0 0 0 / 20%), 0 6px 20px 0 rgb(0 0 0 / 19%);
    box-shadow: 0 4px 8px 0 rgb(0 0 0 / 20%), 0 6px 20px 0 rgb(0 0 0 / 19%);
    border-bottom: 4px solid #E9EBE6;
}
.header.active{
    position:fixed;
    top:0; left:0; right:0;
    z-index: 1000;

}
.header .wrapper {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  gap: 2rem;
  max-width: 100%;
  height: auto;
  padding: 0.5rem 0;
}

.header .navbar {
  max-width: 100%;
  height: auto;
}
.header .menu {
    margin:0;
    padding:0;
}
.header .menu > .menu-item {
  position: relative;
  display: inline-block;
}

.header .menu > .menu-item > a {
  display: block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 600;
  line-height: inherit;
  padding: 0.75rem;
  border: none;
  outline: none;
  color: #4a4a4a;
  text-transform: capitalize;
  text-rendering: optimizeLegibility;
  -webkit-transition: all 0.35s ease;
  -o-transition: all 0.35s ease;
  transition: all 0.35s ease;
}

.header .menu > .menu-item > a .expand {
  position: relative;
  display: inline-block;
  height: 0.75rem;
  width: 0.75rem;
  margin-left: 0.35rem;
  border: none;
  outline: none;
  pointer-events: none;
}

.header .menu > .menu-item > a .expand:before, .header .menu > .menu-item > a .expand:after {
  position: absolute;
  -webkit-box-sizing: inherit;
          box-sizing: inherit;
  content: '';
  left: 50%;
  top: 50%;
  width: 100%;
  height: 2px;
  background: #4a4a4a;
  -webkit-transform: translate(-50%, -50%);
      -ms-transform: translate(-50%, -50%);
          transform: translate(-50%, -50%);
  -webkit-transition: all 0.35s ease;
  -o-transition: all 0.35s ease;
  transition: all 0.35s ease;
}

.header .menu > .menu-item:hover > a {
  color: #e91e63;
  background:#f0f0f0;
}

.header .menu > .menu-item:hover > a .expand::before, .header .menu > .menu-item:hover > a .expand::after {
  background: #e91e63;
}

.header .menu > .menu-item > a .expand::after {
  -webkit-transform: translate(-50%, -50%) rotate(-90deg);
      -ms-transform: translate(-50%, -50%) rotate(-90deg);
          transform: translate(-50%, -50%) rotate(-90deg);
}

.header .menu > .menu-item > .sub-menu > .menu-item > a:hover {
  color: #e91e63;
  background:#f0f0f0;
}

.header .menu > .menu-item > .sub-menu {
  position: absolute;
  left: -1rem;
  top: 100%;
  width: 13rem;
  height: auto;
  margin:0;
  padding: 0.75rem 0;
  border: none;
  outline: none;
  opacity: 0;
  visibility: hidden;
  z-index:9999;
  border-top: 3px solid #e91e63;
  background: #ffffff;
  -webkit-box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
          box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  -webkit-transform: translateY(1rem);
      -ms-transform: translateY(1rem);
          transform: translateY(1rem);
  -webkit-transition: all 0.35s ease;
  -o-transition: all 0.35s ease;
  transition: all 0.35s ease;
}

.header .menu > .menu-item > .sub-menu > .menu-item {
  display: block;
}

.header .menu > .menu-item > .sub-menu > .menu-item > a {
  display: block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 600;
  line-height: inherit;
  padding: 0.5rem 1.25rem;
  color: #4a4a4a;
  border-bottom: 1px solid #f2f2f2;
  text-transform: capitalize;
  text-rendering: optimizeLegibility;
  -webkit-transition: all 0.35s ease;
  -o-transition: all 0.35s ease;
  transition: all 0.35s ease;
}

.header .opened-menu {
 position: relative;
 display: none;
 cursor: pointer;
 width: 2rem;
 height: 1rem;
 margin-left: 1rem;
 border: none;
 outline: none;
 opacity: 0;
 visibility: hidden;
 background: none;
 -webkit-transform: rotate(0deg);
 -ms-transform: rotate(0deg);
 transform: rotate(0deg);
 -webkit-transition: all 0.35s ease;
 -o-transition: all 0.35s ease;
 transition: all 0.35s ease;
}

.header .opened-menu span {
 display: block;
 position: absolute;
 width: 100%;
 height: 3px;
 left: 0;
 border: none;
 outline: none;
 opacity: 1;
 border-radius: 0.25rem;
 background-color: #000;
 -webkit-transform: rotate(0deg);
 -ms-transform: rotate(0deg);
 transform: rotate(0deg);
 -webkit-transition: all 0.25s ease;
 -o-transition: all 0.25s ease;
 transition: all 0.25s ease;
}

.header .opened-menu span:nth-child(1) {
 top: 0;
}

.header .opened-menu span:nth-child(2){
 top: 0.5rem;
}

.header .opened-menu span:nth-child(3) {
 top: 1rem;
}
.header .opened-menu.active span:nth-child(1) {
 top: 0.5rem;
 -webkit-transform: rotate(-45deg);
 -ms-transform: rotate(-45deg);
 transform: rotate(-45deg);
}

.header .opened-menu.active span:nth-child(2){
 display: none;
}

.header .opened-menu.active span:nth-child(3) {
 top: 0.5rem;
 -webkit-transform: rotate(45deg);
 -ms-transform: rotate(45deg);
 transform: rotate(45deg);
}

.header .closed-menu {
 display: none;
 -webkit-box-align: center;
 -ms-flex-align: center;
 align-items: center;
 -webkit-box-pack: center;
 -ms-flex-pack: center;
 justify-content: center;
 cursor: pointer;
 width: 2.5rem;
 height: 2.5rem;
 font-size:25px;
 border: none;
 outline: none;
 background: none;
 -webkit-transition: transform ease-out .2s;
 -moz-transition: transform ease-out .2s;
 -ms-transition: transform ease-out .2s;
 -o-transition: transform ease-out .2s;
 transition: transform ease-out .2s;
 transform: rotate(0deg);
}
.header .closed-menu:hover{
 transform: rotate(90deg);
}

.header .closed-menu img.closed-icon {
 display: block;
 width: 1rem;
 height: auto;
}
.header .overlay {
  position: fixed;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  z-index: 999;
  opacity: 0;
  visibility: hidden;
  background: rgba(0, 0, 0, 0.6);
  -webkit-transition: all 0.35s ease;
  -o-transition: all 0.35s ease;
  transition: all 0.35s ease;
}

@media only screen and (min-width: 993px) {
  .header .menu > .menu-item-has-children:hover > .sub-menu {
    display: block;
    opacity: 1;
    visibility: visible;
    -webkit-transform: translateY(0);
        -ms-transform: translateY(0);
            transform: translateY(0);
  }
  .header .menu > .menu-item-has-children:hover > a .expand::after {
    -webkit-transform: translate(-50%, -50%) rotate(0deg);
        -ms-transform: translate(-50%, -50%) rotate(0deg);
            transform: translate(-50%, -50%) rotate(0deg);
  }
}

@media only screen and (max-width: 992px) {
  .header .overlay.active {
    display: block;
    opacity: 1;
    visibility: visible;
  }
  .header .navbar {
    position: fixed;
    top: 0;
    left: -18rem;
    width: 18rem;
    height: 100%;
    padding: 1rem 0;
    z-index: 999;
    opacity: 0;
    overflow-y: auto;
    visibility: hidden;
    background: #ffffff;
    -webkit-box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    -webkit-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    transition: all 0.5s ease;
  }
  .header .navbar.active {
    left: 0rem;
    opacity: 1;
    visibility: visible;
  }
  .header .navbar::-webkit-scrollbar {
    width: 5px;
  }
  .header .navbar::-webkit-scrollbar-thumb {
    border-radius: 1rem;
    background: #e6e6e6;
    -webkit-box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.12);
            box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.12);
  }
  .header .menu {
    width: 100%;
    height: auto;
    margin-top: 3.5rem;
  }
  .header .menu > .menu-item {
    display: block;
    margin: 0;
  }
  .header .menu > .menu-item-has-children > a {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: justify;
        -ms-flex-pack: justify;
            justify-content: space-between;
    -webkit-box-align: center;
        -ms-flex-align: center;
            align-items: center;
  }
  .header .menu > .menu-item > a {
    padding: 0.75rem 1rem;
    color: #4a4a4;
    border-bottom: 1px solid #f2f2f2;
  }
  .header .menu > .menu-item:first-child > a {
    border-top: 1px solid #f2f2f2;
  }

  .header .menu > .menu-item-has-children.active > a .expand:after {
    -webkit-transform: translate(-50%, -50%) rotate(0deg);
        -ms-transform: translate(-50%, -50%) rotate(0deg);
            transform: translate(-50%, -50%) rotate(0deg);
  }
  .header .menu > .menu-item > .sub-menu {
    position: relative;
    top: auto;
    left: auto;
    width: 100%;
    max-height: 0;
    padding: 0px;
    border: none;
    outline: none;
    opacity: 1;
    overflow: hidden;
    visibility: visible;
    background: transparent;
    -webkit-box-shadow: none;
            box-shadow: none;
    -webkit-transform: translateY(0px);
        -ms-transform: translateY(0px);
            transform: translateY(0px);
  }
  .header .menu > .menu-item > .sub-menu > .menu-item > a {
    padding: 0.75rem 2rem;
  }
  .header .opened-menu {
    display: block;
    opacity: 1;
    visibility: visible;
  }
  .header .closed-menu {
    position: absolute;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    top: 1rem;
    right: 0.5rem;
  }
}

Và cuối cùng cũng cực kỳ quan trong là đoạn code javascript

Code:
//nav resposive script
jQuery(document).ready(function($) {

    const openedMenu = document.querySelector('.opened-menu');
    const closedMenu = document.querySelector('.closed-menu');
    const navbarMenu = document.querySelector('.navbar');
    const menuOverlay = document.querySelector('.overlay');
    
    // Opened navbarMenu
    // Closed navbarMenu
    // Closed navbarMenu by Click Outside
    openedMenu.addEventListener('click', toggleMenu);
    closedMenu.addEventListener('click', toggleMenu);
    menuOverlay.addEventListener('click', toggleMenu);
    
    // Toggle Menu Function
    function toggleMenu() {
       navbarMenu.classList.toggle('active');
       menuOverlay.classList.toggle('active');
       openedMenu.classList.toggle('active');
       document.body.classList.toggle('scrolling');
    }

    navbarMenu.addEventListener('click', (event) => {
       if (event.target.hasAttribute('data-toggle') && window.innerWidth <= 992) {
          // Prevent Default Anchor Click Behavior
          event.preventDefault();
          const menuItemHasChildren = event.target.parentElement;
    
          // If menuItemHasChildren is Expanded, Collapse It
          if (menuItemHasChildren.classList.contains('active')) {
             collapseSubMenu();
          } else {
             // Collapse Existing Expanded menuItemHasChildren
             if (navbarMenu.querySelector('.menu-item-has-children.active')) {
                collapseSubMenu();
             }
             // Expand New menuItemHasChildren
             menuItemHasChildren.classList.add('active');
             const subMenu = menuItemHasChildren.querySelector('.sub-menu');
             subMenu.style.maxHeight = subMenu.scrollHeight + 'px';
          }
       }
    });
    
    // Collapse Sub Menu Function
    function collapseSubMenu() {
       navbarMenu.querySelector('.menu-item-has-children.active .sub-menu').removeAttribute('style');
       navbarMenu.querySelector('.menu-item-has-children.active').classList.remove('active');
    }
    
    // Fixed Resize Screen Function
    function resizeScreen() {
       // If navbarMenu is Open, Close It
       if (navbarMenu.classList.contains('active')) {
          toggleMenu();
       }
    
       // If menuItemHasChildren is Expanded, Collapse It
       if (navbarMenu.querySelector('.menu-item-has-children.active')) {
          collapseSubMenu();
       }
    }
    
    window.addEventListener('resize', function() {
       if (this.innerWidth > 992) {
          resizeScreen();
       }
    });
});
Xem chủ đề cũ hơnVề Đầu TrangXem chủ đề mới hơn
Permissions in this forum:
Bạn không có quyền trả lời bài viết