'Sticky' element inside a 'Fixed' element slides in the opposite direction - javascript

I have a child div that needs to be positioned fixed with respect to a wrapper which is way up in the DOM hierarchy (instead of the viewport/parent element). I am creating a new stacking context in order to achieve this.
The child div also has some sticky elements in it. And its parent has horizontal scroll.
Am facing an issue when I scroll the parent div. It ends up sliding the sticky elements too, which is the desired behavior, but why do the elements stick to the right edge instead of left?
http://jsfiddle.net/5vhsg1Ln/2/
<div class="wrapper">
<p>
This is some content which is outside of ggparent div. I want the 'child' to be positioned relative to this div.
</p>
<div class='ggparent'>
<p>
This is the great grand parent. This div is vertically scrollable.
</p>
<div class='gparent'>
<p>
This is the grand parent div.
</p>
<div class='parent'>
<p>
Horizontal scroll here... This is the parent div with some text.
</p>
<div class='child'>
<span class='sticky'>
Sticky 1
</span>
<span class='sticky2'>
Sticky 2
</span>
<p>
This is the child. Positioned fixed to wrapper.
</p>
</div>
</div>
<div class='parent2'>
<p>
This is another parent div with some text.
</p>
</div>
</div>
</div>
</div>
div{border:1px solid #ddd;}
.wrapper {
transform: rotate(0deg); /* new stacking context */
overflow-y: hidden;
}
.ggparent {
height: 300px;
width: 400px;
overflow-y: scroll;
}
.gparent{
height: 600px;
width: 300px;
}
.parent, .parent2{
height: 300px;
width: 200px;
white-space: nowrap;
overflow-x: scroll;
position: relative; /* For the sticky element in child */
}
.child {
height: 100px;
width: 200px;
position: fixed; /* gets fixed to wrapper */
top: 225px;
background-color: lightblue;
white-space: normal;
}
.sticky {
position: sticky;
left: 0px;
z-index: 1;
}
.sticky2 {
position: sticky;
left: 50px;
z-index: 1;
}
Any help is appreciated. Thanks in advance!

Related

how to apply overflow:hidden for children of children with absolute positioning [duplicate]

We have two DIVs, one embedded in the other. If the outer DIV is not positioned absolute then the inner DIV, which is positioned absolute, does not obey the overflow hidden of the outer DIV.
#first {
width: 200px;
height: 200px;
background-color: green;
overflow: hidden;
}
#second {
width: 50px;
height: 50px;
background-color: red;
position: absolute;
left: 250px;
top: 250px;
}
<div id="first">
<div id="second"></div>
<div id="third"></div>
</div>
Is there any chance to make the inner DIV obey the overflow hidden of the outer DIV without setting the outer DIV to position absolute (cause that will muck up our complete layout)?
Also position relative for our inner DIV isn't an option as we need to "grow out" of a table TD.
#first {
width: 200px;
height: 200px;
background-color: green;
}
#second {
width: 50px;
height: 400px;
background-color: red;
position: relative;
left: 0px;
top: 0px;
}
<table id="first">
<tr>
<td>
<div id="second"></div>
</td>
</tr>
</table>
Are there any other options?
Make outer <div> to position: relative and inner <div> to position: absolute. It should work for you.
What about position: relative for the outer div? In the example that hides the inner one. It also won't move it in its layout since you don't specify a top or left.
An absolutely positioned element is actually positioned regarding a relative parent, or the nearest found relative parent. So the element with overflow: hidden should be between relative and absolute positioned elements:
<div class="relative-parent">
<div class="hiding-parent">
<div class="child"></div>
</div>
</div>
.relative-parent {
position:relative;
}
.hiding-parent {
overflow:hidden;
}
.child {
position:absolute;
}
Make sure.
parent position relative.
parent have manually assigned width and height(important as child element having absolute position).
child position absolute;
.outer{
position:relative;
width:200px;
height:100px;
overflow:hidden;
}
.inner{
position:absolute;
width:100px;
height:100px;
font-size:3rem;
}
<div class="outer">
<div class=inner>
Inner DIV to apply overflw hidden
</div>
</div>
}
You just make divs like this:
<div style="width:100px; height: 100px; border:1px solid; overflow:hidden; ">
<br/>
<div style="position:inherit; width: 200px; height:200px; background:yellow;">
<br/>
<div style="position:absolute; width: 500px; height:50px; background:Pink; z-index: 99;">
<br/>
</div>
</div>
</div>
I hope this code will help you :)

