Drop down div under another div


#1

Hi,

I am trying to create a slide down div that appears under my main navbar. I’ve managed to create the drop down, but it’s appearing inside of my navbar.

What would be the best way to have it under the navbar? Would I need to use absolute positioning?

Also, I would like the collapsed div to collapse back up if the user clicks outside of that div. Is this possible?

This is what I have so far:
https://jsfiddle.net/toolman/ypvxq68j/11/

Thanks


#2

I assumed you meant a dropdown menu but are you talking about the search bar that appears when you click the search icon?

If so then I would add a class that you can control it with CSS.

i.e.

Change the CSS to this:

#search {
	background: #fffcc4;
	padding: 20px 15px;
	overflow: hidden;
	opacity:0;
	position:absolute;
	left:-999em;
	box-sizing:border-box;
	width:100%;
	top:100%;
	transform:translateY(-100%);
	transition:transform 1s ease, opacity 1s ease, top 0s ease 1s, left 0s ease 1s;
}
#search.open {
	transform:translateY(0%);
	opacity:1;
	left:0;
	transition:transform 1s ease, opacity 1s ease;
}

Instead of display:none which can’t be animated we place it off-left with absolute positioning. The we get the js to add a class and allow the css to animate the menu. The menu is animated using transform translate and opacity and we set a delay on the left positioning so that we don;t get it sliding off to the side when the class is removed.

For the JS you could detect a click on the document and then hide the menu if active. e.g. change your js to this:

 $('html').on("click", function(event) {

	if ( event.target.id === 'btn-search') {
         $('#search').toggleClass('open');
     } else {
		  $('#search').removeClass('open');
	}	
});

You might want to run that through one of the JS gurus to check if there’s a neater way to do this.:slight_smile:


#3

Hi,

Thanks for the reply.

Yes, sorry I meant have a search bar that appears.

That worked, however, it disappears/fades back when the user clicks in the search box, but I can play around with that.

I also tried to have it appear from under the nav rather than on top, but I couldn’t get that to happen using position: relative and giving it a z-index


#4

As the header is position sticky and has a z-index other than auto it is not possible to place a child element under the parent’s background. What you would need to do is remove the background styles and padding from the parent and apply it to a suitable inner container such as .container nav instead. That will allow you to set a higher z-index on container nav but a lower one on the search bar.

e.g.

header.header-blue {
	background:transparent;
	margin-bottom: 20px;
	color: #fff;
	font-size: 18px;
	z-index: 1000;
	position: sticky;
	position: -webkit-sticky;
	top: 0
}
.container-nav {
	background: #064882;
	background: linear-gradient(-45deg, #064882, #00284c, #064882, #00284c);
	background-size: 300% 300%;
	position:relative;
	padding: 15px 0;
	z-index:99;
	box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2);
	border-bottom: 1px solid #00111f;
	display: flex;
	flex-direction: row-reverse;
	flex-wrap: nowrap;
}

And hen set the search bar z-index:

#search {
	background: #fffcc4;
	padding: 20px 15px;
	overflow: hidden;
	opacity:0;
	position:absolute;
	z-index:1;
	left:-999em;
	box-sizing:border-box;
	width:100%;
	top:100%;
	transform:translateY(-100%);
	transition:transform 1s ease, opacity 1s ease, top 0s ease 1s, left 0s ease 1s;
}

OK, yes I didn’t notice that but you will need to detect where the click came from and ignore if on the inner search elements.

Something like this works but probably needs cleaning up.:slight_smile:

<script>
$('html').on("click", function(event) {
	if ( event.target.id === 'search' || $(event.target).parents('#search').length) {
		return;
	}
	if ( event.target.id === 'btn-search') {
         $('#search').toggleClass('open');
     } else {
		  $('#search').removeClass('open');
	}	
});



</script>

#5

