Attaching a page layout to explain my requirements better.
Place the the text just before the footer section.
Some time the footer may not be visible (may need scroll), in that case bring the text to the bottom of visible area.
I have tried many ways to achieve this.
Any pointers to solve this issue would be helpful.
Thanks,
Santhosh
You can use flexbox to achieve this
body {
margin: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.content {
/* occupy all height */
flex: 1 0 auto;
/* nested flex container */
display: flex;
flex-direction: column;
}
.bottom-text {
/* Move to the bottom */
/* This works because this is flex item */
margin-top: auto;
}
/* styles just for demo */
body {
text-align: center;
}
header {
background-color: tomato;
}
.content {
background-color: lightsteelblue;
}
.bottom-text {
background-color: moccasin;
}
footer {
background-color: lime;
}
<header>Page header</header>
<section class="content">
Page content
<div class="bottom-text">Place a text just before footer</div>
</section>
<footer>Page footer</footer>
For showing bottom-text when footer is not visible we'll use Javascript:
// Checks if element is visible on screen
function checkVisible(element) {
var rect = element.getBoundingClientRect();
var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
}
var footer = document.querySelector("footer");
var bottomText = document.querySelector(".bottom-text");
var bottomTextFixedClassName = "bottom-text--fixed";
// Sets element position as fixed
// when footer is not visible on screen
function setFixedButtonText() {
if (checkVisible(footer))
bottomText.classList.remove(bottomTextFixedClassName);
else
bottomText.classList.add(bottomTextFixedClassName);
}
window.addEventListener("scroll", setFixedButtonText);
setFixedButtonText();
body {
margin: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.content {
/* occupy all height by flex-grow: 1 */
/* Don't shrink using flex-shrink: 0 */
/* Setting flex-basis to 1500px to emulate long content */
/* Replace 1500px with auto in production code */
flex: 1 0 1500px;
/* nested flex container */
display: flex;
flex-direction: column;
}
.bottom-text {
/* Move to the bottom */
/* This works because this is flex item */
margin-top: auto;
}
.bottom-text--fixed {
position: fixed;
left: 0;
right: 0;
bottom: 0;
}
/* styles just for demo */
body {
text-align: center;
}
header {
background-color: tomato;
}
.content {
background-color: lightsteelblue;
}
.bottom-text {
background-color: moccasin;
}
footer {
background-color: lime;
}
<header>Page header</header>
<section class="content">
Page content
<div class="bottom-text">Place a text just before footer</div>
</section>
<footer>Page footer</footer>
If you need IE suppost you can use change min-height: 100vh; to height: 100vh;. This is workaround for IE's min-height bug for flex with flex-direction: column;.
Related
I know the title is a known 'issue'. However, I have tried many solutions, but none seem to work.
My footer is stuck on the bottom (phew) on almost all cases (when there is a lot of content, when I can scroll,..). Sadly, when there is barely any content, it just goes straight to the middle. I really have no clue why this is happening :( I am using Gatsbyjs for my website.
This is the global.css
html {
height: 100%;
}
main {
flex: 1 0 auto;
}
body {
display: flex;
flex-direction: column;
position: relative;
height: 100%;
margin: 0;
font-family: "Roboto", sans-serif;
color: whitesmoke;
background: radial-gradient(circle at center, #2b2b2b, #414141);
}
My footer.js component and it's css is:
css:
footer {
background-color: #2b2b2b;
position: relative;
font-size: smaller;
opacity: 0.98;
padding: 1rem;
width: 100%;
margin-top: auto;
}
html for footer:
const Footer = () => {
return (
<div>
<footer>
<p>©Copyright {currentYear} Humital - Made with ❤️</p>
</footer>
</div>
)
}
export default Footer
the main html comes from layout.js:
<div className={styles.flex}>
<NavBar />
<div className={styles.container}>
<main>{children}</main>
</div>
<Footer />
</div>
Which holds some css for the container:
.container {
display: flex;
flex-direction: column;
padding-top: 5rem;
padding-bottom: 1rem;
margin-left: 1rem;
line-height: 1rem;
flex: 1 0 auto;
position: relative;
}
.flex {
flex: 1;
}
Not sure why the footer won't go down when there is no content :( Any help is welcome! :)
I think you just need to add min-height: 100vh rule (and a flex-direction) to your .flex class:
.flex {
flex: 1;
min-height: 100vh;
flex-direction: column;
}
Because your .container has the flex: 1 0 auto will push the footer to the bottom.
Summarizing, you only need this rules to stick your footer to the bottom:
.flex {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.container {
flex: 1 0 auto;
}
.flex applies to the outer wrapper, which contains the Footer, the <main> and the <NavBar />.
.container applies to the <main> or the <main>'s wrapper. I think it's not needed to wrap the <main> with another <div>, you can apply the styles directly to the <main> tag, yet the approach to push the footer to the bottom is exactly the same.
I am using Angular 6 and my templates are as below.
Header, Left panel, Body part, footer
Header,Left panel, Body part, right panel, footer
Header, body part, footer
Since, I have so many templates, I wanted to make it JSON driven instead of just hardcoding html part.
The JSON file will look like,
{
"horizontal" : [
{
width : 20%,
height: 100%
},
{
width : 80%,
height: 100%,
{
"vertical" : [
{
width : 80%,
height: 60%
},
{
width : 80%,
height: 40%
}
]
}
}
],
}
Here, the page gets divided into left panel(20% width) and body(80%) and then body gets divided into vertically like 60% top and 20% bottom.
Is there any way to make this JSON into HTML?
While this question is too broad, I were/am a back end guy too, and wen't through many ideas before landing, so I decided to post an answer and share my experience.
My intention with this is to show how simple, and with how little code, one can create something reusable and easy to maintain.
Instead of convert styles from a JSON to HTML, use what is meant for that, CSS, and here is a few samples how to manage many templates with a small style guide, and get one of the best features of all, performance.
With one CSS, making using Flexbox, and the given logic for your different templates, it could look like this.
Sample 1 (with CSS notes)
html, body, .container {
height: 100%;
margin: 0;
}
.container, main {
display: flex; /* make children flex items */
flex-direction: column; /* default flow is row */
}
header, footer { /* flex column item will by default fill parent's width */
/* height is controlled by content */
}
.wrapper {
flex: 1; /* fill remaining height (flex column item) */
display: flex;
}
aside { /* flex row item will by default fill parent's height */
flex-basis: 20%; /* set width (flex column item) */
}
main {
flex: 1; /* fill remaining width (flex row item) */
}
section {
flex-basis: 60%; /* set height (flex column item) */
}
section + section { /* target the 2nd section */
flex-basis: 40%;
}
/* for demo purpose */
header, footer, aside, section {
border: 1px dotted gray;
}
<div class="container">
<header>Header</header>
<div class="wrapper">
<aside>Aside</aside>
<main>
<section>Section</section>
<section>Section</section>
</main>
</div>
<footer>Footer</footer>
</div>
Sample 2
html, body, .container {
height: 100%;
margin: 0;
}
.container, main {
display: flex;
flex-direction: column;
}
header, footer {
}
.wrapper {
flex: 1;
display: flex;
}
aside {
flex-basis: 20%;
}
main {
flex: 1;
}
section {
flex-basis: 60%;
}
section + section {
flex-basis: 40%;
}
header, footer, aside, section {
border: 1px dotted gray;
}
<div class="container">
<header>Header</header>
<div class="wrapper">
<aside>Aside</aside>
<main>
<section>Section</section>
<section>Section</section>
</main>
<aside>Aside</aside>
</div>
<footer>Footer</footer>
</div>
Sample 3
html, body, .container {
height: 100%;
margin: 0;
}
.container, main {
display: flex;
flex-direction: column;
}
header, footer {
}
.wrapper {
flex: 1;
display: flex;
}
aside {
flex-basis: 20%;
}
main {
flex: 1;
}
section {
flex-basis: 60%;
}
section + section {
flex-basis: 40%;
}
header, footer, aside, section {
border: 1px dotted gray;
}
<div class="container">
<header>Header</header>
<main>
<section>Section</section>
<section>Section</section>
</main>
<footer>Footer</footer>
</div>
Or for a given template, using different CSS (only show 1 and 3 here, as 2 will be the same as the above)
Sample 1
html, body, .container {
height: 100%;
margin: 0;
}
.container, main {
display: flex;
flex-direction: column;
}
header, footer {
}
.wrapper {
flex: 1;
display: flex;
}
aside {
flex-basis: 20%;
}
main + aside { /* target the 2nd/right aside */
display: none;
}
main {
flex: 1;
}
section {
flex-basis: 60%;
}
section + section {
flex-basis: 40%;
}
/* for demo purpose */
header, footer, aside, section {
border: 1px dotted gray;
}
<div class="container">
<header>Header</header>
<div class="wrapper">
<aside>Aside</aside>
<main>
<section>Section</section>
<section>Section</section>
</main>
<aside>Aside</aside>
</div>
<footer>Footer</footer>
</div>
Sample 3
html, body, .container {
height: 100%;
margin: 0;
}
.container, main {
display: flex;
flex-direction: column;
}
header, footer {
}
.wrapper {
flex: 1;
display: flex;
}
aside {
display: none;
}
main {
flex: 1;
}
section {
flex-basis: 60%;
}
section + section {
flex-basis: 40%;
}
/* for demo purpose */
header, footer, aside, section {
border: 1px dotted gray;
}
<div class="container">
<header>Header</header>
<div class="wrapper">
<aside>Aside</aside>
<main>
<section>Section</section>
<section>Section</section>
</main>
<aside>Aside</aside>
</div>
<footer>Footer</footer>
</div>
After resizing of page nested content-box get down thru main div and break it.
It's look like so:
Here is live example (Content loading work on Chrome only). Here is jsfiddle
The css code that response for displaying problem (as I think) part:
.Central {
display: flex;
flex-direction: row;
flex-grow: 1;
height: auto;
}
.LeftSide {
background-color: #ddd0d1;
flex-grow: 8;
}
.RightSide{
background-color: #965254;
flex-grow: 1;
}
Instead of height: 100vh, use min-height: 100vh.
.MainContainer {
background-color: #fee9ea;
margin-left: 0%;
margin-right: 0%;
/* height: 100vh; <-- remove fixed height */
min-height: 100vh; /* new */
box-sizing: border-box;
display: flex;
flex-direction: column;
}
That will release your main container to expand with the content.
If you prefer the fixed height, then keep the height: 100vh and add vertical scroll:
.LeftSide {
background-color: #ddd0d1;
flex-grow: 8;
overflow: auto; /* new */
}
I'd like to know: is it possible to build a 3 rows layout, 100% height, with flexbox?
<header> The header content goes here. </header>
<div class="content"> The main content goes here. </div>
<footer> The footer content goes here. </footer>
fixed-height header and footer, while content the liquid part.
I mean, something like this but without absolute positioning:
* {
margin: 0;
}
header {
position: absolute;
width: 100%;
height: 64px;
top: 0;
background: red;
}
footer {
position: absolute;
width: 100%;
height: 64px;
bottom: 0;
background: green;
}
.content {
position: absolute;
width: 100%;
top: 64px;
bottom: 64px;
background: blue;
}
<header>The header content goes here.</header>
<div class="content">The main content goes here.</div>
<footer>The footer content goes here.</footer>
http://jsfiddle.net/BMxzn/
body {
display: flex;
flex-direction: column;
height: 100vh;
}
.content {
flex: 1; /* this is the key; consumes all available height */
background: blue;
}
header {
height: 64px;
background: red;
}
footer {
height: 64px;
background: green;
}
* {
margin: 0;
}
<header>The header content goes here.</header>
<div class="content">The main content goes here.</div>
<footer>The footer content goes here.</footer>
I add my own accepted answer here, because it addresses other issues as well.
I noted that the usually suggested code has a problem with Android prior to 4.4.4. By better indagating > this and > this I found out that the problem is > this, even if Android is not mentioned on the affected browsers list. So, my solution was to add flex-shrink: 0 to the content:
body{
display: flex;
flex-direction: column;
height: 100%;
}
.main-content{
flex: 1 0 auto; // flex-shrink:0 > android 4.4.2 fix (and some other browsers too)
}
It's also good to assign some kind of flex property to header and footer. I noticed on Android 442 that otherwise the bg color was gone:
.main-header,
.main-footer{
flex: none; // or flex something.
}
Also please note that I'm using Autoprefixer. Otherwise, you should not use the shortcut on main-content (IE shit-fix):
.main-content{
flex-grow: 1;
flex-shrink:0;
flex-basis:auto;
}
Very similar to these question : this & this
You need only 3 lines of code:
display:flex;
flex-flow:column;
height:/* whatever height needed */
and then flex:1; to the container that needs to fill remaining space
* {
margin: 0;
}
body {
display: flex;
flex-flow: column;
height: 100vh;/* if you relay on flex, then vh is also understood */
}
body>* {
padding: 1em;
}
header {
background: red;
}
footer {
background: green;
}
.content {
flex: 1;
background: blue;
color: white;
/* optionnal if you want to keep footer at screen
overflow:auto; */
}
<header>The header <b>of any height</b> content goes here.</header>
<div class="content">The main content goes here.</div>
<footer>The footer <b>of any height</b> content goes here.</footer>
there is no need to set heights to footer or header , but you might add overflow:auto to the main container.
I have the following construct to render a simple layout with fixed header and footer and a flexible body that with scrollable content: http://jsbin.com/jokevuyave/1/edit?html,css
<div id="main-view">
<div class="rows">
<div class="head">header</div>
<div class="main scroll"></div>
<div>footer</div>
</div>
</div>
and this are the styles:
.rows,
.columns {
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.columns {
flex-direction: row;
max-height: 100%;
overflow: hidden;
}
.main {
flex: 1;
}
.scroll {
display: flex;
overflow: hidden;
position: relative;
flex-direction: column;
}
.scroll > * {
margin: 0;
width: 100%;
overflow: auto;
}
html,
body,
#main-container,
#main-view,
.scrollable {
height: 100%;
margin: 0
}
#main-view > div {
max-height: 100%;
display: flex;
}
.head {
height: 120px
}
This construct works well in firefox and also in chrome until the version 43 was released. Now the height of the containers is wrong, header and footer don't expand to display its content and the content container lays over the header content. Any idea how to fix this?
Edit
The problem seems to be this line:
#main-view > div {
max-height: 100%;
}
The idea is that the box should only expand if the content is to large.
Change it to
#main-view > div {
height: 100%;
}
fix the wrong height for the inner container but now the box has always the height of 100%, even if the content is really small.
There is a problem with max-heigth and flexbox: flexbox misbehaving with max-height
So the solution is to set the flex property to every element insight rows container to 0
.rows .main {
flex: 1;
}
.rows > * {
flex: 0 0 auto
}