CSS: position absolute varying the div width

I am having the following div structure in a part of my site. There are two divs one below another. The first div is divided into two elements. One div (63%) and a button.
Below this, there is another div which is having same 63% as width and position as absolute.
Having the position as absolute not resulting in the two divs with the same width in the same size.
A part of CSS code
#two{
border: 1px solid;
width: 63%;
position: absolute; //Enabling this resulting in varying size even width is same
}
This is my code pen link, https://codepen.io/JGSpark/pen/bZyvEV?editors=1100
I would like to have two divs in the same size as the position absolute. Is there something I can try out here?
When you add position: absolute not relative to any element it is positioned relative to the root element.
A 63% textValue is 63% of #one element but 63% of #two is 63% of the document which includes the default body margin. So reset this to zero:
body {
margin: 0; /* added */
}
#template {
width: 30%;
}
#textValue {
border: 1px solid red;
width: 63%;
float: left;
}
#icon {
width: 5%;
}
#text {
width: 95%;
float: left;
}
#one {
width: 100%;
}
#two {
border: 1px solid;
width: 63%;
position: absolute;
}
<div id="one" class="row">
<div id="textValue"><span id="text">ONE Inner text</span><span id="icon"><i class="fa fa-angle-up"></i></span></div>
<button id="template" class="btn primary">Template</button>
</div>
<div id="two">TWO</div>
Or you can add a wrapper to the element which has position: relative - see demo below:
.wrapper {
position: relative; /* added */
}
#template {
width: 30%;
}
#textValue {
border: 1px solid red;
width: 63%;
float: left;
}
#icon {
width: 5%;
}
#text {
width: 95%;
float: left;
}
#one {
width: 100%;
}
#two {
border: 1px solid;
width: 63%;
position: absolute;
}
<div class="wrapper">
<div id="one" class="row">
<div id="textValue"><span id="text">ONE Inner text</span><span id="icon "><i class="fa fa-angle-up "></i></span></div>
<button id="template" class="btn primary ">Template</button>
</div>
<div id="two">TWO</div>
</div>
We able to add parent div with position:relative. Or Just add position:relative to body tag.
<div style="position: relative;">
<div id="one" class="row">
<div id="textValue"><span id="text">ONE Inner text</span><span id="icon"><i class="fa fa-angle-up"></i></span></div>
<button id="template" class="btn primary">Template</button>
</div>
<div id="two">TWO</div>
</div>
Position absolute need to be relative to something, in this case it is relative to the document which has default margin and padding. Try this:
<div class="wrapper">
<div id="one" class="row">
<div id="textValue"><span id="text">ONE Inner text</span><span id="icon"><i
class="fa fa-angle-up"></i></span></div>
<button id="template" class="btn primary">Template</button>
</div>
<div id="two">TWO</div>
</div>
in css add:
.wrapper {
position:relative;
}
In your case the #textValue that is inside #one is 63% that is 63% of #one div.
where as the #two div is given absolute without giving a parent element position relative so it is taking relative to body element that is comparatively bigger than the #one div so
you able to see the difference even though you have given a same width.

is there a way to get the inherited width of position:absolute elements?

Here the second div is positioned absolute. first div is taking 60% of outer div width, but the second div is taking 60% width of the whole screen. I know that by giving position: relative for the first div will solve the problem.Is there a way to solve it other than by giving position: relative?
.outer {
height: 100px;
width: 100px;
}
.first {
background: black;
width: 60%;
color: white;
}
.second {
position: absolute;
width: inherit;
background: yellow;
color: black;
}
<div class="outer">
<div class="first">
parent
<div class="second">
child
</div>
</div>
</div>
If the outer div will have a defined width you can rely on CSS variable to define the percentage and inherit will work like expected:
.outer {
height: 100px;
--w:100px;
width: var(--w);
}
.first {
background: black;
width: calc(0.6 * var(--w));
color: white;
}
.second {
position: absolute;
width: inherit;
background: yellow;
color: black;
}
<div class="outer">
<div class="first">
parent
<div class="second">
child
</div>
</div>
</div>
If you don't know in advance the width of your parent, you can compute its width in javascript with a document.getElementById('parentID').getBoundingRect().width and use that value to resize your child element to 60% of this value.
But why would you not want to use position: relative on the parent ?

