Flex layout with a fixed column [duplicate] - html

This question already has answers here:
Is it possible for flex items to align tightly to the items above them?
(5 answers)
Make a div span two rows in a grid
(2 answers)
Closed 5 years ago.
I have this structure ... it's similar to the WordPress administration area ... the point is that I need .main taking all the space available in width and height and .foot remains down while there is no content that lowers it. I want to use flex because I will have columns inside the .main and I need these columns take full height as well... Maybe someone can give me another solution, but I can NOT change the html, only the CSS
.wrap {
display: flex;
}
.sidebar {
position: fixed;
top: 0;
bottom: -100px;
background-color: #00a0d2;
width: 200px;
}
.main {
background-color: #66BB6A;
display: flex;
}
.foot {
margin-left: -200px;
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>
where the final result would be something like this, thx

A fixed position sidebar will not be affected by flexbox, so you need to adjust your margins to make room for it.
html,
body {
height: 100%;
}
body {
min-height: 100%;
}
.wrap {
display: flex;
flex-direction: column; /* required to establish column layout */
min-height: 100%;
}
.sidebar {
position: fixed;
top: 0;
bottom: 0; /* full height - change if required */
background-color: #00a0d2;
width: 200px;
opacity: .5/* for demo purposes */
;
}
.main {
background-color: #66BB6A;
display: flex;
flex: 1; /* take remaining height*/
margin-left: 200px; /* width of sidebar */
}
.foot {
margin-left: 200px; /* width of sidebar */
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>

You could use css grid. It allows room for 2d grid with minimal code.
.wrap {
display: grid;
/*Make 2 columns with the first having a min width of 200px*/
grid-template-columns: minmax(200px, 1fr) 10fr;
}
.sidebar {
background-color: #00a0d2;
/*Make sidebar take up the space of the 2 rows*/
grid-row: 1/3;
}
.main {
background-color: #66BB6A;
/*Let the main content take up the space of view height*/
height: 100vh;
}
.foot {
/*set footer to span the last row leaving the space for the sidebar*/
grid-column: 2/3;
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>

Related

Sticky sidebar on desktop and within content on mobile

Im having issues trying to create a sticky sidebar. On mobile the content just needs to flow within its container, then on desktop that div needs to break out into a sticky sidebar on the right, while the content flows on the left side as normal:
http://jsfiddle.net/sace510n/
Think its causing issues because the div for the sidebar is in the middle of each block.
.a {
position: sticky;
top: 0;
right: 0;
}
}
Any ideas would be greatly appreciated, thanks
Grid is the way to go here imho. Just create a new grid with 2 columns for your desktop inside your media query then set grid-column for the grey items to the left and the red one to the right. Then use position: sticky to, er, make it sticky.
The code should be self-explanatory but if not just drop me a comment on and I'll explain.
Edited: If each element is a different size, and the right-hand element is bigger than the first left-hand element then the gaps may look uneven. To solve this use a grid-row span on the .b class rule and choose a span that's big enough to keep the gaps even. Unfortunately grid-row: 1/-1 doesn't work on implicit grids.
body {
background: #20262e;
padding: 20px;
font-family: Helvetica;
}
.content {
display: grid;
gap: 1rem;
width: 100%;
max-width: 800px;
margin: 0 auto;
outline: 1px solid lime;
}
.a,
.b {
padding: 15px;
width: 200px;
height: 100px;
margin: 0 auto;
display: block;
}
.a {
background: grey;
}
.b {
background: red;
height: fit-content; /* added this during edit */
}
#media (min-width: 768px) {
.content {
grid-template-columns: repeat(2, 1fr);
}
.a {
grid-column: 1/2;
}
.b {
position: sticky;
top: 0;
grid-column: 2/3;
grid-row: 1/ span 3; /* <- choose a number to give the RHS grid enough space so the gaps of the LHS items don't grow */
}
}
.h0 {
height: 2.5rem;
}
.h1 {
height: 10rem;
}
.h2 {
height: 13rem;
}
.h3 {
height: 4rem;
}
<div class="content">
<div class="a h0">title1</div>
<div class="a">title2</div>
<div class="a">title3</div>
<div class="a">title4</div>
<div class="a h1">title5</div>
<div class="a h1">title6</div>
<div class="a">title7</div>
<div class="a h2">title8</div>
<div class="b">here on mobile, sticky sidebar on desktop <br/>title<br />title<br />title<br />title<br />title<br />title<br /></div>
<div class="a h1">title9</div>
<div class="a h3">title10</div>
</div>

Empty space when I set height of a child element

I want to create a simple page with flex looks like this:
So this is what I try:
.container {
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.header {
height: 40px;
background-color: red;
width: 100%;
}
.sidenav {
background-color: blue;
align-items: flex-start;
}
.main {
background-color: green;
flex-grow: 1;
}
<div class="container">
<header class="header">Header</header>
<nav class="inner sidenav">Sidenav</nav>
<div class="inner main">Main</div>
</div>
My question is, when I set the height of the .header, there's a blank space between .header and the others. Anybody knows why? How can I fix it?
I know I can add more div to make it works, but I want a solution without adding any extra wrapper.
It seems that your content wrapped into two flex rows, and when height is distributed among those rows there are some extra space remained. All of that extra space is not given to last row automatically. So a gap remains unless you shrink the height of window to your contents' exact height.
If you want your second row to take remaining space using css, maybe you can assign remaining height to it with CSS like this:
.container {
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.header {
height: 40px;
background-color: red;
width: 100%;
}
.sidenav {
background-color: blue;
align-items: flex-start;
height: calc(100vh - 40px);
}
.main {
background-color: green;
flex-grow: 1;
}
body
{
margin: 0
}
<div class="container">
<header class="header">Header</header>
<nav class="inner sidenav">Sidenav</nav>
<div class="inner main">Main</div>
</div>

CSS - Can't have a div to auto-fit with the screen height

In the below I have 2 div containers.
Container 1 which contains a google map div that looks like the below :
HTML
<div class="container">
<div class="mapCanvas2" #mapCanvas2></div>
</div>
CSS
.container{
height: 64%;
width: 100%;
}
.mapCanvas2{
position:relative;
height: 100%;
width: 100%;
}
Container 2
.container2{
height: 36%;
width: 100%;
}
The problem:
On some screens (depending on its height) a blank space shows up below container 2 to hide it I must set the height value of .container to 67% or above which is of course not a solution.
You can use flex, by specifing flex:1 you make the second container fill the remaining space :
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
.container {
height: 30%;
background: red;
}
.container-2 {
flex: 1;
background: blue;
}
<div class="container">
<div class="mapCanvas2" #mapCanvas2> map </div>
</div>
<div class="container-2"></div>

Height is not correct in flexbox items in Chrome [duplicate]

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I've got a delicate problem for any CSS guru out there.
My green div has a flexible height, taking up the remaining.
And now I want to put a div inside that div which should be the half of the green div. But it seems like if Chrome treats it like half of the whole page rather than the flex item.
http://jsfiddle.net/unh5rw9t/1/
HTML
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>
CSS
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
}
#half_of_content {
height: 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
#Michael_B explained why Chrome behaves like this:
You gave the body a height: 100%. Then gave its child (.wrapper)
a height: 100%. Then gave its child (.content) a height: 100%.
So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be a 50% height
of body.
However, Firefox disagrees because, in fact, that height: 100% of .content is ignored and its height is calculated according to flex: 1.
That is, Chrome resolves the percentage with respect to the value of parent's height property. Firefox does it with respect to the resolved flexible height of the parent.
The right behavior is the Firefox's one. According to Definite and Indefinite Sizes,
If a percentage is going to be resolved against a flex item’s
main size, and the flex item has a definite flex
basis, and the flex container has a definite main
size, the flex item’s main size must be treated as
definite for the purpose of resolving the percentage, and the
percentage must resolve against the flexed main size of the
flex item (that is, after the layout algorithm below has been
completed for the flex item’s flex container, and the flex
item has acquired its final size).
Here is a workaround for Chrome:
#content {
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
height: auto;
}
This way the available space in #content will be distributed equally among #half_of_content and the ::after pseudo-element.
Assuming #content doesn't have other content, #half_of_content will be 50%. In your example you have a 2 in there, so it will be a bit less that 50%.
html,
body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
You could absolutely position div id="half_of_content".
#content {
flex: 1;
height: 100%;
background-color: green;
position: relative; /* new */
}
#half_of_content {
height: 50%;
background-color: yellow;
position: absolute; /* new */
width: 100%; /* new */
}
DEMO
With regard to your statement:
But it seems like if Chrome treats it like half of the whole page
rather than the flex item.
You gave the body a height: 100%. Then gave its child (.wrapper) a height: 100%. Then gave its child (.content) a height: 100%. So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be 50% height of body.
With absolute positioning, however, you don't need to specify parent heights.
Nesting flexboxes is a little buggy. I reworked your markup a little by adding an inner wrapper with display: flex; which seems to do the job. Here is the fiddle (also using class names instead of ids).
<div class="content">
<div class="wrapper-inner">
2
<div class="half">
2.1
</div>
</div>
</div>
.wrapper-inner {
position: absolute;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
Fix:
on #content set
display: flex;
flex-flow: column nowrap;
justify-content: flex-end
on #half_of_content set flex: 0 0 50%;
Caveat: you need to add an extra div as a child of #content.
Here's the full example:
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
display:flex;
flex-flow: column nowrap;
justify-content: flex-end;
background-color: green;
}
#half_of_content {
flex: 0 0 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>

