Absolutely positioned element is scrolled with content, why? - html

I have the following setup: (try scrolling the content)
HTML
<div class="wrapper">
<div class="backdrop"></div>
<div class="content">
1<br>
2<br>
3<br>
4<br>
5<br>
6<br>
7<br>
</div>
</div>
CSS:
.wrapper {
height: 100px;
overflow: auto;
border: 1px solid black;
position: relative;
}
.backdrop {
position: absolute;
top:0;
left: 0;
bottom:0;
right: 0;
background: red;
}
The problem is that backdrop for some reason is scrolled top with the content. Why is this happening? I was expecting the backdrop to remain still since it's positioned relative to the wrapper borders, not content's.

The scrollable area is defined by the wrapper via its overflow: auto declaration. Since wrapper serves as the containing block for both the content and the backdrop (due to position: relative), this causes both elements to scroll together. In other words, this is due to both overflow: auto and position: relative on the same parent element, working in tandem.
Note that absolute positioning does not make an element immune to scrolling; when an absposed element does not appear to scroll, that is simply because its containing block does not scroll, and whatever is scrolling apart from the absposed element is some other element that is not its containing block. That is not the case in your setup. See the last example in section 11.1.1 of the spec for another example of this.

Related

Horizontal scroll not working on a div element

#Here, I'm trying to create horizontal scrolling for a div element for my application. The div element consists of ul li element and some other div tags for my requirement. The Ul li elements are dynamically added inside the parent div element.
Although I could get the vertical scrolling working properly and my horizontal scrolling is displayed using overflow-x: scroll. I am not able to scroll it, the ul li elements gets distorted. I have set a predefined width of 700px for the div container also. Its like the horizontal scrolling is disabled. I am not using overflow anywhere else in the application
<div class="org-chart" appOrgachart [empArr]="employees" [orgaArr]="orgaArr" *ngIf="employees.length>0 && !isLoading">
<ul>
<li *ngFor="let emp of empArr">
<div class="user">
<div class="name">{{emp.empname}}</div>
<div class="role">{{emp.empdesgname}}</div>
</div>
</li>
</ul>
</div>
My CSS file:
.org-chart {
display: flex;
justify-content: center;
left: 29px;
position: relative;
overflow-x: scroll !important;
overflow-y: scroll;
height: 400px;
width: 65%;
transform: translateY(12%);
}
Looking at your code, providing overflow-x: scroll !important; is big no no from me, it should be the last option for you to use.
now coming to your requirement, you need to specifically provide overflow-x: scroll if you give overflow:auto it automatically gives you a scroll when needed.
now when is it??
when the height and width is more than the browser size that is when you will get the scrolling feature.
if you need a scroll within browser size then, decrease the width of the container and apply overflow:auto; that should give you a scroll on sight.
here is the example of what I am saying:
so what does it mean is when you want a scroll within the browser then you should have a child class and the width of that class should be less w.r.t the content so that it can overflow.
.org-chart {
display: flex;
justify-content: center;
left: 29px;
position: relative;
overflow: auto;
border: 1px solid black;
/*Main container */
height: 300px;
width: 65%;
}
.content {
width: 100%;
/* you should have another width inside main container */
border: 1px solid red;
}
<div class="org-chart" appOrgachart [empArr]="employees" [orgaArr]="orgaArr" *ngIf="employees.length>0 && !isLoading">
<ul>
<li *ngFor="let emp of empArr">
<div class="user">
<div class="name">{{emp.empname}}</div>
<div class="role">{{emp.empdesgname}}</div>
<div class="content">Notice that the text-align-last property sets the alignment for all last lines within the selected element. So, if you have a with three paragraphs in it, text-align-last will apply to the last line of EACH of the paragraphs. To use text-align-last
on only the last paragraph in the container, you can use :last child, see example below. Notice that the text-align-last property sets the alignment for all last lines within the selected element. So, if you have a with three paragraphs in it,
text-align-last will apply to the last line of EACH of the paragraphs. To use text-align-last on only the last paragraph in the container, you can use :last child, see example below. Notice that the text-align-last property sets the alignment
for all last lines within the selected element. So, if you have a with three paragraphs in it, text-align-last will apply to the last line of EACH of the paragraphs. To use text-align-last on only the last paragraph in the container, you can
use :last child, see example below. Notice that the text-align-last property sets the alignment for all last lines within the selected element. So, if you have a with three paragraphs in it, text-align-last will apply to the last line of EACH
of the paragraphs. To use text-align-last on only the last paragraph in the container, you can use :last child, see example below.</div>
</div>
</li>
</ul>
</div>
apply max-width property as 64% and overflow:auto