Create a fixed header for an internal container

I would like to create a fixed header bar,
but the problem is that the header is not a full width navbar like always.
It is a header of the middle container, I have sidebar and container.
So the sidebar should be have the same,
but the container header should stay at the top when I scroll the container.
just like in this code example:
https://plnkr.co/edit/RxSkde8M5wkNg5XoFNEF?p=preview
The pink header "HEADER HERE" should stay at the top always.
code from example:
<div id="wrapper">
<div class="side">
side content
</div>
<div class="content">
<div class="header">
HEADER HERE
</div>
<div class="inner">
dontcare long content
</div>
</div>
</div>
I had fixed it for you: https://plnkr.co/edit/CO910df64twLhEvuaWvb?p=preview;
Explanation
You set the header in position fixed (fixed to the screen). So a part of your content will be under the header. So here I put a padding-top on the content (you can replace it with a margin). The value of the padding-top has to be the same as the height of the header.
.content {
background: blue;
width: 70%;
float: left;
position: relative;
padding-top: 2rem;
}
.content .header {
position: fixed;
top: 0;
width: 100%;
background: pink;
height: 2rem;
}
use this style in your header div
<div style="position: fixed; width: 100%" class="header">
HEADER HERE
</div>
.content .header {background: pink;top:0;position:fixed;width:100%;}
Adding the following to the .content .header makes the header stay at the top always
Just add position: fixed to your .header class
.content .header {
background: pink;
position: fixed;
top: 0;
}

How to get rid of flicker during scrolling for artificially fixed elements?

This is a very simple example of sticking an element at the top of another element's visible area. When .container is scrolled, .fixed stays at the top.
<div class="container">
<div class="fixed">fixed content</div>
<div class="content">regular content<br/>regular content<br/>regular content<br/>regular content<br/>regular content</div>
</div>
<style type="text/css">
.container {
position: relative;
border: 1px solid blue;
overflow: auto;
width: 250px;
height: 250px;
}
.content {
height: 500px;
width: 500px;
}
.fixed {
position: absolute;
width: 500px;
margin-top: 2rem;
border 1px solid red;
}
</style>
<script type="text/javascript">
$('.container').scroll(function () {
var top = $('.container').prop('scrollTop');
console.log(top);
$('.fixed').css('top', top);
});
</script>
The problem with this is that if the browser is not fast enough, the .fixed element flickers when I scroll. It lags behind the scroll (compare the position of the text in .fixed to the text in .content as you're scrolling). On my desktop it works flawlessly, but when I try running this in Chromium in a virtual machine, I can see the flicker.
Is there any other way to catch the scroll event and set the position of my .fixed element before the browser renders the page?
edit Updated example to include horizontal scrolling. The fixed element should only be fixed vertically.
Use a double container:
<div class="container-wrapper">
<div class="fixed">fixed content</div>
<div class="container">
<div class="content">regular content<br/>regular content<br/>regular content<br/>regular content<br/>regular content</div>
</div>
</div>
With the CSS:
.container-wrapper {
position: relative;
border: 1px solid blue;
overflow: hidden;
width: 250px;
height: 250px;
}
.container {
overflow: auto;
width: 100%;
height: 100%;
}
.content {
height: 500px;
}
.fixed {
position: absolute;
top: 0px;
left: 0px;
width: 245px;
border 1px solid red;
z-index: 10;
}
This way you won't need jQuery to reposition the .fixed div when you scroll, and it won't flicker.
EDIT To address the horizontal scrolling...
$('.container').on('scroll', function() {
var left = this.scrollLeft;
$('.fixed').css('left', -left + 'px');
});
This should move the .fixed div without flickering. In your solution, the flickering was caused because the browser moved your div while scrolling, and the event handler then moved it again. Now it will only move once.

Categories