CSS sticky to left only [duplicate] - css

Why my nested sticky element with left: 0 does not stick while the nested element with top: 0 sticks normally?
.scroll {
width: 200px;
height: 200px;
border: 1px solid;
overflow: auto;
}
.container {
width: 600px;
height: 1000px;
}
.sticky-left {
position: sticky;
left: 0;
}
.sticky-top {
position: sticky;
top: 0;
}
<div class="scroll">
<div class="sticky-top">sticky-top</div>
<div class="sticky-left">sticky-left</div>
<div class="container">
<div class="sticky-top">sticky-top-nested</div>
<div class="sticky-left">sticky-left-nested</div>
</div>
</div>

Let's add some border and we will clearly see what is happening:
.scroll {
width: 200px;
height: 200px;
border: 1px solid;
overflow: auto;
}
.scroll > div {
border:2px solid green;
}
.container {
width: 600px;
height: 1000px;
border:2px solid red!important;
}
.container > div {
border:2px solid green;
}
.sticky-left {
position: sticky;
left: 0;
}
.sticky-top {
position: sticky;
top: 0;
}
<div class="scroll">
<div class="sticky-top">sticky-top</div>
<div class="sticky-left">sticky-left</div>
<div class="container">
<div class="sticky-top">sticky-top-nested</div>
<div class="sticky-left">sticky-left-nested</div>
</div>
</div>
As you can see, the nested sticky elements are both having their width equal to parent width (since they are block element) so there is no room for the left-sticky to have any sticky behavior1 since it has width:100% unlike the top one that can still stick because its height is less that the parent height.
For the non-nested elements I think it's clear.
Make the element inline-block or reduce the width and you will have a sticky behavior:
.scroll {
width: 200px;
height: 200px;
border: 1px solid;
overflow: auto;
}
.scroll > div {
border:2px solid green;
}
.container {
width: 600px;
height: 1000px;
border:2px solid red!important;
}
.container > div {
border:2px solid green;
width:150px;
}
.sticky-left {
position: sticky;
left: 0;
}
.sticky-top {
position: sticky;
top: 0;
}
<div class="scroll">
<div class="sticky-top">sticky-top</div>
<div class="sticky-left">sticky-left</div>
<div class="container">
<div class="sticky-top">sticky-top-nested</div>
<div class="sticky-left">sticky-left-nested</div>
</div>
</div>
1 A stickily positioned element is an element whose computed position value is sticky. It's treated as relatively positioned until its containing block crosses a specified threshold (such as setting top to value other than auto) within its flow root (or the container it scrolls within), at which point it is treated as "stuck" until meeting the opposite edge of its containing block.ref
In your case you were always meeting the opposite edge.

As per the MDN documentation on position: sticky, the top, right, bottom, and left properties determine the final location of positioned elements. My guess is that in order for it to be stickied from the top, it needs to also contain top: 0. The snippet I added seems to work.
.scroll {
width: 200px;
height: 200px;
border: 1px solid;
overflow: auto;
}
.container {
width: 600px;
height: 1000px;
}
.sticky-left {
position: sticky;
left: 0;
top: 0; // Add this so it sticks to top
}
.sticky-top {
position: sticky;
top: 0;
}
<div class="scroll">
<div class="sticky-top">sticky-top</div>
<div class="sticky-left">sticky-left</div>
<div class="container">
<div class="sticky-top">sticky-top-nested</div>
<div class="sticky-left">sticky-left-nested</div>
</div>
</div>

Related

Unstick position sticky element when it reaches a position absolute sibling within a container

I have a container which has a sticky element that sticks to the top, within the container, there's also a position absolute element at the bottom. I only want the sticky element to be sticky up to the point when it reaches the bottom element.
My solution requires knowing the bottom element height in order to reserve a min-height for the sticky element to be sticky.
Is there a way to do it without know the height of the bottom position absolute element?
.container {
height: 1000px;
}
aside {
background: palegoldenrod;
height: 600px;
width: 300px;
position: relative;
}
.stickyWrapper {
min-height: calc(100% - 100px);
}
.sticky {
position: sticky;
top: 0;
}
.stickyItem {
background: pink;
height: 100px;
color: #000;
}
.bottomThing {
position: absolute;
bottom: 0;
height: 100px;
background: blue;
color: #fff;
width: 100%;
}
<div class="container">
<aside>
<div class="stickyWrapper">
<div class="sticky">
<div class="stickyItem">
sticky item
</div>
</div>
</div>
<div class="bottomThing">
position absolute
</div>
</aside>
</div>
I've worked out a solution by using flexbox. I will also no longer need the bottom element to be position absolute.
.container {
height: 1000px;
}
aside {
background: palegoldenrod;
height: 600px;
width: 300px;
position: relative;
display: flex;
flex-direction: column;
}
.stickyWrapper {
flex-grow: 1;
}
.sticky {
position: sticky;
top: 0;
}
.stickyItem {
background: pink;
height: 100px;
color: #000;
}
.bottomThing {
height: 100px;
background: blue;
color: #fff;
width: 100%;
}
<div class="container">
<aside>
<div class="stickyWrapper">
<div class="sticky">
<div class="stickyItem">
sticky item
</div>
</div>
</div>
<div class="bottomThing">
position absolute
</div>
</aside>
</div>

DIV moved with position: relative create gap between that div and next one

