I've prepared a mobile site, which has the right aspect ratio of images, but on some phones with bigger screens it's to short and after the footer I get white gap. I would prefer to add some DIVs between contents which they would auto stretch when needed.
I'm thinking of something like this:
<div id="wrapper">
<div id="header"></div>
<div id="content1"></div>
<div class="empty_gap"></div>
<div id="accordion"></div>
<div class="empty_gap"></div>
<div id="footer"></div>
</div>
The .empty_gap DIVs would get evenly height so the page would fit the screen height. How to get this done? Or do you have any other solution for such a situation when the page is to short to fill the entire mobile screen?
EDIT: I have to add one thing which I didn't think before it will cause a problem. None of these solutions are working for me, because I use jquery accordion, and when I execute $("#wrapper").outerHeight(); I get much bigger value than the screen size even when I have all panels collapsed. I guess that this is also the reason for flexible boxes that those solutions don't work too.
EDIT2: The JS solution is working now, I just needed to subtract the panel's content from the wrapper.
If you're OK with a JavaScript solution, try this:
Usually your divs should be wrapped with a div container. If it's not the case, then go ahead and add one like this:
<div id="wrapper">
<div id="header"></div>
<div id="content1"></div>
<div class="empty_gap"></div>
<div id="content2"></div>
<div class="empty_gap"></div>
<div id="footer"></div>
</div>
Then in JavaScript, calculate the height of this container div and subtract it from the window's height. That would be the total of all your gaps, so divided by the number of your gaps (2 in your example) to get the height of each gap. Something like this:
var totalGap = $(window).height() - $("#wrapper").outerHeight();
var gap = totalGap / 2; //2 is the number of your gaps
$(".empty_gap").css("height", gap);
Place this code in event for when the page finished loading. However, if your app supports rotation, then you'll have to place this code in the $(window).resize() event.
I suggest to use flexbox layout, for the equal space above and below #content2 you will just need to set #content2 { margin: auto 0; } to make it to work.
jsFiddle
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
margin: 0;
}
#content2 {
margin: auto 0;
}
<div id="header">header</div>
<div id="content1">content1</div>
<div id="content2">content2</div>
<div id="footer">footer</div>
If you do not need to support old browsers, it can be a job for flexible boxes.
Have a look here for browsers support (94.22% support when used jointly the with -webkit prefixed version).
You just have to set your container element to display: flex; with flex-direction: column; then add flex-grow: 1 (or anything > 0) to the .empty_gap elements.
#container {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
#header, #footer {
height: 25px;
background-color: red;
}
#content1, #content2 {
height: 50px;
background-color: blue;
}
.empty_gap {
background-color: yellow;
flex-grow: 1;
}
<div id="container">
<div id="header"></div>
<div id="content1"></div>
<div class="empty_gap"></div>
<div id="content2"></div>
<div class="empty_gap"></div>
<div id="footer"></div>
</div>
Related
In my site I have the following structure:
Header
Content
Footer
And I want to make the Header and the Footer size based on their content (not a fixed size). And the Content to fill the remaining space.
I saw many questions and answers like: Make a div fill the height of the remaining screen space
that solves similar cases but in my case, the Header and Footer sizes are unknown so I can't use the calc() function, and the Header Has position:fixed which removes it from the layout calculations and makes the
flex solutions of various kinds wrong:
html,
body {
height: 100%;
margin: 0;
}
.box {
display: flex;
flex-flow: column;
height: 100%;
}
.box .row {
border: 1px dotted grey;
}
.box .row.header {
flex: 0 1 auto;
position: fixed;
/* The above is shorthand for:
flex-grow: 0,
flex-shrink: 1,
flex-basis: auto
*/
}
.box .row.content {
flex: 1 1 auto;
}
.box .row.footer {
flex: 0 1 40px;
}
<!-- Source - https://stackoverflow.com/a/24979148-->
<div class="box">
<div class="row header">
<p><b>header</b>
<br />
<br />(sized to content)</p>
</div>
<div class="row content">
<p>
<b>content</b>
(fills remaining space)
</p>
</div>
<div class="row footer">
<p><b>footer</b> (fixed height)</p>
</div>
</div>
Or using this solution:
html,
body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
.header{
position:fixed;
}
.content {
flex-grow: 1;
border: 1px dotted red;
}
<!-- Source - https://stackoverflow.com/a/28771764-->
<body>
<div class="header">header</div>
<div class="content"></div>
</body>
Is there any way to do make the Content height = 100% - FooterHeight - HeaderHeight
When the Footer and Header dimensions are unknown, and the Header has fixed position?
Since the header is fixed, I think you would need to know its height through JavaScript, and set the body's min-height as 100% of the viewport's height minus the header's height. After, you could simply use CSS Grid on body, to have the content take all the avaiblable height. Like so:
document.body.style.minHeight=`calc(100vh - ${document.querySelector("header").clientHeight}px)`;
document.body.style.paddingTop= document.querySelector("header").clientHeight + "px";
body{
margin:0;
display:grid;
grid-template-rows:1fr auto;
}
header{
background:lightblue;
position:fixed;
top:0;
left:0;
width:100%;
}
div{
background:lightgreen;
}
footer{
background:lightyellow;
}
<header>I'm the header</header>
<div>I'm the content</div>
<footer>I'm the footer</footer>
I can think of two solutions based on the rather general description of your problem:
A) Use JavaScript to do the calculations for you and apply the values to margins or positions, whichever works better in your case;
B) You could repeat the contents of the header (and footer, id that's out of the document flow also) in element(s) atop the content and make it transparent and non-inter-active (pointer-events: none) - dirty, but if JS is not an option and your header does not offer some other way to determine it's height through some 'css-magic' it might be the only solution.
Quite often I find, that there are better solutions when the problem is more specifically described, so if you can tell us what elements make it impossible to know the height of the header, there might be better solutions. Often when ratios as with images are in play, vh can come to the rescue - even though tha can be tricky too...
Finally I found a pure css solution.
since the Header is in the top , using position: sticky instead of fixed will have the same result but the layout will take it into account when calculating:
html,
body {
height: 100%;
margin:0;
}
body {
display: flex;
flex-direction: column;
}
.header{
position:sticky;
}
.content {
flex-grow: 1;
border: 1px dotted red;
}
<!-- Source - https://stackoverflow.com/a/28771764-->
<body>
<div class="header">header</div>
<div class="content"></div>
</body>
I'm trying to lay out a web page that has three reasons - left, top right and bottom right. The left and bottom right regions should have scrollbars in them, and the entire page should fill the screen. I'm using Bootstrap 4.
I can get the scrollbars working properly around the left region. The problem is with the right regions - the horizontal scrollbar appears on the bottom-right region, as it should, but the vertical scrollbar appears on the entire page. Note that the bottom-right also has a vertical scroll bar, but it's disabled.
#outer {
height: 100vh;
overflow: none;
}
#left-col {
height: 100vh;
overflow: scroll;
background-color: #ff85d4;
}
#left-large {
height: 5000px;
width: 5000px;
}
#right-col {
height: 100vh;
}
#right-top {
background-color: #abff64;
}
#right-bottom {
overflow: scroll;
background-color: #ccddff;
}
#right-bottom-inner {
width: 2000px;
height: 2000px;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid">
<div class="row" id="outer">
<div class="col-9" id="left-col">
<div id="left-large">
Large left
</div>
</div>
<div class="col-3" id="right-col">
<div id="right-top">
<p>
Top 1
</p>
<p>
Top 2
</p>
<p>
Top 3
</p>
</div>
<div id="right-bottom">
<div id="right-bottom-inner">
Right bottom inner
</div>
</div>
</div>
</div>
</div>
How can I make the bottom-right region have its own scrollbars?
Like I said in the comments this is another way to do this with CSS grid which seems like the perfect tool for something this ... "gridy" :)
I gave all the boxes plenty of space you can scroll... adjust at will.
Update: I made the right-top box max-content and grow for as long as the content is while giving the right-bottom box a min height of 20px.
body {
padding: 0;
margin: 0;
}
.wrapper {
display: grid;
grid-template-columns: 1.6fr 0.4fr;
grid-template-rows: max-content minmax(20px, 1fr);
gap: 1rem;
height: 100vh;
width: 100vw;
}
.wrapper-inner {
height: 2000px;
width: 2000px;
}
.left,
.right-top,
.right-bottom {
overflow: auto;
padding: 1rem;
}
.left {
grid-row-start: 1;
grid-row-end: 3;
background: hotpink;
}
.right-top {
background: lime;
}
.right-bottom {
background: skyblue;
}
<div class="wrapper">
<div class="left">
<div class="wrapper-inner">
Large left
</div>
</div>
<div class="right-top">
<p>
Top 1
</p>
<p>
Top 2
</p>
<p>
Top 3
</p>
</div>
<div class="right-bottom">
<div class="wrapper-inner">
Right bottom inner
</div>
</div>
</div>
If you want to force a scrollbar on any block element, you'll need to set a fixed height and include an overflow-x:scroll or overflow-y:scroll property depending on where you want the scrollbar to appear.
If you want a horizontal scrollbar, use overflow-x:scroll;, if you want a vertical scrollbar, use overflow-y:scroll;
flex is magic
CSS
/*Allow children to auto fixed height*/
#right-col {
display: flex;
flex-direction: column;
}
#right-top {
height: fit-content; /*Only use essential*/
}
#right-bottom {
overflow: scroll; /*See child content*/
height:100%; /*use all remain height*/
}
Seeing that the height needs to be explicit (either as percentage or a fixed number), I couldn't find a CSS-only solution.
Instead I used a ResizeObserver to track changes to the size of the right-col and right-top elements (in my actual problem, the right-top element changes in size), calculated the right-bottom element (right-col.height - right-top.height basically), and applied it as a dynamic style on the right-bottom element.
Not pretty but it's working.
I tried using a CSS grid, too (instead of bootstrap altogether), but without explicitly specifying the height of the right bottom element, the scrollbars misbehaved there, as well.
I need to create a 2 rows layout for a web page to manage a section for filters and other section for results with the following characteristics:
the page cannot overflow the height of 100%
the height of the first row is based on his content (could be variable and a javascript function can change it by hiding some elements)
the height of the second row is the difference between 100% and the height of first row
in the second row the div with overflow must be the one with class "list" and I can't move it to div with class="result" (that will make it work)
HTML:
<div class="main">
<div class="filter">
<div class="filtercontent">
filter content
</div>
</div>
<div class="result">
<div class="resultcontent">
<div class="list">
<div class="listcontent">
list content
</div>
</div>
</div>
</div>
</div>
CSS:
.main {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
.filter {
width: 100%;
}
.result {
width: 100%;
}
.resultcontent {
height: 100%;
width: 100%;
}
.list {
height: 100%;
width: 100%;
overflow: auto;
}
.listcontent {
height: 1000px;
width: 2000px;
}
I tried with flexbox (in different ways) but I can't find a solution for the last point.
IMPORTANT: I can't use javascript to set the height of the rows. I need a solution using only CSS.
Thanks!
If you declare your .result div with "flex: 1" property it will take all space remaining in the outer div (.main). So if the .filter div occupies 500 height pixels the .result will adjust in the blank space filling the 100% from the parent. If you change it dynamically hiding or adding elements flex: 1 will guarantee that all remaining space will be populated by .result automatically.
Hope it helps
EDIT: My example was to complicated. So I made a simpler one.
http://codepen.io/knobo/pen/gaZVoN
.top grows beyond the available size of the html element. I don't want any content outside the current viewport which is 100vh, but I don't know the height of .bottom which can vary.
This line:
max-height: calc(100vh - 60px);
Makes it look like this works. But it does not, because I don't know the height of .bottom, which I just estimated to 60px;
<div class="page">
<div class="top">
<div class="left">Some text</div>
<div class="right">
<img src="http://placehold.it/350x1800">
</div>
</div>
<div class="bottom">
<button>Click</button>
<button>Click</button>
<button>Could be several lines</button>
</div>
</div>
html, body {
max-height: 100vh;
}
Css
.page {
display: flex;
flex-direction: column;
height: 100%;
}
.top {
flex: 1 1 auto;
display: flex;
overflow: hidden;
max-height: calc(100vh - 60px);
/*
I don't know the height of .bottom
It can change when browser is resized too..
How do I solve this.
*/
}
.left {
flex: 1 1 auto;
}
.bottom {
padding: 10px;
flex: 1 1 auto;
background-color: teal;
}
EDIT2: (included the original links from the first version)
http://codepen.io/knobo/pen/epboBv (css version. Does not work)
http://codepen.io/knobo/pen/wKRNjr/ (js version. Works. But I want to know how to do it with css.)
EDIT3
Screenshots:
When browser window is small, the bottom row disappears, when div.right is too big.
When browser window is large everything shows up (corectly)
This is how it should be: div.top is scaled down, and bottom row is stil visible. I was able to do it with javascript. I guess it should be possible with css too.
The solution is surprisingly easy.
.right {
position: relative;
/* width: Do something with width here. */
}
.nooverflow {
position: absolute;
}
then wrap the content of .right with class="nooverflow"
<div class="right">
<div class="overflow">
{{ Content of .right }}
</div>
</div>
I'm looking for a CSS solution to the following:-
<div style="display:inline;">
<div>The content of this div is dynamically created but will always be wider than
the below div.
</div>
<div> Need this div to have the same width as the above div.
</div>
</div>
The wrapper div has an inline display and works as expected, both child divs have dynamically generated content. I need the bottom one to take the width of the previous sibling.
Many thanks for any suggestions in advance.
Here's another Flexbox solution which allows for the second child to wrap to match the width of the variable height sibling.
.wrapper > div {
border: 1px solid;
}
.child {
display: flex;
}
.child div {
flex-grow: 1;
width: 0;
}
.wrapper {
display: inline-block;
}
<div class="wrapper">
<div>This div is dynamically sized based on its content</div>
<div class="child"><div>This div will always be the same width as the preceding div, even if its content is longer (or shorter too).</div></div>
</div>
Edit:
To support multiple divs under .child, where each div is on its own line, add break-after: always; ...
.child div {
flex-grow: 1;
width: 0;
break-after: always;
}
Floats and tables are so 2000 and late. With today's browsers we can make the two sibling DIVs match each other's width, regardless which is bigger/smaller.
Here's a Flexbox solution fit for 2016:
.wrapper {
display: inline-block;
}
.parent {
display: flex;
flex-direction: column;
}
/* For visualization */
.child {
border: 1px solid #0EA2E8;
margin: 2px;
padding: 1px 5px;
}
<div class="wrapper">
<div class="parent">
<div class="child">Child number one</div>
<div class="child">Child #2</div>
</div>
</div>
Set your div to display:inline-block instead, this way your div will expand with the content inside of it.
http://jsfiddle.net/CpKDX/
2023 keep it simple...
Use grid and the fr unit. Then you can split up into as many equally sized rows or columns as you want:
.container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 1em;
}
.container > div {
border: 1px solid black;
padding: 0.5em;
}
<div class="container">
<div>I'm a part of a grid. I will be split up into equal parts with my other sibling(s) depending on how many columns the grid is given.</div>
<div>I am a sibling element.</div>
</div>
Here is still a flexbox-based approach.
The essential idea: in an outermost wrapper, elements that need to be of equal width are wrapped into another wrapper.
.wrapper {
display: inline-block;
}
.flex-wrapper {
display: flex;
flex-direction: column;
}
.demo-bar {
height: 4px;
background-color: deepskyblue;
}
<div class="wrapper">
<div class="flex-wrapper">
<div contenteditable>Some editable text.</div>
<div class="demo-bar"></div>
</div>
</div>
Another practical example: an adaptive progress bar with the same width below a media (video or audio) element.
video.addEventListener("timeupdate", () =>
progress.style.width = `${video.currentTime / video.duration * 100}%`
)
.wrapper {
display: flex;
flex-direction: column;
position: relative;
align-items: center;
}
video {
display: block;
max-width: 100%;
}
.progress-bar {
height: 0.25rem;
background: #555;
}
#progress {
width: 0%;
height: 100%;
background-color: #595;
}
<div class="wrapper">
<div data-css-role="wrapper">
<video id="video" controls>
<source src="https://raw.githubusercontent.com/mdn/interactive-examples/master/live-examples/media/cc0-videos/flower.webm">
</video>
<div class="progress-bar">
<div id="progress"></div>
</div>
</div>
</div>
UPDATE: This works with me, I've just tried it:
<div style="max-width:980px;border:1px solid red;">
<div style="background:#EEE;float:left;">
<div style="width:auto;border:1px solid blue;float:left;">If you use 100% here, it will fit to the width of the mother div automatically.</div>
<div style="border:1px solid green;"> The div will be 100% of the mother div too.</div>
</div>
<div style="clear:both;"></div>
</div>
Is this what you want? The borders and background are just to show the divs ;)
Just go like this:
Let's say you want the whole divs be max. 980px (otherwise just leave that out or replace with 100%)...
<div style="max-width:980px;">
<div style="width:100%;">If you use 100% here, it will fit to the width of the mother div automatically.
</div>
<div style="width:100%;"> The div will be 100% of the mother div too.
</div>
</div>
The second option would be, to use one more div... or you use style="width:auto;" for the dynamic div...
Not sure if I understood what you are trying to do, but looks like setting a 100% width to the last div should work:
<div style="width:100%;">
BTW the style in the first div is not well defined, you should use a colon instead of a equal sign in the properties definition:
<div style="display:inline;">
If your willing to give up on a couple of <div>s then I have the solution for you:
<div style=“display: inline-block;”>
<table>
<tr>
<td>The table automatically makes its siblings the same width</td>
</tr>
<tr>
<td>So this will be as wide</td>
</tr>
</table>
</div>
Remember to set the div display:inline-block;