Why does height 100% work on absolutely positioned element?

As far as I know for the height to work as percentage the container element must have a specific height mentioned. But this doesn't hold true for absolutely positioned element with the ancestor being relatively positioned. Here is a working example of what I meant:
.container {
width: 400px;
background: cyan;
text-align: right;
position: relative;
color: white;
}
.child {
width: 90%;
height: 100%;
background: blue;
}
.absolute {
position: absolute;
}
.second {
margin-top: 30px;
}
<div class="container">
<div class="child absolute">Absolute</div>
one <br> two <br> three <br> one <br> two <br> three <br>
</div>
<div class="container second">
<div class="child">Static</div>
one <br> two <br> three <br> one <br> two <br> three <br>
</div>
As you can see the absolutely placed div applied 100% height onto it but not the statically positioned div. Why?
From MDN
relative
This keyword lays out all elements as though the element were not positioned, and then adjusts the element's position, without changing layout (and thus leaving a gap for the element where it would have been had it not been positioned). The effect of position:relative on table-*-group, table-row, table-column, table-cell, and table-caption elements is undefined.
Read more. Is very nicely described.
Here is a great read about the different position types:
Absolute is relative to the parent element and is not affected by other elements and are removed from the flow of the page i.e. you can see the list with one, two, three unaffected.
It's height is 100% as .child specifies.

How to have a div fixed only inside one div and change to position: absolute when it starts overlapping with following div

Say I have three divs like following:
<div class="wrapper">
<div class="container">
container1
<div class="element">
fixed
</div>
</div>
<div class="container2">
container2
</div>
</div>
I want div: element to be fixed when it is inside div: container, but its position should become absolute when div: container2 becomes visible, it should not overlap with div - container2, but scroll away at that time with div: container.
A pure CSS solution is preferable, but if not possible I may go for a JS or jquery solution. I have created a fiddle for this, and tried some solution suggested here, which are not working.
What I would suggest is to use javascript to recognize when the scrolling is at a certain point with window.pageYOffset
When it reaches your desired window Y Offset you can start an event that modifies the css value of the positioning from fixed to absolute (by setting the parent container to relative) and bottom at 0.
Check out this jsfiddle https://jsfiddle.net/zq0kkkcx/2/
Also, this is the code that I'm talking about:
document.addEventListener("scroll", function(event) {
if(window.pageYOffset >= 1200){
console.log("1200");
// this is where you want your element to become absolute
// positioned to his parent container
// write your css changes here and apply them to elements
// add relative to container and absolute with bottom 0 to element
} if (window.pageYOffset <= 1200){
console.log("<1200");
}
});
If you want a CSS solution, here is a trick that you can do using z-index. Other than this there is a JS solution.
.wrapper {
width:100%
}
.container {
width:300px;
margin:0 auto;
height:1200px;
background:#ccc;
position: relative;
z-index: -1;
}
.container2{
width:300px;
margin:0 auto;
height:1200px;
background:#fcf;
z-index: 1;
}
.element {
background:#f2f2f2;
position:fixed;
width:50px;
height:70px;
margin-left:250px;
border:0px solid #d6d6d6;
}
<div class="wrapper">
<div class="container">
container1
<div class="element">
fixed
</div>
</div>
<div class="container2">
container2
</div>
</div>
You're looking for a sticky header. There is currently no way to make a header sticky at an arbitrary scroll position using pure CSS - you'll have to look into a JavaScript solution to accomplish that.
Yes, it is 100% possible to do this without any JavaScript
I updated your fiddle
Markup should be like this
<div class="wrapper">
<div class="outer-scroller">
<div class="scroll-container">
container1
<div class="fixed-header">
fixed
</div>
</div>
</div>
<div class="last-container">
container2
</div>
</div>
and css
.wrapper {
width: 100%;
height: 300px;
}
.outer-scroller {
height: 140px;
overflow-y: scroll;
}
.scroll-container {
padding-top: 70px;
width: 300px;
height: 1200px;
background: #CCC;
}
.last-container {
width: 300px;
height: 600px;
background: #FCF;
}
.fixed-header {
background: #F2F2F2;
position: absolute;
width: 300px;
height: 70px;
top: 0;
pointer-events: none;
}
You'll see I've added an outer-scroller div.
The next bit is changing your CSS slightly
The new outer-scroller div is double the height of your fixed-header (for the purposes of this example) and it has an overflow-y: scroll on it.
The container inside there is still the same.
The next change is turning your position: fixed into a position: absolute and then adding padding to the top part of the div you want to scroll in order to push its content "below" the new "fixed" header.
Scrolling over the outer-scroller div then makes its content scroll, and because its height is set with an absolute element on top it then scrolls "under" the fixed header.
Once the bottom of its child content scroll-container is reached, the whole page then continues scrolling, and you get the illusion of the header disappearing.
The last bit is pointer-events: none on the header so that it doesn't scroll away when the cursor is over it (but the div below does)

