This question already has answers here:
My position: sticky element isn't sticky when using flexbox
(8 answers)
Closed last month.
I want my .sidebar flex element to be sticky when I'm scrolling but position: sticky; top: 0; doesn't work.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
}
header {
width: 100%;
height: 100px;
background-color: blue;
opacity: 0.5;
position: sticky;
z-index: 100;
top: 0;
}
.container {
display: flex;
gap: 2rem;
position: relative;
}
.sidebar {
position: sticky;
top: 0;
}
.main {
display: flex;
gap: 2rem;
flex-direction: column;
}
.main div {
width: 300px;
aspect-ratio: 1 / 1;
background-color: red;
}
<div class="root">
<header></header>
<div class="container">
<div class="sidebar">
<p>Sidebar</p>
<button>Upload image</button>
</div>
<div class="main">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</div>
The issue is that the default property of align-items for flex elements is normal (acts like stretch in this context) therefore the .sidebar element takes all the available height and can't have the "sticky effect".
You can achieve the the sticky efect by changing the align-items property on the .container element to flex-start like this :
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
}
header {
width: 100%;
height: 100px;
background-color: blue;
opacity: 0.5;
position: sticky;
z-index: 100;
top: 0;
}
.container {
display: flex;
align-items: flex-start; /* <- ADD THIS */
gap: 2rem;
position: relative;
}
.sidebar {
position: sticky;
top: 100px;
}
.main {
display: flex;
gap: 2rem;
flex-direction: column;
}
.main div {
width: 300px;
aspect-ratio: 1 / 1;
background-color: red;
}
<div class="root">
<header></header>
<div class="container">
<div class="sidebar">
<p>Sidebar</p>
<button>Upload image</button>
</div>
<div class="main">
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
</div>
</div>
(Note that I also changed the top property on the .sidebar element so it doesn't hide under the header)
Related
I have the following layout (see snippet below).
This is the expected behavior.
The problem is:
Once the extra-large-content is simulated (by removing the comment on the extra-large-content CSS rule), it breaks the layout.
I would like the extra-large-content to scroll horizontally while staying inside column-3.
Is this even possible?
(the code is also available here https://codepen.io/Ploddy/pen/NWXOgMG?editors=1100)
body {
height: 1920px;
margin: 0;
}
.container {
display: flex;
border: 1px solid #ccc;
margin: 1rem;
}
.container > * {
border: 1px solid #ccc;
position: sticky;
top: 0;
align-self: flex-start;
flex-grow: 1;
margin: 1rem;
}
#column-3 {
height: 300px;
}
#extra-large-content {
background-color: lightgreen;
/*width: 3000px;*/
}
<div class="container">
<div>
column-1
</div>
<div class="container">
<div>
column-2
</div>
<div id="column-3">
column-3
<div id="extra-large-content">
extra-large content
</div>
</div>
</div>
</div>
This should work nicely for you. Essentially, I just specified width's on the .container elements. In theory, you could put overflow-x: scroll; on the .container, however, this would break your sticky positioning.
Edit ~ OP wants the extra-large content to scroll horizontally, not the entire column-3.
Set overflow-x: scroll; on the new parent wrapper of the div that has the 3000px static width.
body {
height: 1920px;
margin: 0;
}
.container:first-child {
max-width: 100%;
}
.container:first-child > div:first-child {
width: 40%;
}
.container:nth-child(2) {
width: 60%;
}
.container:nth-child(2) > div:first-child {
margin: 1em 0em 1em 1em;
}
.container {
display: flex;
border: 1px solid #ccc;
margin: 1rem;
}
.container>* {
border: 1px solid #ccc;
position: sticky;
top: 0;
align-self: flex-start;
flex-grow: 1;
margin: 1rem;
}
.wrapper {
display: flex;
flex-direction: column;
width: 40%;
}
#column-3 {
background-color: salmon;
}
#extra-large-content {
height: 300px;
width: 3000px;
background-color: lightgreen;
}
.xl-content-wrapper {
overflow-x: scroll;
}
<div class="container">
<div>column-1</div>
<div class="container">
<div>column-2</div>
<div class="wrapper">
<div id="column-3">column-3</div>
<div class="xl-content-wrapper">
<div id="extra-large-content">extra-large content</div>
</div>
</div>
</div>
</div>
The issue comes from using flexbox.
Switching to grid fixes the problem.
body {
height: 1920px;
margin: 0;
}
#primary-container {
position: relative;
display: flex;
margin: 1rem;
}
#secondary-container {
position: relative;
display: grid;
grid-template-columns: max-content 1fr;
align-items: start;
}
#column-3 {
display: grid;
grid-auto-rows: min-content;
height: 200px;
}
#content-wrapper {
overflow: auto;
}
#extra-large-content {
width: 3000px;
background-color: lightgreen;
}
.sticky {
position: sticky;
top: 0;
align-self: flex-start;
}
.border {
border: 1px solid #ccc;
}
<div id="primary-container" class="border">
<div class="sticky">
column1
</div>
<div id="secondary-container" class="border">
<div class="sticky">
column2
</div>
<div id="column-3" class="sticky border">
column3
<div id="content-wrapper">
<div id="extra-large-content">
extra-large content
</div>
</div>
...
</div>
</div>
</div>
This question already has answers here:
Flexbox: center horizontally and vertically
(14 answers)
How can I vertically center a div element for all browsers using CSS?
(48 answers)
How can I vertically align elements in a div?
(28 answers)
Closed 2 years ago.
Lets say I have this simple html page:
<div class="main">
<div class="header">
<h1>HEADER</h1>
</div>
<div class="content">
<div class="box">
</div>
</div>
</div>
My header is fixed and the content should be beneath it and with height 100% of what ever left of the body.
I've already done that with this style:
*{
margin-left: 0;
margin-top: 0;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
.header {
background-color: red;
text-align: center;
position: fixed;
width: 100%;
}
.content {
background-color: antiquewhite;
padding-top: 38px;
}
h1 {
margin-bottom: 0;
}
.main {
display: flex;
flex-direction: column;
height: 100vh;
}
.content {
flex: 1;
}
.box {
width: 150px;
height: 150px;
background-color: yellow;
}
Here's how the page looks for now: https://elbargho.github.io/sudoku/centerdiv.html
now I'm trying to center the box div horizontally and vertically in relative to the full body - the header size
what I've tried to do:
margin-top: 50% - for some reason the box went all the way down to the bottom
setting the position of content div to relative, and of box div to absolute - the content div overlapped the fixed header
You can set content class as
.content {
/* flex: 1; */
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
*{
margin-left: 0;
margin-top: 0;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
.header {
background-color: red;
text-align: center;
position: fixed;
width: 100%;
}
.content {
background-color: antiquewhite;
padding-top: 38px;
}
h1 {
margin-bottom: 0;
}
.main {
display: flex;
flex-direction: column;
height: 100vh;
}
.content {
/*flex: 1; */
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.box {
width: 150px;
height: 150px;
background-color: yellow;
}
<div class="main">
<div class="header">
<h1>HEADER</h1>
</div>
<div class="content">
<div class="box">
</div>
</div>
</div>
This is probably what you need. Documented in the code.
* {
margin-left: 0;
margin-top: 0;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
/* Modified */
.header {
background-color: red;
text-align: center;
/* position: fixed; */
position: sticky;
width: 100%;
}
.content {
background-color: antiquewhite;
padding-top: 38px;
}
h1 {
margin-bottom: 0;
}
/* Modified */
.main {
display: flex;
flex-direction: column;
height: 100vh;
align-items: center;
}
/* Modified */
.content {
/*flex: 1;*/
display: flex;
align-items: center;
height: inherit;
}
.box {
width: 150px;
height: 150px;
background-color: yellow;
}
<div class="main">
<div class="header">
<h1>HEADER</h1>
</div>
<div class="content">
<div class="box">
</div>
</div>
</div>
Here solution:
.content {
display: flex;
flex: 1;
justify-content: center;
align-items: center;
}
One way is to use CSS Transform.
.box {
position: relative;
top: 50%;
transform: translateY(-50%);
/* horizontal center */
margin: 0 auto;
}
Check out this website for all CSS centering help:
http://howtocenterincss.com/
This question already has answers here:
CSS: Width in percentage and Borders
(5 answers)
Closed 3 years ago.
I want to create a bar to go along the top of a box on a website that I am working on.
This is the desired outcome
Here's my code, I keep getting this overlap
.page {
display: flex;
flex-wrap: wrap;
position: relative;
}
.section {
border: 2px solid #FBA7FF;
width: 85%;
height: 30%;
margin: 1vw;
padding: 1vw;
display: flex;
align-items: center;
position: relative;
z-index: 1;
}
.section h1 {
position: relative;
}
.section_header {
border: 4px solid #FBA7FF;
position: absolute;
top: 0;
left: 0;
width: 100%;
bottom: 95%;
}
<div class='page'>
<div class='section'>
<div class="section_header"></div>
<h1>sample text</h1>
</div>
</div>
So far I've got the parent div with position: relative and the child element with position: absolute then setting top and left to 0 width to 100% and bottom to 95% to attempt the desired effect yet it creates an overlap.
I can see that 0 is within the div and doesn't take into account the border which is perhaps why this is happening.
* {
box-sizing: border-box;
margin: 0;
}
.page {
display: flex;
flex-wrap: wrap;
position: relative;
}
.section {
width: 100%;
display: inline-block;
text-align: center;
}
.section_header {
width: 100%;
background: #FBA7FF;
display: block;
height: 70px;
margin-bottom: 20px;
}
<div class='page'>
<div class='section'>
<div class="section_header"></div>
<h1>sample text</h1>
</div>
</div>
Remove the position:absolute and use flex-direction:column;
* {
margin: 0;
padding: 0;
}
.page {
display: flex;
flex-wrap: wrap;
flex-direction: column;
min-height: 100vh;
background: lightgrey;
position: relative;
}
.section {
border: 2px solid #FBA7FF;
width: 85%;
margin: 1vh auto;
height: 30%;
background: lightgreen;
display: flex;
flex-direction: column;
flex: 1;
align-items: center;
}
.section_header {
height: 50px;
width: 100%;
background: orange;
}
<div class='page'>
<div class='section'>
<div class="section_header"></div>
<h1>sample text</h1>
</div>
</div>
I have a layout that is mainly divided into 3 parts and the middle one should take a full height. And it does.
However, I need an additional div which will play a role of the backdrop and here the problem comes. The child doesn't want to take 100% height.
Here .body is a div that is being stretched when there is not enough content and .bg-gray is the one I want to take its parent full height.
Is there a way achieve this without using relative + absolute positioning?
Also, I'm looking for the answer to my question: why is this happening that way.
html, body {
padding: 0;
margin: 0;
}
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: stretch;
}
.header {
height: 50px;
background-color: #e6e6e6;
}
.footer {
height: 50px;
background-color: #aaa444;
}
.body {
flex: 1;
}
.bg-gray {
background-color: #eee;
min-height: 100%;
flex: 1;
}
<div class="container">
<div class="header">
</div>
<div class="body">
<div class="bg-gray">
<div>
asdasd
</div>
</div>
</div>
<div class="footer">
</div>
</div>
Apply flexbox to the .body div.
.body {
flex: 1;
display: flex;
flex-direction: column;
}
html,
body {
padding: 0;
margin: 0;
}
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: stretch;
}
.header {
height: 50px;
background-color: #e6e6e6;
}
.footer {
height: 50px;
background-color: #aaa444;
}
.body {
flex: 1;
display: flex;
flex-direction: column;
}
.bg-gray {
background-color: darkgrey;
min-height: 100%;
flex: 1;
}
.bg-gray div {
background: lightblue;
}
<div class="container">
<div class="header">
</div>
<div class="body">
<div class="bg-gray">
<div>
asdasd
</div>
</div>
</div>
<div class="footer">
</div>
</div>
How do I get the left sidebar to overlay the content instead of pushing the content? I want it overlay on mobile but push on web layout. Flexbox is a little new to me so not sure if I need a different layout to do this or if this is possible with flexbox? I'm guessing I need to remove the sidebar from the flexbox and use a fixed relative layout ??
I'm also using angular but I removed the angular code just for simplicity so don't mind the extra divs please.
<div class="wrapper">
<header class="header">
header
</header>
<div class="main">
<div class="left-sidebar">
left sidebar
</div>
<div class="main-content-wrapper">
<div class="main-content">
<h3>Main </h3>
</div>
<footer class="footer">
<p>content</p>
<p>content</p>
<p>content</p>
</footer>
</div>
</div>
</div>
body,
html {
height: 100%;
overflow: hidden;
}
header {
min-height: 60px;
flex: none;
width: 100%;
background-color: silver;
}
.wrapper {
height: 100vh;
display: flex;
flex-direction: column;
.main {
flex: 1;
display: flex;
.main-content-wrapper {
display: flex;
flex: 1;
flex-direction: column;
overflow: auto;
.main-content {
padding: 2rem;
flex: 1;
background-color: antiquewhite;
}
footer {
background-color: silver;
min-height: 300px;
flex-shrink: 0;
}
}
}
}
.left-sidebar {
width: 0;
height: 100%;
overflow: auto;
flex: none;
&.active {
width: 250px;
}
.left-sidebar-content {
padding: 1rem;
}
}
Try this, I actually made pretty much a new structure, although not that different to yours, (did remove some elements just to work with less code); I'm using flexbox to make the whole wrapper a flex container, as well as media queries to indicate when the sidebar should push the content to the side, and when to overlap the content along with an overlay.
document.getElementById('toggleBtn').onclick = function() {
document.getElementById('sidebar').classList.toggle('active');
document.getElementById('overlay').classList.toggle('hidden');
}
document.getElementById('overlay').onclick = function() {
document.getElementById('overlay').classList.toggle('hidden');
document.getElementById('sidebar').classList.toggle('active');
}
body {
margin: 0;
}
.wrapper {
display: flex;
align-items: stretch;
height: 100vh;
}
.main-content-wrapper {
width: 100%;
}
#sidebar {
min-width: 230px;
max-width: 230px;
background-color: lightgray;
transition: all 0.3s;
height: 100vh;
margin-left: -230px;
/* top layer */
z-index: 3
}
#sidebar.active {
margin-left: 0px;
}
#media (max-width: 580px) {
#sidebar {
position: fixed;
top: 0;
/* top layer */
z-index: 3
}
.overlay {
background-color: rgba(0, 0, 0, 0.425);
width: 100vw;
height: 100vh;
z-index: 2;
top: 0;
left: 0;
position: absolute;
}
.overlay.hidden {
display: none;
}
}
<div class="wrapper">
<div class="left-sidebar" id="sidebar">
left sidebar
</div>
<div class="main-content-wrapper">
<div class="main-content">
<h3>Main </h3>
<button type="button" id="toggleBtn">Toggle</button>
</div>
</div>
<div class="overlay hidden" id="overlay"></div>
</div>