I'm trying to achieve the following layout:
Top bar
Main content placeholder
Bottom bar
The main content has (always one at the same time though) children, one of which is a table which should always be square.
How can I do this with CSS? I've tried flexbox and CSS grid including aspect-ratio but couldn't get it to work.
The idea is basically the following:
Top/Main content/Bottom is always the same height/full width
If there's a table inside the main content, it should be square. The main content placeholder should remain the size but the table within should always be automatically resized to be square (ideally with the minimum of available width or height)
To achieve this, it's okay for the top bar the change its height, the bottom bar should remain fixed
Here's some example code I've tried:
<!DOCTYPE html>
<html lang="en" style="height: 100%;">
<head>
<meta charset="UTF-8">
<title>Test</title>
<style>
.main {
background: gray;
height: 100vh;
grid-template-rows: 20% 60% 20%;
display: grid;
}
.top {
background: red;
}
.placeholder {
background: green;
width: 100%;
height: 100%;
position: relative;
}
.square-table {
background: yellow;
aspect-ratio: 1/1;
height: 100%;
position: absolute;
}
.bottom {
background: blue;
}
</style>
</head>
<body style="height: 100%;">
<div class="main">
<div class="top">Top</div>
<div class="placeholder">
<p>Generic placeholder</p>
<table class="square-table">
<tbody>
<tr>
<td>abc</td>
</tr>
</tbody>
</table>
</div>
<div class="bottom">Bottom</div>
</div>
</body>
</html>
Any help or pointers in the right direction would be much appreciated.
Grid children have min-height: auto set by default which means they will always resize based on the content. So you can set min-height: 100% on the .placeholder div. Then I set the placeholder div to also be a grid, and then the min-height fix on the table again -- see solution below
body { color: white; margin: 0; font-family: sans-serif; text-align: center }
.main { background: gray }
.top { background: red }
.placeholder { background: green }
.bottom { background: blue }
.square-table { background: yellow; color: black }
.main {
height: 100vh;
grid-template-rows: 20% 60% 20%;
display: grid;
}
.placeholder {
min-height: 100%;
grid-template-rows: fit-content(0) 1fr;
display: grid;
justify-content: center;
}
.square-table {
margin: auto;
max-height: 100%;
min-height: 100%;
aspect-ratio: 1/1;
}
<div class="main">
<div class="top">Top</div>
<div class="placeholder">
<div> <!-- if no intro just remove <p> tag and leave the <div> empty -->
<p>Generic placeholder</p>
</div>
<table class="square-table">
<tbody>
<tr>
<td>abc</td>
</tr>
</tbody>
</table>
</div>
<div class="bottom">Bottom</div>
</div>
Related
When creating my dashboard with flexbox css html, I have a scroll problem for example:
In the middle red container if I make it vertical the horizontal one does not work well for me opteniendo results like it expands the container descuadrando the design.
If I work the horizontal scroll does not work the vertical scroll expanding this.
I want it to work like this in the following image:
Desired result
I have tried many things with the flexbox like setting the height or width to 100% and even forcing the scroll, but I can't get the expected effect.
Your question is a bit broad, you should post your current solution next time to see which part is not working. For example, I couldn't really tell if the vertical scrollbar in the middle region is supposed to scroll the top or the middle part. Anyways, if you're set on using flexboxes, here's a way to do it:
body {
margin: 0;
}
main {
display: flex;
width: 100vw;
height: 100vh;
}
.left {
width: 20%;
background-color: cornflowerblue;
}
.left__header {
background-color: lightblue;
}
.middle {
display: flex;
flex-direction: column;
width: 40%;
background-color: salmon;
}
.middle__header {
flex-shrink: 0;
overflow-y: auto;
background-color: lightpink;
}
.middle__body {
overflow-x: auto;
}
.middle__footer {
margin-top: auto;
background-color: white;
}
.right {
width: 40%;
background-color: lightgreen;
}
<main>
<div class="left">
<div class="left__header">1</div>
<div class="left__body"></div>
</div>
<div class="middle">
<div class="middle__header">
<!-- Fixed width to simulate overflowing content -->
<div style="min-width: 2000px">1 2 3 4 5</div>
</div>
<div class="middle__body">
<!-- Fixed height to simulate overflowing content -->
<div style="min-height: 2000px">Content</div>
</div>
<div class="middle__footer">
Pia de Pagina
</div>
</div>
<div class="right">
SideBar Right
</div>
</main>
But if you don't plan on dynamically adding/removing elements or moving stuff around in the base layout (i.e. these regions stay the same during the use of the application) I'd recommend using CSS grid instead:
body {
margin: 0;
}
main {
display: grid;
grid-template:
"left-header middle-header right" min-content
"left-body middle-body right"
"left-body middle-footer right" min-content / 2fr 4fr 4fr;
width: 100vw;
height: 100vh;
}
.left__header {
grid-area: left-header;
background-color: lightblue;
}
.left__body {
grid-area: left-body;
background-color: cornflowerblue;
}
.middle__header {
grid-area: middle-header;
overflow-x: auto;
background-color: lightpink;
}
.middle__body {
grid-area: middle-body;
overflow-y: auto;
background-color: salmon;
}
.middle__footer {
grid-area: middle-footer;
background-color: white;
}
.right {
grid-area: right;
background-color: lightgreen;
}
<main>
<div class="left__header">1</div>
<div class="left__body"></div>
<div class="middle__header">
<!-- Fixed width to simulate overflowing content -->
<div style="min-width: 2000px">1 2 3 4 5</div>
</div>
<div class="middle__body">
<!-- Fixed height to simulate overflowing content -->
<div style="min-height: 2000px">Content</div>
</div>
<div class="middle__footer">
Pia de Pagina
</div>
<div class="right">
SideBar right
</div>
</main>
This results in the same output, but the HTML/CSS is much more readable IMO. It uses the grid-template property, which is fairly new, but should be available in most browsers.
image wireframe
I would like to recreate messaging phone app in html and css. So the app must be full frame without any overflow.
The trick is the bottom part (in red) must be resizable according to the child content. So I used flex (with flex-direction: column) to manage my layout.
The problem is : when the content (in yellow) grow up, the core part will compress the red part. My goal is to overflow, with a scrollbar, the content inside the core part and don't change the size of the red div.
index.html
<body>
<div id="header">
</div>
<div id="core">
<div class="conainer" style="">
<div class="row">
<div class="two columns"></div>
<div class="ten columns">
<div class="msgright">
.
</div>
</div>
</div>
<div class="row">
<div class="ten columns">
<div class="msgright">
.
</div>
</div>
<div class="two columns"></div>
</div>
</div>
</div>
<div id="footer">
</div>
index.css
html, body, div {
margin: 0;
padding: 0;
}
html, body {
height: 100%;
max-height: 100%;
overflow: hidden;
}
body {
display: flex;
flex-direction: column;
}
#header {
height: 50px;
background: #2A9D8F;
flex: 0 0 auto;
}
#core {
background-color: #264653;
flex: 1;
display: flex;
align-items: flex-end;
}
#footer {
height: auto;
background-color: red;
min-height: 50px;
flex: 0 0 auto;
}
.conainer {
flex: 0 0 100%;
}
.row {
margin: 5px;
background-color: yellow;
height: 130px;
}
https://codepen.io/jln_brtn/pen/pobVZBv
Best regards and thank you for your help.
I'm not sure if I understand the problem correctly but since your .row elements have a fixed height: 130px, the element should not be able to grow any further. Overflow styling to .row elements can be added like this:
.row {
overflow-y: scroll;
}
If it is just the #core element, then you can do something like this:
#core {
overflow-y: scroll;
}
For this instance I would suggest to use CSS Grid instead of Flexbox, and giving both <header> and <footer> the space they need, while the <main> gets the rest. This means that both <header> and <footer> stay were they are, even if <main> needs more space for its content, meaning <main> will get a scrollbar.
You can achieve the same by using position: fixed and setting a margin to top and bottom, with fixed heights of <header> and <footer>, and sizing <main> with height: calc(100% - HEIGHT_OF_HEADER - HEIGHT_OF_FOOTER). The problem with this is maintenance, as you would always have to check and revalidate the heights when changing something.
html, body {
margin: 0;
width: 100%;
height: 100%;
}
body {
display: grid;
grid-template-rows: auto 1fr auto;
}
header {
height: 3.125rem;
background: #2A9D8F;
}
main {
padding: 0.3125rem;
display: flex;
flex-flow: column;
gap: 0.3125rem;
background: #264653;
overflow: hidden auto;
}
footer {
height: 3.125rem;
background: red;
}
main > div {
flex-shrink: 0;
height: 8.125rem;
background: yellow;
}
<header></header>
<main>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</main>
<footer></footer>
My top-level layout is n columns, all of which are of fixed width (sidebars) except for the central one (mainbar) that should automatically fill up the remaining space.
So, I have this tricky wide table in the mainbar. It has a wrapper with overflow-x: auto, however instead of triggering the scrolling on the wrapper, it prefers to stretch everything up to the top-level flex container. This can be solved by adding width: calc(100% - {sum of widths of other columns}px) to the mainbar, but I'm looking for a more flexible solution that would allow adding more columns and resizing the existing ones without touching this calc rule.
Any ideas? Is there any way to say to a flex item: fill up the remaining space, but don't allow your content to stretch you?
UPD: Managed to do it by wrapping the content of the mainbar in a table with table-layout: fixed (the code is here), but I feel bad about it. Does anyone know of a more flexboxy solution? Or is this one okay?
// this JS generates placeholder text, ignore it
for (const el of document.querySelectorAll(".lorem")) {
el.innerHTML = Array(Number(el.getAttribute("p")) || 1)
.fill()
.map(() => `<p>${chance.paragraph()}</p>`)
.join("");
}
body {
margin: 0;
}
.outer {
display: flex;
}
.sidebar {
flex: 0 0 300px;
background: #eef;
}
.mainbar {
background: #ffe;
/* width: calc(100% - 500px); */
}
.rightbar {
flex: 0 0 200px;
background: #fef;
}
.table-wrapper {
width: 100%;
overflow-x: auto;
background: pink;
}
.table-wrapper td {
min-width: 400px;
}
<script src="https://unpkg.com/chance#1.0.16/chance.js"></script>
<div class="outer">
<div class="sidebar">
<div class="lorem" p="4"></div>
</div>
<div class="mainbar">
<div class="table-wrapper">
<table>
<tr>
<td class="lorem"></td>
<td class="lorem"></td>
<td class="lorem"></td>
<td class="lorem"></td>
</tr>
</table>
</div>
<div class="lorem" p="10"></div>
</div>
<div class="rightbar">
<div class="lorem" p="3"></div>
</div>
</div>
If I understand you correct, add flex: 1; min-width: 0; to your .mainbar rule and it should behave.
The flex: 1 will make it take available space and min-width: 0 will allow a flex item to be smaller than its content, which you can read more about here:
Why don't flex items shrink past content size?
Stack snippet
// this JS generates placeholder text, ignore it
for (const el of document.querySelectorAll(".lorem")) {
el.innerHTML = Array(Number(el.getAttribute("p")) || 1)
.fill()
.map(() => `<p>${chance.paragraph()}</p>`)
.join("");
}
body {
margin: 0;
}
.outer {
display: flex;
}
.sidebar {
flex: 0 0 300px;
background: #eef;
}
.mainbar {
background: #ffe;
flex: 1;
min-width: 0;
/* width: calc(100% - 500px); */
}
.rightbar {
flex: 0 0 200px;
background: #fef;
}
.table-wrapper {
width: 100%;
overflow-x: auto;
background: pink;
}
.table-wrapper td {
min-width: 400px;
}
<script src="https://unpkg.com/chance#1.0.16/chance.js"></script>
<div class="outer">
<div class="sidebar">
<div class="lorem" p="4"></div>
</div>
<div class="mainbar">
<div class="table-wrapper">
<table>
<tr>
<td class="lorem"></td>
<td class="lorem"></td>
<td class="lorem"></td>
<td class="lorem"></td>
</tr>
</table>
</div>
<div class="lorem" p="10"></div>
</div>
<div class="rightbar">
<div class="lorem" p="3"></div>
</div>
</div>
This question already has answers here:
How to create a sidebar and content area using flexbox?
(1 answer)
Flexbox layout, push content when opening sidebar?
(1 answer)
Flexbox sidebar with max-width
(1 answer)
Closed 5 years ago.
on my page I want to have a header and below this I want to have a sidebar on the left side and the content page on the right side.
The sidebar should have a width of X (maybe 100 px) and the content page should have the rest of the full window with.
I started creating this but my sidebar and content page don't have a full height. Even when setting height to 100% the don't fill the rest of the page.
And why do I have to set a min and max width for the sidebar instead of width? When setting width: 100px the width returns 70px.
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
font-family: Ubuntu;
background: linear-gradient(#b3ffab, #67fffc);
}
#header {
height: 30px;
display: flex;
align-items: center;
background: linear-gradient(#444444, #333333);
color: #bbbbbb;
}
#headerContent {
margin-left: 10px;
}
#page {
display: flex;
}
#sideBar {
min-width: 100px;
max-width: 100px;
background: red;
}
#content {
width: 100%;
background: blue;
}
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Ubuntu" />
<div id="header">
<div id="headerContent">
Desktop
</div>
</div>
<div id="page">
<div id="sideBar">
<div>
box 1
</div>
<div>
box 2
</div>
</div>
<div id="content">
content
</div>
</div>
You can set the height and width in a flexible way.
Height is set to 100% of the height of the viewport minus the height of the header.
Width is set to 100px for the sidebar. The content is now allowed to grow to fill the rest of the screen.
Hope this helps.
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
font-family: Ubuntu;
background: linear-gradient(#b3ffab, #67fffc);
}
#header {
height: 30px;
display: flex;
align-items: center;
background: linear-gradient(#444444, #333333);
color: #bbbbbb;
}
#headerContent {
margin-left: 10px;
}
#page {
display: flex;
height: calc( 100vh - 30px);
/* calculate the height. Header is 30px */
}
#sideBar {
width: 100px;
background: red;
}
#content {
background: blue;
flex: 1 0 auto;
/* enable grow, disable shrink */
}
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Ubuntu" />
<div id="header">
<div id="headerContent">
Desktop
</div>
</div>
<div id="page">
<div id="sideBar">
<div>
box 1
</div>
<div>
box 2
</div>
</div>
<div id="content">
content
</div>
</div>
Refer to this Fiddle.
I have a top-level div whose height is configured as one screen height (height:100vh). Within this div, there is a fixed-height (60px) child div and another child div I want to grow to fill the remaining height (so as to be responsive with different screen sizes).
This child div has an image and some text. Currently, its width is hard-coded, or else the image fills the entire screen (and exceeds the length of its parent). Setting height:100% (or even calc(100% - 60px)) doesn't scale the div as I'd hoped.
.one-page {
min-height: 100vh;
max-height: 100vh;
background-color: #FF5555;
}
.fixed-size {
height: 60px;
border-style: solid;
}
.main-container {
background-color: #55FF55;
width: 300px;
margin: auto;
}
.subtitle {
text-align: center
}
.other {
background-color: blue;
}
img {
vertical-align: middle;
width: 100%;
height: auto;
}
<body>
<div class="one-page">
<div class="fixed-size">
this div is a fixed size
</div>
<div class="main-container">
<p>
<img src="http://images.clipartpanda.com/square-clip-art-clipart-square-shield-256x256-e296.png">
</p>
<div class="subtitle">
subtitle text
</div>
</div>
</div>
<div class="other">
something else
</div>
</body>
Try to use height:calc(100vh - 60px).
.main-container {
background-color: #ff00ff;
width: 300px;
margin: auto;
padding:0;
height:calc(100vh - 60px);
}
DEMO
Use flexbox to work it out. Run the below snippet and you'll understand. flex-grow: 1 will basically give all the remaining height to the second child.
.p {
height: 100vh;
display: flex;
flex-direction: column;
}
.c1 {
height: 60px;
background-color: green;
}
.c2 {
flex-grow: 1;
background-color: red;
}
<div class="p">
<div class="c1"></div>
<div class="c2"></div>
</div>