Thanks, I managed to use a different method of showing/hiding the search bar, however, I’m still having trouble getting the search bar to appear outside of the navbar and to be sticky when collapsed.

This is my fiddle:
https://jsfiddle.net/toolman/xzgh83sv/7/

I’m not sure how to get the search bar to be outside of the navbar and also be sticky.


#6

I gave you a fully working version that does exactly what you want in all areas and explained how to make the search drop down underneath. I realise you may have a different structure in your real site but the techniques should have worked.

I’m on a mobile at the moment so can’t look at your new fiddle (jsfiddle doesn’t work on mobile) but if you look at the changes I explained in the previous post you should be able to achieve what you want assuming you haven’t changed the html structure.

If you can’t work it out or you have changed the structure I will have another look in the morning. If you have moved the search out of the header then you will make it awkward to be sticky and to keep track with the header.


#7

You can’t nest containers in bootstrap because they supply padding that is immediately offset in rows and columns to create the grid gutters. If you want a full width (viewport edge to edge) layout then just use your own div with appropriate class outside of a bootstrap container.

In your new example you would need to add these two new elements and move the styling to them instead of the ones you had. Here’s a fully working example.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<style>
header.header-blue {
	z-index: 1000;
	position: -webkit-sticky;
	position: sticky;
	top: 0
}
.top-wrap {
	background: #064882;
	background: linear-gradient(-45deg, #064882, #00284c, #064882, #00284c);
	background-size: 300% 300%;
	-webkit-animation: Gradient 8s ease infinite;
	-moz-animation: Gradient 8s ease infinite;
	animation: Gradient 8s ease infinite;
	color: #fff;
	font-size: 18px;
	box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2);
	border-bottom: 1px solid #00111f;
}
.header-container {
	padding: 15px 0;
}
.container-nav {
	display: flex;
}
.container-nav>div {
	margin-left: 30px;
}
.col-logo {
	margin: 0 auto 0 0;
}
.col-menu, .col-ask-button, .col-search, .col-topics {
	margin-left: 30px;
}
/* SEARCH */
#search-wrap {
	position:absolute;
	top:100%;
	left:0;
	right:0;
	border-top: 1px solid #d8d8d8;
	padding-left: 25px;
	padding-right: 10px;
	z-index: 9999;
	background: #fff;
	-webkit-box-shadow: -1px 2px 2px rgba(0, 0, 0, 0.2);
	-moz-box-shadow: -1px 2px 2px rgba(0, 0, 0, 0.2);
	box-shadow: -1px 2px 2px rgba(0, 0, 0, 0.2);
	display: none;
}
#search-bar {
	width: 100%;
}
#s {
	display: block;
	width: 88%;
	border: 0;
	outline: none;
	padding: 0;
	height: 60px;
	line-height: 60px;
	font-size: 3.0em;
	font-weight: bold;
	color: #676767;
}
#searchsubmit {
	display: block;
	float: right;
	margin-top: 6px;
	background: none;
	color: #717171;
	border: 0;
	outline: none;
	cursor: pointer;
}

/* end SEARCH */
</style>
</head>

<body>
<!-- main menu -->
<header class="header-blue">
  <div class="top-wrap">
    <div class="container">
      <div class="row">
        <div class="col-md-12">
          <div class="container-nav header-container">
            <div class="col-logo"> Logo </div>
            <div class="col-topics"> Categories </div>
            <div class="col-search"> <a href="#" id="searchtoggl">search</a> </div>
            <div class="col-ask-button"> <a href="#" class="ask-button">Button</a> </div>
            <div class="col-menu"> menu </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  
  <!-- search -->
  <div id="search-wrap">
    <div class="container">
      <div class="row">
        <div class="col-md-12">
          <div id="search-bar" class="clearfix">
            <form id="searchform" method="get" action="searchpage.php">
              <button type="submit" id="searchsubmit" class="fa fa-search fa-4x"></button>
              <input type="search" name="s" id="s" placeholder="Keywords..." autocomplete="off">
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
  <!-- end search --> 
  
