How to fix buttons above footer using flex - css

I am using Materializecss to create React app. I have already applied flex inside my app class. And now I want to apply flex inside main tag where buttons get fixed at bottom of main tag & above the footer.
I have tried {margin-top: auto;} , justify-content: flex-end which didn't help. The buttons always print after content class. I can set the height of the content class, but small devices render view badly and it's not fixing my problem.
JSX code:
<div className="app">
<header> <header>
<main>
<div className="box">
<div className="content"> Long text less than 100 words <div>
<div className="buttons"> <button> Button-1 </button> <button> Button-2 </button>
<div>
<main>
<footer><footer>
<div>
My css
app {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex: 1 0 auto;
}
I want to stick my button above the footer. My content class has 100 words then the button should stick above the footer not rendered after the content class.
I would appreciate the help.

You haven't applied display:flex etc to the main element. If you do that the margin-top:auto will work.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::before,
::after {
box-sizing: inherit;
}
.app {
display: flex;
min-height: 100vh;
flex-direction: column;
background: ;
}
main {
flex: 1;
display: flex;
flex-direction: column;
}
.buttons {
margin-top: auto;
}
<div class="app">
<header>header </header>
<main>
<div class="box">box</div>
<div class="content"> Long text less than 100 words </div>
<div class="buttons">
<button> Button-1 </button>
<button> Button-2 </button>
</div>
</main>
<footer>footer</footer>
</div>

Related

Make position:sticky follow an element outside of its parent container?

So what I've got is a landing page that should show a.) a header b.) a large picture that fills the screen on desktop and c.) a navbar. The navbar should scroll along the page once it's reached the top of the page.
Now, the only way I would know to ensure that all three of those elements fit perfectly into the viewport on desktop is with max-height: 100vh in a parent element. However, I'd like to make the navbar scroll along once it's at the top of the screen. This isn't possible when the navbar is in its own container, because it'll stop scrolling along once it's hit the bottom of its container.
Does anyone know of a fix? Below is a sample of the structure I'm trying to use right now:
<div class="container-top">
<header>
<!--- ...header content... -->
</header>
<div>
<img src="1080p_image.png">
</div>
<nav class="sticky-top">
<!-- ...navbar content... -->
</nav>
</div>
<div class="other-content">
<!-- ...other content... -->
</div>
.container-top{
max-height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-between;
}
img{
width: 100vw;
}
header{
background-color: darkgray;
height: 5rem;
z-index: 1;
}
nav{
background-color: darkgray;
height: 5rem;
z-index: 1;
}
.sticky-top{
position: sticky;
top: 0;
}
.other-content{
height: 100rem;
}
Have you tried moving your nav into its own div below div.container-top?
<div class="container-top">
<header>
<!-- ...header content -->
</header>
<div>
<img/>
</div>
</div>
<div>
<nav class="sticky-top">
<!-- ..navbar content... -->
</nav>
</div>
<div class="other-content">
<!-- ...other content... -->
</div>
And if you want these elements to take up 100vh:
.container-top {
max-height: 75vh;
display: flex;
flex-direction: column;
justify-content: space-between;
}
nav {
max-height: 25vh;
}
Lemme know how that works for ya.

CSS span or p goes outside of div

I am trying to replicate stackoverflow-like design and ran into problem.
<div class="flex-grow-0 pd-around-m"> # line 1
<div class="flex-col fill-row mr-around-s"> # line 2
<div class="flex-row fill-row"> # line 3
<div class="flex-col justify-center mr-around-m"> # line 4
//Buttons
</div>
<span>
//Long Text!!
</span>
</div>
<div class="answer-bottom"></div>
</div>
</div>
.fill-row {
width: 100%
}
.flex-col {
display: flex;
flex-direction: column;
}
.flex-row {
display: flex;
flex-direction: row;
}
.mr-around-m {
margin: 1rem;
}
.justify-center {
justify-content: center;
}
When I enter long text in <span>, <div> in line 2, line 3 goes out of div box in line 1.
I tried adding white-space: pre-line to div in line 2 and directly at span but still text goes out of the box.
How can I keep the text inside parent div?
navigation bar on the left has property width:20% but gets squashed. Is this because of the textbox problem I asked above?
EDIT
https://jsfiddle.net/pzcu2yjn/
Here's a replication of my problem. if you make the text in span short enough, navbar and menu will have some empty space in the left maintaining 20% of the screen. however, if you leave the long text as it is, it gets squashed and 20% gets ignored
Few things:
On using flex it is good to provide width for left and right container since container will not know what it should when content increases.
Once you have the width assigned to the right container that is when you can use wrap functionality so the wrap works only for right container and it doesn't have no impact on less container. overflow-break-word;
NOTE:
I have removed unwanted code from the code, you can put it back it has no impact if those are needed.
.flex-row {
display: flex;
width: 100%;
}
.navbar {
display: flex;
flex-direction: column;
justify-content: flex-start;
border-right: 0.05rem solid var(--main-border-color);
align-items: flex-end;
width: 20%;
border: 1px solid red;
}
.pd-around-m {
width: 80%;
border: 1px solid blue;
display: inline-block;
overflow-wrap: break-word;
}
<div class="flex-row">
<div class="navbar">
<div>
menu1
</div>
</div>
<div class="flex-grow-0 pd-around-m">
<div class="flex-col fill-row mr-around-s">
<div class="fill-row">
<span>
AaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaaAaaaaaaaaaaaaaaaaaa
</span>
</div>
<div class="answer-bottom"></div>
</div>
</div>
</div>
You can add overflow: hidden; to prevent the text from going outside of your div.
There's a very similar question with a precise answer:
<span> element going outside of <div> element