I have 2 div's, one after the other. When i move first div with postion: relative and top: -60px it creates gap between them.
Here is example: https://codepen.io/dusannis/pen/oNgBpoK
As you can see there is gap between red and yellow div. Is there some css property that I can add to parent div that can remove this gap, or something simillar?
This is HTML:
<body>
<div class="container">
<div class="div-1">
<p>something here</p>
</div>
<div class="div-2"></div>
</div>
</body>
This is CSS:
body {
background: blue;
padding: 60px
}
.div-1 {
padding: 60px;
position: relative;
top: -50px;
background: red;
}
.div-2 {
height: 50px;
background: yellow;
}
Use negative margin instead of relative positioning.
body {
background: blue;
padding: 60px
}
.div-1 {
padding: 60px;
/* position: relative; --> not required */
margin-top: -50px;
/* change this */
background: red;
}
.div-2 {
height: 50px;
background: yellow;
}
<div class="container">
<div class="div-1">
<p>something here</p>
</div>
<div class="div-2"></div>
</div>
Codepen Demo of the effects of various methods of "moving" elements:
"Relative Position vs Margin vs Transform".
You can try add same top/position to the second div:
.div-1 {
padding: 60px;
position: relative;
top: -60px;
background: red;
}
.div-2 {
position: relative;
top: -60px;
height: 50px;
background: yellow;
}
Alternatively you can add internal div and use padding for that one, then get rid of padding for the parent and the body (or adjust to the real value if you want it):
<body>
<div class="container">
<div class="div-1">
<div class="div-1-inside">
something here
</div>
</div>
<div class="div-2"></div>
</div>
</body>
body {
background: blue;
padding: 10px;
}
.div-1 {
position: relative;
background: red;
}
.div-1-inside {
padding: 60px;
background: red;
}
.div-2 {
height: 50px;
background: yellow;
}

Overflow element without cutting absolutely positioned elements in it

In a container element I have floated element and an absolutely positioned image that needs to protrude from container. However I need container to keep its height because it has a margin-bottom that separate it from the next block below it.
Problem: container's overflow: hidden cuts the image off so it cannot protrude from it. So I have to choose between 2 things I absolutely need: the image to protrude and container to keep its height.
How to solve this dilemma?
HTML
<div class='container'>
<div class='col1'>
content
</div>
<div class='col2'>
<img src='whatever.jpg'/>
</div>
</div>
CSS
.container {
overflow: hidden;
}
.col1,
.col2 {
float: left;
width: 50%;
}
.col2 {
position: relative;
}
img {
position: absolute;
top: -100px;
left: -100px;
}
Is the overflow to contain the floats? If so there are several other methods.
These can be found here
The modern method is:
.container:after {
content:"";
display:table;
clear:both;
}
.container {
width: 80%;
border: 1px solid grey;
margin: 100px auto;
background: pink;
}
.container:after {
content: "";
display: table;
clear: both;
}
.col1,
.col2 {
float: left;
width: 50%;
height: 150px;
}
.col2 {
position: relative;
background: #c0ffee;
}
img {
position: absolute;
top: -100px;
left: -100px;
}
<div class='container'>
<div class='col1'>
content
</div>
<div class='col2'>
<img src='http://www.fillmurray.com/200/200' />
</div>
</div>

CSS width is automatically maximum in one row

I have 2 divs in a row (with inline-blocks). One of them has a fixed width and the other one is supposed to automatically fill the left space. How can I do that?
My favorite solution is to use padding on the container block and absolute position on the fixed with object:
.wrapper {
padding-left: 100px;
position: relative;
}
.stay {
width: 100px;
position: absolute;
left: 0;
top: 0;
/* for demo */
height: 50px;
background-color: pink;
}
.fit {
width: 100%;
/* for demo */
height: 50px;
background-color: red;
}
HTML:
<div class="wrapper">
<div class="stay"></div>
<div class="fit"></div>
</div>

Firefox table-cell and full width absolutely positioned children

I've stumbled upon some unexpected behaviour when testing a layout in Firefox. It seems that when a parent is set to display:table-cell and position:relative, its children do not respect the parent width when positioned absolutely and given 100% width. Instead, the child width is set to the parent's parent width. I've recreated this issue with a fiddle:
http://jsfiddle.net/D6Rch/1/
which is structured as:
<div class="table">
<div class="cell-1">
<div class="content-1">this must be positioned absolutely</div>
<div class="content-2">as these divs will be overlapping</div>
</div>
<div class="cell-2">
<div class="advert">fixed width advert</div>
</div>
</div>
.table {
width:600px;
height:400px;
border:3px solid black;
display: table;
position: relative;
table-layout: fixed;
}
.cell-1 {
width: auto;
display: table-cell;
background: yellow;
position: relative;
margin-right:10px;
}
.cell-2 {
margin-right:10px;
width: 100px;
display: table-cell;
background: pink;
position: relative;
}
.content-1 {
position: absolute;
top: 10px;
width: 100%;
background: lightgreen;
z-index: 5;
}
.content-2 {
position: absolute;
top: 50px;
width: 100%;
background: lightblue;
z-index: 5;
}
.advert {
position: relative;
border: 1px solid red;
}
It functions as expected in Chrome & Safari, but not on Firefox. Question is, why does this happen? And is there a workaround for this or should I take an altogether different approach?
Thanks in advance,
This is a known bug in Gecko. See the Gecko Notes here - https://developer.mozilla.org/en-US/docs/Web/CSS/position
So, you'll have to wrap you content divs in another positioned div. Like so
http://jsfiddle.net/D6Rch/4/
<div class="cell-1">
<div class="wrapper">
<div class="content-1">this must be positioned absolutely</div>
<div class="content-2">as these divs will be overlapping</div>
</div>
</div>
.wrapper {
position: relative;
}

Resources