</header>
<div class="clearfix"></div>
<!-- end main menu -->

<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<p> text </p>
<script src="http://code.jquery.com/jquery-latest.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/js/bootstrap.min.js"></script> 
<script>
jQuery(function() {
  var $searchlink = jQuery('#searchtoggl i');
  var $searchbar = jQuery('#search-wrap');

  jQuery('.col-search a').on('click', function(e) {
    e.preventDefault();

    if (jQuery(this).attr('id') == 'searchtoggl') {
      if (!$searchbar.is(":visible")) {
        // if invisible we switch the icon to appear collapsable
        $searchlink.removeClass('fa-search').addClass('fa-search-minus');
      } else {
        // if visible we switch the icon to appear as a toggle
        $searchlink.removeClass('fa-search-minus').addClass('fa-search');
      }

      $searchbar.slideToggle(300, function() {
        // callback after search bar animation
      });
    }
  });

  jQuery('#searchform').submit(function(e) {
    e.preventDefault(); // stop form submission
  });
});



</script>
</body>
</html>

I am guessing that you wanted the search dropdown to be full width and also guessing that you wanted the dummy text below not to move out of the way when the dropdown opens. If you do want the text to move down when the dropdown opens then change the position:absolute to position:relative instead.

Note that your version does not close when clicked outside the page unlike the previous method I gave you. If you want to achieve that you would need to check for a click on the document and act accordingly as in the code I gave you before. A possible easier way to do this is when the search menu opens you also open another fixed positioned overlay that covers the whole screen but with a z-index lower than than the header portions and then detect a click on that element. The fixed element would be outside the html of everything else and thus a click will not bubble through everything, You seem to have some other js in places I will leave that for you to implement.

Also your dropdown is not as smooth as the css version but the js slideToggle is always choppy. I assumed you added a height to the search to make it smoother but that would break the responsiveness so avoid that at all times,

Here’s the old version with the css animation plus bootstrap added. Im not sure why you made the nav so complicated either?

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<style>
/*HEADER */
header.header-blue {
	z-index: 1000;
	position: -webkit-sticky;
	position: sticky;
	top: 0
}
.top-wrap {
	background: #064882;
	background: linear-gradient(-45deg, #064882, #00284c, #064882, #00284c);
	background-size: 300% 300%;
	animation: Gradient 8s ease infinite;
	color: #fff;
	font-size: 18px;
	box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2);
	border-bottom: 1px solid #00111f;
	z-index:99;
	position:relative;
}
.container-nav {
	position:relative;
	padding: 15px 0;
	display: flex;
	flex-wrap: nowrap;
}
.container-nav > div{margin-left:30px;}
.container-nav > .col-logo {
	margin: 0 auto 0 0;
}
.container-nav {
	display: flex;
}

/* SEARCH */

.btn-search {
	border: 0;
	color: #fff;
	background:transparent;
	/*padding:10px 15px;*/
    cursor: pointer;
	transition: all .5s ease-out;
}
.btn-search:hover {
	color: #ccc;
}
#search-wrap {
	background: #fffcc4;
	padding: 20px 15px;
	overflow: hidden;
	opacity:0;
	position:absolute;
	z-index:1;
	left:-999em;
	box-sizing:border-box;
	width:100%;
	top:100%;
	transform:translateY(-100%);
	transition:transform 1s ease, opacity 1s ease, top 0s ease 1s, left 0s ease 1s;
}
#search-wrap.open {
	transform:translateY(0%);
	opacity:1;
	left:0;
	transition:transform 1s ease, opacity 1s ease;
}
#search form {
	text-align: center;
	max-width: 600px;
	margin: 0 auto;
}
#search input {
	padding: 5px;
	font-size: 1.2rem;
	border-radius: 5px;
	border: 2px solid #00585f;
	width: 100%;
}
#search #submit {
	padding: 7px 10px;
	background: #ff3800;
	border: 0;
	color: #fffcc4;
	text-transform: uppercase;
}
#search .left-side {
	float: left;
	width: 75%;
}
#search .right-side {
	float: right;
	width: 20%;
}
</style>
</head>