Set Width of Element Wider than Parent when using Relative Positioning

I have an element (in my case a HR tag) that needs to be as wide as the browser but which is also wider than it's parent container. However, it still needs to maintain relative positioning so that it scrolls vertically with the page. The problem is that my parent div has to have relative positioning as well (due to other layouts that are working).
The only way I have been able to solve this is to set the width of the HR tag to 3000px with a left position of -1000px. This works, but it adds a horizontal scrollbar to the page (to display the 3000px width). Is there any way to accomplish this cleanly (without the horizontal scroll bar)? You can see my fiddle at http://jsfiddle.net/UGwst/.
Here's the HTML:
<div id="layout-wrapper">
<p>Above Content</p>
<div id="content-wrapper">
<p>Top Content Here</p>
<hr class="rule" />
<p>Bottom Content Here</p>
</div>
</div>​
Here's the CSS:
#content-wrapper {
width: 400px;
margin-left: auto;
margin-right: auto;
margin-top: 8px;
background-color: #ddd;
position: relative;
}
.rule {
background-color: #dbb328;
height: 5px;
position: relative;
left: -1000px;
width: 3000px;
}
​
I realize that there are a couple of other questions here that are similar, but don't quite seem to fix this issue.
Use position:relative on the parent.
Use position:absolute on the HR, that way the HR is bound to the parent and will scroll with it.
To hide scroll bars use overflow:hidden on your outer wrapper, or BODY.
Try
body {overflow-x: hidden;}
to eliminate the horizontal scrollbar. According to this answer, it even works in IE6 - CSS - Only Horizontal Overflow?

Avoid an Element from being cut off when they are inside a "overflow: hidden" element

I'm using the equal heights CSS trick as outlined on this page.
It was all working fine until today when I need to add a dialogue box inside one of the columns, which is absolutely positioned to take it out of the flow. The problem is that since the container has "overflow: hidden" on it, the dialogue is being cut off when it overflows.
Aside from bringing the dialogue outside of the container element, is there any possible way to get it to show via CSS?
Here's a small example demonstrating what I've mentioned.
<style>
.container { overflow: hidden; margin-top: 30px }
.col {
float: left;
padding-bottom: 2000px;
margin-bottom: -2000px;
border-right: 1px solid black;
width: 100px;
background-color: grey;
}
.col.third { border-right: none }
#div-a { position: relative }
#div-b {
position: absolute;
background-color: red;
width: 35px;
height: 350px;
bottom: 0;
right: 0;
margin: 5px;
border: 2px solid black;
}
</style>
<div class="container">
<div class="col first">
<p style="height: 100px">One</p>
</div>
<div class="col second">
<p style="height: 300px">Two</p>
<div id="div-a">
<!-- this gets cut off by the "overflow: hidden" on div.container -->
<div id="div-b">
Foo
</div>
</div>
</div>
<div class="col third">
<p style="height: 200px">Three</p>
</div>
</div>
You see that div#div-b is cut off at the top when it overflows in the div.container element.
Unfortunately what you want to do is impossible without bringing the dialogue outside of the container element.
Your best bet is to make the dialog element a sibling of the container and position it that way.
Unfortunately no... I don't think there's a way to circumvent overflow: hidden with absolute position. You may experiment with position: fixed, but you won't be positioning under quite the same conditions if you use it.
One option would be to place the content of your overflow:hidden container into a sub-container (a child div perhaps). Then, make the sub-container match the dimensions of the container and move the overflow:hidden from the container to the sub-container.
Then, you can make the dialog a child of the container (a sibling of the sub-container), and it will now exist in an element that does NOT have overflow:hidden.
I haven't tested this, and removing the overflow:hidden from the container may break your design. If that is the case, I would suggest doing as others have and moving the dialog box outside of the container entirely. This could even be done via Javascript if you don't have the option of putting the dialog box's code anywhere else. (Javascript could make the dialog box a child of BODY, or some other tag, when you need it displayed)