How to make position fixed item same width as flex parent - css

I want the fixed progress bar have same width as the yellow container and always positioned at the bottom of screen which overlapping on top of yellow container with CSS.
I have try to using width: inherit in the fixed child but the yellow parent do not have width so it doesn't work.
.container {
display: flex;
width: 500px;
height: 1200px;
}
.left {
flex: 1;
background: blue;
}
.right {
flex: 1;
background: yellow;
}
.progress {
position: fixed;
background: gray;
bottom: 0;
}
<div class="container">
<div class="left">
</div>
<div class="right">
<div class="progress">I'm progress bar</div>
</div>
</div>

Position fixed will be fixed to the page's scroll position and should not be used as a child of a static element.
Instead, you should set position to absolute on the progress bar, and position relative on the container.
.container {
position: relative;
}
.child {
position: absolute;
width: 100%;
left: 0;
}
.container {
position: relative;
display: flex;
width: 500px;
height: 100px;
}
.left {
flex: 1;
background: blue;
}
.right {
flex: 1;
background: yellow;
}
.progress {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background: gray;
}
<div class="container">
<div class="left">
</div>
<div class="right">
<div class="progress">I'm progress bar</div>
</div>
</div>
Alternatively, you can use JavaScript to match two elements width's while keeping position fixed using offsetWidth.
function resizeProgress() {
const container = document.querySelector('.container');
const progress = document.querySelector('.progress');
progress.style.width = container.offsetWidth + 'px';
progress.style.left = container.offsetLeft + 'px';
}
function resizeProgress() {
const container = document.querySelector('.container');
const progress = document.querySelector('.progress');
progress.style.width = container.offsetWidth + 'px';
progress.style.left = container.offsetLeft + 'px';
}
resizeProgress();
.container {
position: relative;
display: flex;
width: 500px;
height: 1200px;
}
.left {
flex: 1;
background: blue;
}
.right {
flex: 1;
background: yellow;
}
.progress {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background: gray;
}
<div class="container">
<div class="left">
</div>
<div class="right">
</div>
</div>
<div class="progress">I'm progress bar</div>

Related

How to render subchild above parent overlay

