Creating a responsive navigation menu by converting overflowing menu items into a dropdown list

I'm currently designing a menu that contains multiple list items. I would like the overflowing li's to collapse and display in a dropdown when resizing the browser to smaller screens, such as laptops and tablets.

Original Menu. https://i.sstatic.net/edXyV.png

Responsive view of the menu. https://i.sstatic.net/QSUOY.png

Below is the code structure.

var menuWidth = $('ul').width(); //retrieve ul actual width

var listWidth = $.map($('ul li'), function(val) {
  return $(val).width();
}); //store individual li widths in an array
var arrayTotalValue = listWidth.reduce(function(a, b) {
  return a + b;
}); //add values in the above array
var totalWidth = Math.ceil(arrayTotalValue); //round up total value

if (totalWidth > menuWidth) {
  $('li').css({
    color: '#FF0000'
  })
}
ul {
  display: flex;
  padding: 50px 0;
  box-sizing: border-box;
  align-items: center;
  width: 700px;
  overflow: visible;
}

li {
  text-decoration: none;
  color: #000000;
  font-size: 20px;
  text-transform: capitalize;
  border: 1px solid black;
  margin: 20px 10px;
  list-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li class="menu-item">menu1</li>
  <li class="menu-item">menu2</li>
  <li class="menu-item">menu3</li>
  <li class="menu-item">menu4</li>
  <li class="menu-item">menu5</li>
  <li class="menu-item">menu6</li>
  <li class="menu-item">menu7</li>
  <li class="menu-item">menu8</li>
  <li class="menu-item">menu9</li>
  <li class="menu-item">menu10</li>
  <li class="menu-item">menu11</li>
  <li class="menu-item">menu12</li>
  <li class="menu-item">menu13</li>
  <li class="menu-item">menu14</li>
  <li class="menu-item">menu15</li>
  <li class="menu-item">menu16</li>
</ul>

Here is the link to my codepen. Feel free to provide any feedback or suggestions.

Answer №1

To start with, my approach would involve modifying the CSS for improved readability and functionality. I plan to make adjustments by disabling the flexbox to enable wrapping and ensuring that only elements in the first row are visible through setting a restricted height (max-height) along with overflow:hidden. Additionally, I will introduce a clickable element that appears when there are hidden items. This will be achieved using a pseudo-element method to conceal it.

ul {
  padding:5px 40px 5px 5px;
  box-sizing: border-box;
  overflow: hidden;
  max-height:55px;
  position:relative;
}

li {
  display:inline-block;
  text-decoration: none;
  color: #000000;
  font-size: 20px;
  text-transform: capitalize;
  border: 1px solid black;
  margin:10px;
  list-style: none;
  position:relative;
}

li:last-child::after {
  content:"";
  position:absolute;
  left:102%;
  width:100vw;
  top:-10px;
  bottom:-10px;
  background:#fff;
  z-index:2;
}

.click {
  background:red;
  position:relative;
  width:40px;
  height:40px;
  margin-left:auto;
  margin-top:-65px;
  margin-right:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li class="menu-item">menu1</li>
  <li class="menu-item">menu2</li>
  <li class="menu-item">menu3</li>
  <li class="menu-item">menu4</li>
  <li class="menu-item">menu5</li>
  <li class="menu-item">menu6</li>
  <li class="menu-item">menu7</li>
  <li class="menu-item">menu8</li>
  <li class="menu-item">menu9</li>
  <li class="menu-item">menu10</li>
  <li class="menu-item">menu11</li>
  <li class="menu-item">menu12</li>
  <li class="menu-item">menu13</li>
  <li class="menu-item">menu14</li>
</ul>
<div class="click"></div>

Subsequently, incorporating some JavaScript code is essential to reveal the concealed elements upon clicking the red square icon, creating a dropdown-like effect. The trick here is to identify hidden items by comparing their offsetTop value against a predefined threshold.

var h = 30;
var val = 0;

$('.click').click(function() {
  if ($('ul').hasClass('show')) {
    $('ul').removeClass('show');
    $('ul li.menu-item').removeClass('drop')
    return;
  }
  val = 0;
  $('ul li.menu-item').each(function() {
    var of = $(this).offset().top - $('ul').offset().top;
    if ( of > 20) {
      $(this).addClass('drop');
      $(this).css('top', 'calc(100% + ' + val + 'px)');
      val += h;
    }
    $('ul').addClass('show');
  })
})
ul {
  padding: 5px 40px 5px 5px;
  box-sizing: border-box;
  overflow: hidden;
  max-height: 55px;
  position: relative;
}

ul.show {
  overflow: visible;
}

li {
  display: inline-block;
  text-decoration: none;
  color: #000000;
  font-size: 20px;
  text-transform: capitalize;
  border: 1px solid black;
  margin: 10px 8px;
  list-style: none;
  position: relative;
}

li.drop {
  display: block;
  position: absolute;
  right: 0;
}

li:last-child::after {
  content: "";
  position: absolute;
  left: 102%;
  width: 100vw;
  top: -10px;
  bottom: -10px;
  background: #fff;
  z-index: 2;
}

li.drop::after {
  content: none;
}

.click {
  background: red;
  position: relative;
  width: 40px;
  height: 40px;
  margin-left: auto;
  margin-top: -65px;
  margin-right: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li class="menu-item">menu1</li>
  <li class="menu-item">menu2</li>
  <li class="menu-item">menu3</li>
  <li class="menu-item">menu4</li>
  <li class="menu-item">menu5</li>
  <li class="menu-item">menu6</li>
  <li class="menu-item">menu7</li>
  <li class="menu-item">menu8</li>
  <li class="menu-item">menu9</li>
  <li class="menu-item">menu10</li>
  <li class="menu-item">menu11</li>
  <li class="menu-item">menu12</li>
  <li class="menu-item">menu13</li>
  <li class="menu-item">menu14</li>
</ul>
<div class="click"></div>

The provided example offers a simplified demonstration with specific hardcoded values that are customizable or can be made dynamic as needed.

Answer №2

I have made an attempt to address the issues you are facing. I have come up with a solution to resolve your problem. Below is the method I suggest for fixing the issue.

$('.header').click(function() {
  console.log('open menu');
  if ($(this).parent().hasClass('expanded') == false) {
    $(this).parent().addClass('expanded');
  } else {
    $(this).parent().removeClass('expanded');
  }
})
ul {
  display: flex;
  padding: 50px 0;
  box-sizing: border-box;
  align-items: center;
  width: 700px;
  overflow: visible;
}

ul .header {
  display: none;
}

li {
  margin: 20px 10px;
}

li {
  text-decoration: none;
  color: #000000;
  font-size: 20px;
  text-transform: capitalize;
}

li.cat {
  display: block;
  border: 1px solid black;
}

@media screen and (max-width: 800px) {
  ul {
    display: table-row;
    list-style-type: none;
    margin: 0;
    padding: 0;
  }
  ul .header {
    display: block;
  }
  ul .cat {
    display: none;
  }
}

.expanded li {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<ul>
  <li class="header">dropdown
    <li>
      <li class="cat">menu1</li>
      <li class="cat">menu2</li>
      <li class="cat">menu3</li>
      <li class="cat">menu4</li>
      <li class="cat">menu5</li>
      <li class="cat">menu6</li>
      <li class="cat">menu7</li>
      <li class="cat">menu8</li>
      <li class="cat">menu9</li>
      <li class="cat">menu10</li>
      <li class="cat">menu11</li>
      <li class="cat">menu12</li>
      <li class="cat">menu13</li>
      <li class="cat">menu14</li>
      <li class="cat">menu15</li>
      <li class="cat">menu16</li>
</ul>

The above example demonstrates a simple approach. You can customize it according to your needs.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Turn off sticky sidebar feature for mobile-friendly layout

I have encountered an issue with my script that I need assistance with. I am trying to disable this script for responsive or mobile view, but despite trying various methods, it is not functioning as expected. <script type="text/javascript"> $(func ...

Dealing with an asterisk * in an id selector: what you need to know

My PHP code generates a series of buttons for users to click on, each button representing the grade of a student. Additionally, the PHP code also creates the jQuery necessary to enable a random selection of students based on the grade clicked: echo "<d ...

Pressing the button will allow you to select and copy the text within the

I am looking to incorporate a mock-chat feature into my website. The concept is to type something on the website, then click a button next to it which will move the text to a frame above. I attempted this using a textarea and even found a code for selectin ...

Implementing CSS styles based on the count of elements

Within my react js project There is a particular block that may contain either one or two elements, depending on the runtime conditions. For instance: Scenario 1: (two groups are present) <div class='menu-list'> <div class='g ...

Issue: The object identified as #<Object> does not contain the 'toUpperCase' method

I am currently encountering the error Object #<Object> has no method 'toUpperCase' right before the POST request is initiated. Any assistance you can provide would be greatly appreciated! Thank you in advance. function ajaxeo(url, data, me ...

How to eliminate bullets from an unordered list using Bootstrap

Struggling to get rid of the bullets displayed on an unordered list using Bootstrap. I attempted utilizing the "text-decoration-none" class without success. ...

Extension for Chrome that enhances YouTube video playback experience

I'm struggling to figure out why this isn't functioning. I've reviewed the Google extension dev docs and examined some sample code. Checked various Stack Overflow questions and answers, but haven't received any helpful feedback or res ...

What method can be used in jQuery to verify if two input boxes contain values or are empty?

I have created a code to show the values entered in two input text boxes using jQuery. How can I verify if these text boxes are filled with values or not? Currently, I am using the change function to display the values entered from the text input boxes ins ...

At what point in the lifecycle of my component am I able to begin using this.$refs?

Exploring ways to integrate HTML5 audio events while initializing a Vue.js component that consists of a single file: <template> <audio ref="player" v-bind:src="activeStationUrl" v-if="activeStationUrl" controls autoplay></audio> < ...

Verify the password on a form by comparing it with the encrypted password stored in the database using the SHA-

My goal is to validate a password in a form against an encrypted password stored in a database using SHA-512 hashing. This validation process is specifically for a change password form. I am able to validate passwords when they are not encrypted, but I ha ...

Are there any risks associated with using nested setTimeout functions with the same name?

While reviewing the source code of typed.js, I noticed that the main function in this plugin utilizes a design pattern with multiple setTimeout functions nested inside one another. Here is a snippet of the code: self.timeout = setTimeout(function() { / ...

Best practice for showcasing an MVC Form with the use of Bootstrap

I am facing an issue with my form layout while trying to capture user input. The use of Bootstrap is creating two columns for text boxes and their labels, but the alignment goes off track with the last EditorFor element. I'm questioning if I am misusi ...

Steps for constructing an object containing an array of nested objects

I've been working on this problem for some time now, and it's starting to feel like a messy situation that just won't come together. I'm trying to recreate an object with 5 properties and a nested array of objects, but so far, it's ...

Using JQuery to Enhance the Highlight Effect: Tips and Tricks

Exploring the functionality of the "highlight" JQuery effect: http://docs.jquery.com/UI/Effects/Highlight You have the ability to modify the background color of any DIV element with a fade in/out effect. However, the provided example demonstrates trigge ...

Using jquery to create HTML elements but unable to remove them using jquery

I'm facing an issue with removing newly created li elements in an unordered list using jQuery. The delete button works perfectly fine for the existing li, but not for the ones added dynamically. <!DOCTYPE html> <html lang="en> <head> ...

Newbie's Dilemma: Issues with Html, Email, and Distribution Lists

I am looking to add a new feature to my website where users can enter their email address to receive a free promotion and be added to an announcement list. Since I don't have any experience with web programming, I'm not sure where to start. Would ...

Ways to customize hover color of Bootstrap 5 Dropdown menu

I'm having trouble modifying the hover color for a dropdown menu using Bootstrap 5. I'm unsure of the correct method to achieve this. The desired outcome is as follows: However, at the moment it appears like this: Apologies for the oversight, h ...

Incorporate a background image property using Jquery

Can anyone help me with adding the css background-image:url("xxxxx") property to my code? jQuery('#'+$trackID+' .sc_thumb').attr('src',$thumb_url); jQuery('#'+$trackID+' .sc_container').css('display& ...

Using the .ajax() function with jQuery to retrieve data and then using .find() on that data

Currently I am facing an issue while trying to extract the body tag from the result of the .ajax() call. Instead of getting the desired result, I only see undefined logged into the console... This is the section of code causing the problem: $(document).r ...

View a pink map on Openlayers 2 using an iPhone

I am currently working on a project where I am trying to track my location using my smartphone and display it on a map. To achieve this, I am utilizing openlayers 2. However, I am encountering an issue. When I implement the code below in a Chrome Browser ...