<body>
<header class="header-blue">
  <div class="top-wrap">
    <div class="container">
      <div class="row">
        <div class="col-md-12">
          <div class="container-nav">
            <div class="col-logo"> Logo </div>
            <div class="col-topics"> Categories </div>
            <div class="col-search">
              <button id="btn-search" class="btn-search">Search <i class="fa fa-search"></i></button>
            </div>
            <div class="col-ask-button"> <a href="#">Button</a> </div>
            <div class="col-menu"> menu </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  
  <div id="search-wrap">
    <div id="search" class="container">
      <div class="row">
        <div class="col-md-12">
          <form>
            <div class="left-side">
              <input type="text">
            </div>
            <div class="right-side">
              <input id="submit" type="submit" value="Submit">
            </div>
          </form>
        </div>
      </div>
    </div>
    <!--/search--> 
  </div>
</header>
<div class="container">
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
  <p> text </p>
</div>
<script src="http://code.jquery.com/jquery-latest.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/js/bootstrap.min.js"></script> 
<script>
$('html').on("click", function(event) {
	if ( event.target.id === 'search-wrap' || $(event.target).parents('#search-wrap').length) {
		return;
	}
	if ( event.target.id === 'btn-search') {
         $('#search-wrap').toggleClass('open');
     } else {
		  $('#search-wrap').removeClass('open');
	}	
});
</script>
</body>
</html>


#8

Hi Paul,

Thank you so much. Yes, I think your version works the best. I may play around with having the search bar toggle when the user clicks on the page - just thinking the user may need to scroll around to reference their search.

Why is the slideToggle choppy?

I may also consider having the actual search bar not full width as otherwise, large screens would have a huge field, but I can play around with some media queries.

Thanks again for all your help, it’s very much appreciated :smiley:


#9

jquery’s slides are always choppy :slight_smile: You can minimise it by having a fixed height and no margins on the elements inside but it’s something you basically have to live with. It’s always best to offset the animation to CSS where possible as that is hardware accelerated. Although some css animations can be choppy also if you’re not careful.


#10

Ah, I see :slight_smile:

I noticed in Safari on a Mac, that the animation of the drop down makes the rest of the text on the page have a weird little effect - almost a different font-weight an then changes back. Maybe it’s Safari as its fine in Opera.

Thanks again!


#11

Looked ok on my mac safari (assuming you meant the last demo) or was it a live version of yours?

Note that text can be affected if a transform happens to the parent in some way.


#12

It was actually in the Codepen, but I will check again on a Mac.

I’m setting up the form on my development site and wondering if there is a way to autofocus the input field in the search drop down div when it is collapsed?

I’ve tried some jQuery, but it’s not autofocusing.

This is what I have:

jQuery('html').on("click", function(event) {
	if ( event.target.id === 'search-wrap' || jQuery(event.target).parents('#search-wrap').length) {
		return;
	}
	if ( event.target.id === 'btn-search') {
         jQuery('#search-wrap').toggleClass('open');
		jQuery('input', this).focus();
     } else {
		  jQuery('#search-wrap').removeClass('open');
		 jQuery('input', this).focus();
	}	
});

I’ve tried adding:
jQuery('input', this).focus();


#13

‘this’ in that context refers to the html element and will not find you the search input.

Just add an id to the search input and then focus it when you toggle the class open.

e.g.

if ( event.target.id === 'btn-search') {
         $('#search-wrap').toggleClass('open');
         $('#searchme').focus();   
     } else {

<input id="searchme" type="text">


#14

Great, that worked :slight_smile: Thanks!