Related
HTML:
<div id="autocomplete" hidden></div>
<input type = "button" id = "search" value = "Search">
The autocomplete div holds various input tags generated by jQuery. When the input tags are created, they shift the button down the screen in order to fit the autocomplete content. What I want to do is to have the autocomplete div overlay on top of the the button rather than shifting the button down.
I have tried using z-index, but it seems to only work if autocomplete is placed after the button in HTML, the using negative margin to shift autocomplete back up. I don't like this solution since it messes up when viewed from other screen sizes.
Is there another way?
I think you have to use absolute positioning to keep the button over the inserting elements.
You can do something like this:
$('#autocomplete').append($('<div>').text('WOW1'))
$('#autocomplete').append($('<div>').text('WOW2'))
$('#autocomplete').append($('<div>').text('WOW3'))
$('#autocomplete').append($('<div>').text('WOW4'))
#container {
position: relative;
}
#search {
position: absolute;
top: 0;
}
#autocomplete {
padding-top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div id="autocomplete" ></div>
<input type = "button" id = "search" value = "Search">
</div>
EDIT:
Here is a link to see how CSS position works:
https://developer.mozilla.org/en-US/docs/Web/CSS/position
Also I recommend you to check this stack overflow answer about relative vs absolute positioning it has a very natural response (Position Relative vs Absolute?)
This tells the browser that whatever is going to be positioned should
be removed from the normal flow of the document and will be placed in
an exact location on the page. It won't affect how the elements before
it or after it in the HTML are positioned on the Web page however it
will be subject to it's parents' positioning unless you override it.
This is the general method to have the items inside the autocomplete div not affect the flow of the other elements on the page (your button in this case).
#autocomplete {
position: relative;
}
#autocomplete > * {
position: absolute;
}
A few comments to improve this code:
Don't use IDs (#) on your css. Better stick to class names.
Don't use the wildcard (*) - preferably add the items that will exist inside the autocomplete, which are not shown on the question. And better, wrap them all in another element so you don't have to absolute position all of them individually
I have this HTML code:
<div class="header">
<div class="desc">Description</div>
<div class="logo"><img src=""/></div>
<div class="navbar"></div></div>
.header has a height of 150px. .navbar has a height of 20px. When the user scrolls, I want .navbar to stick at the top. So I went to the CSS and set position:sticky and top:0. But this didn't work. I initially thought that firefox is not supporting position:sticky, but that's not the case because I was able to see a working demo of it. I googled about it but found nothing helpful. Anyone knows why this is not working?
Position sticky was not working for me due to the body element having overflow-x: hidden; set.
The 2 most common culprits why position: sticky; might not work are:
You haven't defined top: 0;, bottom: 0;, left: 0 or something similar
One of the parents of your sticky element has overflow (x or y) set to hidden, scroll or auto.
For me it was the first one.
It works fine if you move the navbar outside the header. See below. For the reason, according to MDN:
The element is positioned according to the normal flow of the document, and then offset relative to its flow root and containing block based on the values of top, right, bottom, and left.
For the containing block:
The containing block is the ancestor to which the element is relatively positioned
So, when I do not misunderstand, the navbar is positioned at offset 0 within the header as soon as it is scrolled outside the viewport (which, clearly, means, you can't see it anymore).
.navbar {
background: hotpink;
width: 100%;
height: 50px;
position: sticky;
top: 0;
}
.header {
height: 150px;
background: grey;
}
body {
height: 800px;
position: relative;
}
<div class="header">
<div class="desc">Description</div>
<div class="logo"><img src="" /></div>
</div>
<div class="navbar"></div>
To expand from the answers above and some information to make it work with flexbox parent and overflow other than visible (the examples below assume you use vertical - sticky with either top or bottom set to a certain value and position set to sticky):
The most frequent case is you have an ancestor element (not just immediate parent) with overflow property set to something other than visible and as a result there is no space is left to stick around.
To quickly find out if this is the case, you can run this script in the browser console (please make sure you change the .your-sticky-element class to your element's selector):
var stickyElement = document.querySelector('.your-sticky-element');
var parent = stickyElement.parentElement;
while (parent) {
var hasOverflow = getComputedStyle(parent).overflow;
if(hasOverflow != 'visible') {
console.log(hasOverflow, parent);
}
parent = parent.parentElement;
}
SOLUTION:
a) If you found there is overflow set, and you can remove it, this should solve it
b) If you have to keep your overflow setting, you have to make the parent element's height higher than the sticky element's height. If the parent element has no height or the sticky element fills up all the height, it means there is simply no place to stick within when the page is scrolled. It doesn't need to an explicit height (vertical), but you can inspect to see if your sticky element has extra space left after itself.
Parent is not higher than the sticky element to leave extra space. This particular case can be caused by different circumstances but the solution to this is the same above, please see 1.b
If your sticky element's parent is a flexbox (align-items has default value of normal) or grid, and if the sticky element itself doesn't have a proper align-self set, there will be no space left for the sticky element to hold when scrolling (for example, if it is align-self: stretch or auto [default value]). This is because the child element is stretched to fill up the height of the parent.
SOLUTION:
In this case, align-self: flex-start set for the sticky element can fix the problem because in the element will stand at the start, leaving extra space after itself.
Guide: There are much more complex circumstances both in the case of flexboxes and without it, but the general rule of thumb is your sticky element needs space within the parent to be sticky when scrolled.
Somehow your code only works when the .navbar element is not inside another container like the header. I moved it out and then it works fine. I created a codepen snippet for that, check it out
<header>
<div class="logo">Logo</div>
<div class="description"><div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo, veritatis.</div></div>
</header>
<div class="navbar">
<ul>
<li>navitem1</li>
<li>navitem2</li>
<li>navitem3</li>
<li>navitem4</li>
</ul>
</div>
Right now position:sticky is supported quite good as you can see on canIuse. Of course IE currently has no support but the new Edge version will bring full support for this! I found some interesting articles about this topic:
Working demo (chrome,firefox 👍) https://codepen.io/simevidas/pen/JbdJRZ
Caniuse refernce: http://caniuse.com/#search=sticky
sticky article on MDN including latest browser support table https://developer.mozilla.org/en-US/docs/Web/CSS/position#Sticky_positioning
But there are good news on the horizon. I think better browser support will follow the next time.
Adding more content after nav inside header provides sticky behavior, but only for a moment - if the user scrolls down too much, nav will disappear with header, since it can't jump out below header's bottom border.
Thus, the only solution with pure CSS is to put nav inside element that is partially visible even after the user scrolls to the bottom of the page (directly inside body or inside some sort of container that spans to the bottom of the page or at least to the footer).
If this solution is not possible, the other way is to use JavaScript. Before transitioning to CSS, I used the following code (found similar jQuery solution somewhere long time ago, don't remember where, so the credit goes to the anonymous author; Vanilla JS can be easily obtained from this):
$(document).ready(function () {
var sticky_navigation_offset_top = $('nav').offset().top;
var sticky_navigation = function () {
var scroll_top = $(window).scrollTop();
if (scroll_top > sticky_navigation_offset_top) {
$('nav').css({
'position': 'fixed',
'top': 0,
'left': 0,
'right': 0,
'margin-left': 'auto',
'margin-right': 'auto'
});
} else {
$('nav').css({
'position': 'relative'
});
}
};
sticky_navigation();
$(window).scroll(function () {
sticky_navigation();
});
});
Looks like if you try to set sticky a container which has many children nodes inside, instead of them being wrapped in a div, and the parent of sticky container is flex, then it will not sticky. Just wrap the childs in a div fixed it for me.
Your HTML code as it is and write CSS class for navigation bar:
.header {
height: 150px;
background-color: #d1d1d1;
}
.navbar {
background: #999;
border-bottom: 1px solid #333;
border-top: 1px solid #333;
color: #FFF;
margin: 0;
padding: 2px 0 0 12px;
position: sticky;
top: -1px;
}
<div class="header">
<div class="desc">Description</div>
<div class="logo"><img src="" /></div>
<div class="navbar"></div>
</div>
Hope this will help
Met some not evident behaviour of horizontal sticky: if width is 100%, then sticky does not work. Width should be less, then container size.
My sticky header would only partly work ... after a couple of scrolls it would disappear but would work initially
It appears the problem was that I had the parent set to height 100%.
I didn't actually need this as the body one was enough so I removed and it and all was good.. sticks forever
Although this now breaks my footer from staying on the bottom when their is no content!
No huge compromises of the HTML structure need to be made to fix this issue. Simply add display: inline; to all of the sticky element's parents up until you get to the element you wish the sticky element to stick to.
Just to add something to #user56reinstatemonica8 great point...
If immediate parent of sticky node has display: flex sticky positioning could not work.
My guess is that culprit is align-items: stretch as default.
In a flex-direction: row scenario, align-items: stretch let children's height grow so that they are equal height.
So, to overcome this and make sticky work as expected with display: flex you can:
define align-items as center | start | baseline to immediate parent that has display: flex.
define align-self as center | start | baseline to sticky node.
define an explicit height to sticky node.
I'm working on a website for a girlfriend of mine.
But I'm stuck positioning a the logo.
Here is the website I'm talking about:
http://xntriek-test.s3-website-eu-west-1.amazonaws.com/
I tried using z-indexes but don't work. I also tried setting an background image for the body.
But then I'm to limited with sizing the image.
I'm using Twitter bootstrap to put this thing together.
At the moment this is the class I'm using for the logo:
.logo{
position: absolute;
top: 25px;
left: 25px;
height: 45%;
width: 30%;
z-index: 1;
}
At the moment I'm positioning the image in a span along side the main content.
But because I'm using position: absolute this wouldn't make a difference were I put it.
If any body has any ideas how I could solve this, maybe a different approach then I'm doing right now. Any help welcome!
You need to modify your CSS along the following:
<div class="span6 offset3" style="position: relative; z-index: 1">
z-index affects positioned elements, so just add position: relative to your span of interest.
I would create a special class "z-wrap" and modify the style sheet.
<div class="span6 offset3 z-wrap">
In CSS style sheet:
.z-wrap {position: relative; z-index: 1}
Reference: https://developer.mozilla.org/en-US/docs/CSS/Understanding_z-index/Adding_z-index
Note You may have to adjust the value of z-index depending on any z-index value you may have set in the logo container.
First you are distorting the logo with your css, if you want your image to be responsive position it in an responsive element, position this absolut and let the image adjust it's size.
#logoContainer {
position:absolute;
top:25px;
left:25px;
width:30%;
z-index:-1;
}
img.logo{
width:100%;
height:auto;
}
your html should look something like this:
<div id="logoContainer">
<img src="yoursrc/logo.gif" alt="The Logo" class="logo" />
</div>
Put this right after the opening of your body tag and not in some other elements.
By putting it in other elements the logo inherits their z-index and you can only influence it's z-positioning inside the parent but not on the overall page.
One thing to remember when using the z-index attribute :
Only the elements placed using their "position" attribute (relative, absolute or fixed), can be affected by the "z-index".
So if you want to fix your issue, either put your logo as a background image, either use position in the CSS of the content.
If I have 2 div tags:
<div id="parentDiv">
<div id="childDiv"><!-- other html --></div>
<!-- parent div html -->
</div>
I want the content of <div id="childDiv"> to overlap the content <!-- parent div html -->.
Reason (in case this looks like bad code design to anyone):
I need a hack workaround in google sites, I cannot add custom code on the sidebar nav, only in the main html space, I want to float a div that takes no space and relatively position it over the side bar to get around the forced limitation.
I can do everything except stop the childDiv from taking up space in it's bastardized main-page container.
You can give it a position absolute, and navigate it with margins.
#childDiv {
position: absolute;
margin-top: -100px;
margin-left: -100px;
}
How about a simple
#childDiv {height:0; overflow:visible;}
But you probably want it to have a background colour, hm? Hm.
#parentDiv {
position: relative;
}
#childDiv {
position:absolute;
top:0;
left:0;
width:100%;
}
If you need to bump the content around, or overlap stuff that is 'outside' of the sidebar, you can use negative margins to increase the width of the childDiv or move it up (to cover padding or margins you can't override).
If you need to make the #childDiv cover the entire #parentDiv, you can use a bit of JavaScript to set a min-height on childDiv, then add a colored background or something to cover any content.
var parentHeight = jQuery('#parentDiv').height();
jQuery('#childDiv').css('min-height',parentHeight + 'px');
You have to take the childblock out of the flow. The best way to do this is position: absolute on the child div and position: relative on the parent div.
I have two DIVs that I need to position exactly on top of each other. However, when I do that, the formatting gets all screwed up because the containing DIV acts like there is no height. I think this is the expected behavior with position:absolute but I need to find a way to position these two elements on top of each other and have the container stretch as the content stretches:
The top left edge of .layer2 should be exactly aligned to the top left edge of layer1
<!-- HTML -->
<div class="container_row">
<div class="layer1">
Lorem ipsum...
</div>
<div class="layer2">
More lorem ipsum...
</div>
</div>
<div class="container_row">
...same HTML as above. This one should never overlap the .container_row above.
</div>
/* CSS */
.container_row {}
.layer1 {
position:absolute;
z-index: 1;
}
.layer2 {
position:absolute;
z-index: 2;
}
Actually this is possible without position absolute and specifying any height. All You need to do, is use display: grid on parent element and put descendants, into the same row and column.
Please check example below, based on Your HTML. I added only <span> and some colors, so You can see the result.
You can also easily change z-index each of descendant elements, to manipulate its visibility (which one should be on top).
.container_row{
display: grid;
}
.layer1, .layer2{
grid-column: 1;
grid-row: 1;
}
.layer1 span{
color: #fff;
background: #000cf6;
}
.layer2{
background: rgba(255, 0, 0, 0.4);
}
<div class="container_row">
<div class="layer1">
<span>Lorem ipsum...<br>Test test</span>
</div>
<div class="layer2">
More lorem ipsum...
</div>
</div>
<div class="container_row">
...same HTML as above. This one should never overlap the .container_row above.
</div>
First of all, you really should be including the position on absolutely positioned elements or you will come across odd and confusing behavior; you probably want to add top: 0; left: 0 to the CSS for both of your absolutely positioned elements. You'll also want to have position: relative on .container_row if you want the absolutely positioned elements to be positioned with respect to their parent rather than the document's body:
If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed' ...
Your problem is that position: absolute removes elements from the normal flow:
It is removed from the normal flow entirely (it has no impact on later siblings). An absolutely positioned box establishes a new containing block for normal flow children and absolutely (but not fixed) positioned descendants. However, the contents of an absolutely positioned element do not flow around any other boxes.
This means that absolutely positioned elements have no effect whatsoever on their parent element's size and your first <div class="container_row"> will have a height of zero.
So you can't do what you're trying to do with absolutely positioned elements unless you know how tall they're going to be (or, equivalently, you can specify their height). If you can specify the heights then you can put the same heights on the .container_row and everything will line up; you could also put a margin-top on the second .container_row to leave room for the absolutely positioned elements. For example:
http://jsfiddle.net/ambiguous/zVBDc/
Here's another solution using display: flex instead of position: absolute or display: grid.
.container_row{
display: flex;
}
.layer1 {
width: 100%;
background-color: rgba(255,0,0,0.5); /* red */
}
.layer2{
width: 100%;
margin-left: -100%;
background-color: rgba(0,0,255,0.5); /* blue */
}
<div class="container_row">
<div class="layer1">
<span>Lorem ipsum...</span>
</div>
<div class="layer2">
More lorem ipsum...
</div>
</div>
<div class="container_row">
...same HTML as above. This one should never overlap the .container_row above.
</div>
Great answer, "mu is too short".
I was seeking the exact same thing, and after reading your post I found a solution that fitted my problem.
I was having two elements of the exact same size and wanted to stack them.
As each have same size, what I could do was to make
position: absolute;
top: 0px;
left: 0px;
on only the last element. This way the first element is inserted correctly, "pushing" the parents height, and the second element is placed on top.
Hopes this helps other people trying to stacking 2+ elements with same (unknown) height.
Here's some reusable css that will preserve the height of each element without using position: absolute:
.stack {
display: grid;
}
.stack > * {
grid-row: 1;
grid-column: 1;
}
The first element in your stack is the background, and the second is the foreground.
I had to set
Container_height = Element1_height = Element2_height
.Container {
position: relative;
}
.ElementOne, .Container ,.ElementTwo{
width: 283px;
height: 71px;
}
.ElementOne {
position:absolute;
}
.ElementTwo{
position:absolute;
}
Use can use z-index to set which one to be on top.
Due to absolute positioning removing the elements from the document flow position: absolute is not the right tool for the job. Depending on the exact layout you want to create you will be successful using negative margins, position:relative or maybe even transform: translate.
Show us a sample of what you want to do we can help you better.
Of course, the problem is all about getting your height back. But how can you do that if you don't know the height ahead of time? Well, if you know what aspect ratio you want to give the container (and keep it responsive), you can get your height back by adding padding to another child of the container, expressed as a percentage.
You can even add a dummy div to the container and set something like padding-top: 56.25% to give the dummy element a height that is a proportion of the container's width. This will push out the container and give it an aspect ratio, in this case 16:9 (56.25%).
Padding and margin use the percentage of the width, that's really the trick here.
After much testing, I have verified that the original question is already right; missing just a couple of settings:
the container_row MUST have position: relative;
the children (...), MUST have position: absolute; left:0;
to make sure the children (...) align exactly over each other, the
container_row should have additional styling:
height:x; line-height:x; vertical-align:middle;
text-align:center; could, also, help.