Flex Layout with fixed position (no scrolling) sidebar

I have a layout with left and right canvas sidebars, enclosing the Main content area in the middle.
The sidebars and main content are flex items, positioned in a flex layout left to right.
The sidebars contain menus and meta links.
My question is: when scrolling the content area, is it possible to leave the sidebars in fixed position, such that they stay in top position and do not scroll down?
JS Fiddle: http://jsfiddle.net/Windwalker/gfozfpa6/2/
HTML:
<div class="flexcontainer">
<div class="flexitem" id="canvas-left">
<p>This content should not scroll</p>
</div>
<div class="flexitem" id="content">
<div>
<p>Scrolling Content</p>
</div>
</div>
<div class="flexitem" id="canvas-right">
<p>This content should not scroll</p>
</div>
</div>
CSS:
.flexcontainer {
display: flex;
flex-direction: row;
min-height: 100%;
align-items: stretch;
}
.flexitem {
display: flex;
}
#canvas-left {
background: yellow;
order: -1;
flex: 0 0 57px;
}
#content {
background: green;
order: 1;
padding: 1rem;
}
#content div {
display: block;
}
#canvas-right{
background: blue;
order: 2;
flex: 0 0 57px;
}
Please look at the similar question with provided solution: How to simulate 'position:fixed' behavior on Flexbox-aligned sidebar.
According to your code you can also wrap your inner content in "position: fixed" wrapper:
<div class="flexitem" id="canvas-left">
<div class="fixed">
<p>This content should not scroll</p>
</div>
</div>
And add proper styling in CSS:
.fixed {
position: fixed;
width: 57px; /* according to #canvas-left */
}
Here is an example of your code with fixed left sidebar: http://jsfiddle.net/8hm3849m/. Note that this trick won't provide you proper flexible grid for sidebars, width of the wrapper should be fixed (or set dynamically via JavaScript).
The question is old, but I solved a similar issue using
position: sticky;
top: 0;
for the left and right items.
Also I removed the
display: flex
css for the flex items, I don't think that's necessary.
https://jsfiddle.net/8mpxev0u/
i dont know how do it with flex, but here is a easyer/alternate css remove all that flex... and try to never add padding to a outer div, its easyer in inner items, then you dont need to calculate if there are to many divs
.flexcontainer {
display: block;
min-height: 100%;
align-items: stretch;
}
.flexitem {
display: flex;
}
#canvas-left {
background: yellow;
order: -1;
left: 0px;
width: 20%;
position: fixed;
}
#content {
position: absolute;
background: green;
order: 1;
width: 60%;
left: 20%;
}
#content p {
display: block;
padding: 1rem;
}
#canvas-right{
background: blue;
order: 2;
right: 0px;
width: 20%;
position: fixed;
}