I want a gray overlay above all children except for the selected one. Given the following structure:
<div class="parent">
<!-- I have this subparent which is absolute. I cannot remove it... -->
<div class="subParent1">
<div class="subParent2">
<!-- This child I want to be above the OVERLAY, aka not greyed out -->
<div class="child selected">child</div>
<div class="child">child</div>
<div class="child">child</div>
</div>
</div>
<!-- This component is underneat subParent in the tree structure -->
<div class="grayOverlay"></div>
</div>
Here's an exact fiddle. Maybe, I could use a pseudo-element instead?
PS: I updated the children to be a bit more nested to align with my actual code.
You can take the reference from below code. I have altered the CSS a bit. I have added z-index wherever required you can optimise that. Also, removed position: absolute; from subParent1 and added top: 0; left: 0; on the grayOverlay. You can optimise it or change it as per you preference.
.parent {
width: 300px;
height: 300px;
position: relative;
background-color: gray;
}
.grayOverlay {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgb(107 114 128 / 0.8);
z-index: 11000;
}
.subParent1 {
display: flex;
flex-direction: column;
width: 100%;
z-index: 12000;
}
.child {
color: black;
width: 50px;
height: 20px;
background-color: white;
margin: 10px;
z-index: 10000;
}
.childIWantOverOverlay {
background-color: red;
z-index: 12000;
}
<div class="parent">
<div class="subParent1">
<div class="child childIWantOverOverlay">child</div>
<div class="child">child</div>
<div class="child">child</div>
</div>
<!-- This component is underneat subParent in the tree structure -->
<div class="grayOverlay"></div>
</div>
UPDATE 2
Perhaps also consider use a pseudo-element for this, if it is acceptable in the actual use case.
This approach is more isolated, so it might be less likely to have conflict with other existing elements in the actual project.
Example with pseudo-element:
const btn = document.querySelector("button");
const divs = document.querySelectorAll("div.child");
let i = 0;
btn.addEventListener("click", () => {
divs[i].classList.toggle("selected");
if (i < 2) {
divs[i + 1].classList.toggle("selected")
i++;
return;
};
if (i >= 2) {
i = 0;
divs[i].classList.toggle("selected");
}
});
/* Can Change */
.parent {
width: 300px;
height: 300px;
position: relative;
}
/* 👇 Add this */
.parent::after {
content: "";
position: absolute;
inset: 0;
background-color: rgb(107 114 128 / 0.5);
z-index: 50;
}
/* 👇 Disabled for now
.grayOverlay {
position: absolute;
width: 100%;
height: 100%;
background-color: rgb(107 114 128 / 0.5);
z-index: 50;
}
*/
/* CANNOT CHANGE */
.subParent1 {
position: absolute;
display: flex;
flex-direction: column;
width: 100%;
}
/* Can Change */
.child {
color: black;
width: 50px;
height: 20px;
background-color: pink;
margin: 10px;
z-index: 25;
position: relative;
}
/* Can Change */
.selected {
background-color: red;
/* 👇 Add z-index */
z-index: 100;
}
button {
margin-bottom: 1em;
padding: 6px;
}
<button>Toggle</button>
<div class="parent">
<div class="subParent1">
<div class="subParent2">
<div class="child selected">child</div>
<div class="child">child</div>
<div class="child">child</div>
</div>
</div>
<!-- This component is underneat subParent in the tree structure. I cannot move this into subParent1 -->
<!-- <div class="grayOverlay"></div> -->
</div>
Update: also added position: relative on child.
It seems that this can be achieved by removing the z-index on grayOverlay and subParent1 (the grayOverlay is still stacked on top due to natural placement), and add some z-index on selected.
Example:
const btn = document.querySelector("button");
const divs = document.querySelectorAll("div.child");
let i = 0;
btn.addEventListener("click", () => {
divs[i].classList.toggle("selected");
if (i < 2) {
divs[i + 1].classList.toggle("selected")
i++;
return;
};
if (i >= 2) {
i = 0;
divs[i].classList.toggle("selected");
}
});
/* Can Change */
.parent {
width: 300px;
height: 300px;
position: relative;
}
/* Can Change */
.grayOverlay {
position: absolute;
width: 100%;
height: 100%;
background-color: rgb(107 114 128 / 0.5);
/* Removed z-index */
}
/* CANNOT CHANGE */
.subParent1 {
position: absolute;
display: flex;
flex-direction: column;
width: 100%;
/* Removed z-index */
}
/* Can Change */
.child {
color: black;
width: 50px;
height: 20px;
background-color: pink;
margin: 10px;
/* 👇 Add position */
position: relative;
}
/* Can Change */
.selected {
background-color: red;
/* 👇 Add z-index */
z-index: 100;
}
button {
margin-bottom: 1em;
padding: 6px;
}
<button>Toggle</button>
<div class="parent">
<div class="subParent1">
<div class="subParent2">
<div class="child selected">child</div>
<div class="child">child</div>
<div class="child">child</div>
</div>
</div>
<!-- This component is underneat subParent in the tree structure. I cannot move this into subParent1 -->
<div class="grayOverlay"></div>
</div>

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>

Stretch div all the way to the bottom without overflowing