CSS Grid - How to implement grid items, which don't "stretch" the grid row and have a scroll-able container

My challenge is:
I want to have a grid with a fixed amount of columns (which can later be adjusted via javascript) and a flexible amount of rows of equal height.
The number of rows are determined by the amount of grid items, which are UI cards.
These cards should fill out the entire height of their respective cell but MUST not increase the height of the row. So basically max-height = row-height assigned by grid
Then inside these cards we have the typical three parts: Header, Body and Footer. The body MUST be scroll-able, if more list items exists than the row-height allows.
I've tried to implement this on stackblitz
https://stackblitz.com/edit/angular-3gkmtm
What i don't understand is
Why the cards "stretches" the row when more items appear
How to achieve the scroll-able card body section without manually using a fixed height (like in the example i use max-height)
Why when there are more then 3 rows, it overflows
Please help!
<article>
<section>
<h2>Fixed Gird with scrollable cards</h2>
</section>
<section>
<button (click)="onAdd()">Add</button>
<button (click)="onRemove()">Remove</button>
</section>
<section class="remaining-height">
<div class="grid-container">
<div class="grid-item" *ngFor="let card of cards">
<div class="card">
<div class="card-header">Card #{{card}}</div>
<div class="card-body card-flexible-scroll">
<div class="list-item" *ngFor="let item of list">{{item}}</div>
</div>
<div class="card-footer">
Some Footer
</div>
</div>
</div>
</div>
</section>
</article>
article{
display: flex;
flex-direction: column;
height: 100%;
}
.remaining-height{
flex:1
}
.grid-container {
display: grid;
grid-gap: 0.5rem;
height: 100%;
grid-auto-rows: auto;
grid-template-columns: repeat(5, auto);
}
.grid-item{
display: flex;
padding:24px;
}
.card{
display: flex;
flex-direction: column;
width: 100%;
height:100%;
background:#ccc;
}
.card-body{
.list-item{
padding: 6px;
background:#fcd3d3;
}
.list-item:nth-child(even){
background:#efefef;
}
}
.card-flexible-scroll{
flex:1;
overflow-y:auto;
max-height: 300px; // <= no max height
}
Angular Controller to generate cards and list items
```js
export class AppComponent {
name = "Angular";
cards = new Array(8).fill(0).map((_,idx)=>idx+1);
list = new Array(30).fill(0).map((_,idx)=>idx+1);
onAdd() {
this.cards.push(this.cards.length + 1);
}
onRemove() {
this.cards.pop();
}
}
global style
html , body{
height: 100vh;
overflow: hidden;
}
If I understand correctly what you are trying to do you want that the card body takes all the available row space between the header and footer and not force the card to be bigger than the row if it contains items.
It is possible to achieve that with adding another div with absolute positioning inside the card body div that is sized to the full body height then the items inside will overflow correctly.
Here is the changed template:
<article>
<section>
<h2>Fixed Gird with scrollable cards</h2>
</section>
<section>
<button (click)="onAdd()">Add</button>
<button (click)="onRemove()">Remove</button>
</section>
<section class="remaining-height">
<div class="grid-container">
<div class="grid-item" *ngFor="let card of cards">
<div class="card">
<div class="card-header">Card #{{card}}</div>
<div class="card-body">
<div class="card-flexible-scroll">
<div class="list-item" *ngFor="let item of list">{{item}}</div>
</div>
</div>
<div class="card-footer">
Some Footer
</div>
</div>
</div>
</div>
</section>
</article>
And the updated CSS:
.card-body{
.list-item{
padding: 6px;
background:#fcd3d3;
}
.list-item:nth-child(even){
background:#efefef;
}
position: relative;
flex:1;
}
.card-flexible-scroll{
position: absolute;
width: 100%;
height: 100%;
max-height: 100%;
overflow-y: auto;
}
I created a fork of your StackBlitz where you can see how it works. If this is not what you look for please explain more.

How to put a div fix at bottom of the page && above footer using css

I have a box (shopping cart) which I want it to be fixed at the bottom of the page.
But if the page is not long enough, or the user scroll to the end of the page, so that the footer is in the viewport. In this case I want the shopping cart box to be right above the footer.
Is it possible to do this without JS?
Thanks
answer only for the fun, you should relay on javascript to make it solid.
There could be a risky trick with position:sticky, floatting pseudo and display resetting.
aside,
footer {
position: sticky;
bottom: 0;
background: white;
border: solid;
clear: both;
z-index: 1;
}
footer {
z-index: 0;/*hide it from aside */
}
html:before {/* push sticky elements down */
content: "";
float: left;
height: 100vh;
}
body {
margin:0;
display: inline;/* get body scrolling and block formatting context off the game */
}
<main>main<br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> <br/> end main</main>
<aside>aside at bottom !</aside>
<footer>footer</footer>
You can play a little with and test it with content, but remenber, its not reliable, sticky not implemented everywhere and behavior can varie from a browser to another, from an update to another in the most funny and unexpected ways.
Your question is not very clear, so I'll try to answer it as best as I understand.
Getting your footer to sit on the bottom of a short page
To achieve this effect, flexbox comes in very handy. First, set the
body's style to : display:flex;
flex-direction: column;
min-height: 100vh;
Setting display:flex makes all child elements on the page (i.e. in the body tag) flex items, hence offering us the opportunity to style said elements as such. Setting flex-direction to column also ensures that all child elements of body are stacked vertically.
Now, the min-height: 100vh; makes the body span at least 100% of the viewport height.
To get an element (in this case your shopping cart box. Let's call it .shopping-cart-box from here on out) to "push" the footer to the bottom of the viewport, you can then set it's flex (or flex-grow, to be precise) value to 1. This makes it take up the rest of the available space.
Remember the body is at 100% of viewport height. If your navigation menu takes up, say, 10% and footer takes up 5% of the viewport height respectively, the .shopping-cart-box with flex: 1; will then fill up the rest of the 85% of viewport height, essentially "pushing" the footer to the bottom of the page.
Making your shopping cart box sit on top of the footer
Now that we have the footer at the bottom and .shopping-cart-box taking up the rest of the available space, we need to force its contents to align bottom.
We can do this by adding display: flex;
flex-direction: column; to .shopping-cart-box. That, again, allows us to treat all child elements of .shopping-cart-box as flex items.
Assuming we have a child element .shopping-cart-product inside .shopping-cart-box, we can set align it to the bottom of its parent container in two ways:
using margin-top: auto or
align-self: flex-end
A visual representation can be found below with the provided code snippet:
/* RELEVANT CODE*/
.body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.shopping-cart-box {
display: flex;
flex: 1;
}
.shopping-cart-product {
margin-top: auto; /* or align-self: flex-end; */
}
/*CODE FOR AESTHETICS */
.container {
width: 90%;
margin-left: auto;
margin-right: auto;
}
.nav {
display: flex;
flex-direction: row;
padding: 12px;
}
.logo {
display: block;
margin-right: auto;
}
/* Footer */
.footer {
background-color: #013940;
padding: 18px 12px;
color: white;
margin-top: 6px;
}
.ui.item.menu,
.ui.item.menu .item {
width: 40% !important;
margin: 0;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css" rel="stylesheet" />
<body class="body">
<header>
<nav class="nav">
<a href="#" class="logo">
<h1>
ShopperStack</h1>
</a>
<ul class="ui two item menu nav--links">
<li class="item">
Home
</li>
<li class="item">
About
</li>
</ul>
</nav>
</header>
<div class="container">
<p>
This is a block of text on the upper part of the page
</p>
</div>
<div class="shopping-cart-box">
<div class="shopping-cart-product container">
<form action="" class="ui segment form">
<div class="field">
<h3 class="header">Place Order</h3>
<p class="label">ACME SuperBlaster 4000</p>
<input type="submit" value="Buy Now" class="ui button">
</div>
</form>
</div>
</div>
<footer class="footer">
<section class="container">
<h3>Thanks for visiting ShopperStack!</h3>
</section>
</footer>
</body>

Using calc() with a dynamic value?

I am wondering if this is possible: I have a header that can contain a variable amount of text. Below that I have another element which I want to take up the remaining height of the page.
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
Normally I would do this using calc, eg:
.content {
height: calc(100vh - 75px);
}
Where 75px is the set height of .header.
But in this example, the .header element is dynamic and does not have a set height. Only a padding and font-size are set.
To complicate things, this also uses the Foundation Grid layout, which makes me nervous about using display: table (.title and .menu sit side by side on desktop, but stacked on mobile) .
Is there anyway to get the height of the dynamic header element (without resorting to JQuery)?
You can use flexbox and set .content to flex-grow: 1 so that it will fill to grow the available space.
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
.content {
flex-grow: 1;
background: #eee;
}
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
I made a small pen to show the way to do this using flex box, it involved changing your markup a bit:
css:
.container {
display: flex;
flex-direction: column;
height: 250px; // whatever you want here
}
.header {
width: 100%;
background: red;
padding: 10px;
}
.content {
background: yellow;
width: 100%;
flex-grow: 1;
}
So the content will always take the available space inside the content div.
check the whole pen: http://codepen.io/anshul119/pen/yMYeLa
hope this helps.

Resources