Can anyone please help me to fill the width of parent container and stretch it all the way to bottom without overflowing. Here is jsfiddle
http://jsfiddle.net/vn50gka2/1/#&togetherjs=p1VVmrhCtA
.toolbar {
position: absolute;
height: 50px;
width: 100%;
top: 0;
left: 0;
background-color: green;
}
.layout {
height: 100%;
width: 400px;
margin: 60px auto
}
.container {
display: flex;
flex: 1;
flex-direction: column;
background-color: red;
}
Container is the div I'm trying to fix. The toolbar and layout can not be changed. And also just because I want to reuse the container I really wish to not use any calculation or any hardcoded height numbers.. I don't know if this is possible
$(document).ready(function(){
var toolbarheight = $(".toolbar").height();
var windowheight = $(this).height();
var divheight = windowheight - toolbarheight -10;
console.log(divheight)
$(".mydiv").height(divheight);
})
*{
margin:0;
paddin:0;}
.toolbar {
position: fixed;
height: 50px;
width: 100%;
top: 0;
left: 0;
background-color: green;
}
.layout {
margin-top: 60px;
height: 100%;
width: 100%;
}
.container {
width: 100%;
display: flex;
flex: 1;
flex-direction: column;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="toolbar">
Toolbar
</div>
<div class="layout">
<div class="container mydiv">
<div>
stretch to bottom without overflow
</div>
</div>
</div>
well this full height for ur div using jquery!
added -10 is difference between your toolbar height and your layout top margin!

Fixed to left on horizontal scroll

I have navigation bar that is fixed to the top of the page when user scroll down.
I also need it to be fixed to the top left corner of the right block when user scroll horizontally. How to do this? Thanks for any advice.
CSS:
#box {
margin: 0 auto;
}
#content {
height: 500px;
width: 1000px;
}
#left {
max-width: 20%;
display: inline-block;
background: #aaa;
}
#right {
max-width: 80%;
display: inline-block;
background: red;
height: 100%;
width: 100%;
}
nav {
position: fixed;
top: 0;
height: 50px;
background: #666;
}
HTML:
<div id="box">
<div id="content">
<div id="left">LEFT</div>
<div id="right">
<nav>
Some text
</nav>
RIGHT
</div>
</div>
</div>
jsfiddle here: https://jsfiddle.net/deguac8y/
You can use jQuery to detect scrolling horizontally and by using class you can switch between having a fixed position nav to absolute position nav when horizontal scrolling is detected without losing the current scroll position.
JSFiddle
$(document).ready(function (){
var detectScroll = 0;
$(window).scroll(function () {
var documentScrollLeft = $(document).scrollLeft();
if (detectScroll != documentScrollLeft) {
detectScroll = documentScrollLeft;
$('nav').addClass('notFixed');
var scrollTop = $(window).scrollTop();
$('nav').css('top',scrollTop);
} else {
$('nav').removeClass('notFixed');
$('nav').css('top','auto');
}
});
});
body {
margin:0
}
#box {
margin: 0 auto;
}
#content {
height: 500px;
width: 1000px;
}
#left {
max-width: 20%;
display: inline-block;
background: #aaa;
}
#right {
max-width: 80%;
display: inline-block;
background: red;
height: 100%;
width: 100%;
}
nav {
position: fixed;
height: 50px;
background: #666;
}
nav.notFixed {
position:absolute;
top:auto;
left:auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="box">
<div id="content">
<div id="left">LEFT</div>
<div id="right">
<nav>Some text</nav>RIGHT</div>
</div>
</div>

position sticky automatic "top" position

Is there a way for stickies to take into account other stickes on the page?
For example:
body {
display: flex;
min-height: 2000px;
flex-direction: column;
}
#header {
height: 40px;
flex: 0 0 auto;
position: sticky;
top: 0;
background: yellow;
}
#footer {
flex: 0 0 auto;
height: 20px;
}
#main {
display: flex;
flex: auto;
background: blue;
}
#side {
width: 200px;
background: red;
}
#side > div {
position: sticky;
top: 0px;
}
<div id="header">header</div>
<div id="main">
<div id="side">
<div>side</div>
</div>
<div id="content">
content
</div>
</div>
<div id="footer">footer</div>
Notice that if I scroll down the header will overlap the sidebar because they have the same top position.
To fix I have to make the top position of the sidebar take the value of the header height
body {
display: flex;
min-height: 2000px;
flex-direction: column;
}
#header {
height: 40px;
flex: 0 0 auto;
position: sticky;
top: 0;
background: yellow;
}
#footer {
flex: 0 0 auto;
height: 20px;
}
#main {
display: flex;
flex: auto;
background: blue;
}
#side {
width: 200px;
background: red;
}
#side > div {
position: sticky;
top: 40px;
}
<div id="header">header</div>
<div id="main">
<div id="side">
<div>side</div>
</div>
<div id="content">
content
</div>
</div>
<div id="footer">footer</div>
But what if the header has variable height? Can I tell the browser somehow to position the stickies so they dont overlap others?
I think you would need to use javascript for this. First to get the height of the header and then set the top position of your side div using that value. I am not aware of any pure css way of doing it I am afraid.
If you are using jQuery it is simply using the .height() method if not you can use this:
var clientHeight = document.getElementById('myDiv').clientHeight;
var offsetHeight = document.getElementById('myDiv').offsetHeight;
The offset method gets the height with any padding and borders.

Resources