I'd like to know if there is a way to limit the dimensions of a grid (not the element to which it's applied, the grid itself). I explain :
Let's say we've got a footer, with a dark background, spanning all the width of your page.
This footer contains 2 sub-blocks, classnames .footer__1 and .footer__2, and we want them to occupy 2/3 and 1/3 of the available width, with a 2rem gutter.
Is there a way to give the grid containing the two sub-blocks a grid-max-width (yes, i made that up) of 60rem, without changing the block width (remember, it has a background which must be full width), without using a wrapper ?
So, the occupied width (.footer__1 + gap + .footer__2) should be 60rem max, centered horizontally.
<footer>
<div class="footer__1">foo</div>
<div class="footer__2">whatever</div>
</footer>
.footer {
display: grid;
grid-template_columns: 2fr 1fr;
grid-column-gap: 2rem;
/* grid-max-width: 60rem */
}
Thanks
You have to wrap it with an additional element and limit the width to the additional element.
footer {
background-image: linear-gradient(20deg, red, pink);
}
.container {
display: grid;
grid-template-columns: 2fr 1fr;
grid-column-gap: 2rem;
/* just for demo purpose */
max-width: 300px;
margin: 0 auto;
min-height: 150px;
background: white;
}
<footer>
<div class="container">
<div class="footer__1">foo</div>
<div class="footer__2">whatever</div>
</div>
</footer>
Without another container, I think it is not possible.
However, you can mimic it by making the footer width: 60rem and set the background as a pseudo-element and expand it.
footer {
position: relative;
z-index: 1;
width: 60rem;
margin: 0 auto;
}
footer:before {
content: '';
position: absolute;
top: 0;
left: 50%;
z-index: -1;
transform: translateX(-50%);
width: 9999px;
height: 100%;
background: green;
}
<footer>
<div class="footer__1">foo</div>
<div class="footer__2">whatever</div>
</footer>
The best approach, as I think, is to add div.footer__inner that will hold the two divs - .footer__1 and .footer__2.
Related
Let's say there's a scenario where you have a grid with 3 columns and 2 rows, something like this:
<div class="wrapper">
<div class="content"></div>
<div class="info"></div>
</div>
Elements have these simple styles:
.wrapper {
position: relative;
display: grid;
grid-template-columns: 1fr 1fr 400px;
grid-template-rows: 400px auto;
}
.content {
grid-column: 1/4;
grid-row: 1/3;
}
.info {
position: absolute;
top: 0;
right: 0;
width: 400px;
height: 400px;
}
This would fill the contents of .content element to the whole .wrapper available space and the .info element would be positioned absolute over in the right top corner.
Is it possible to display the contents of .content into everything except to top right cell - like this (red is where the content is):
I'm trying to put a footer at the end of my homepage component. In my website, the overflow is made auto only for mobile view with a media query, so the scroll remains hidden for desktop view. I have used all the solutions I could find but nothing helps, the footer is perfectly aligned in desktop view at the bottom, but for mobile view, it is aligned at the end of the screen (not the page). I have no clue how to fix this.
website: https://shivamaima.netlify.com/
git: https://github.com/darwin619/portfolio
.homepage {
text-align: center;
width: 100%;
position:relative;
padding:0;
margin:0;
min-height:100vh;
top:0;
#media screen and (max-width: 600px) {
overflow: auto;
height: 100vh;
}
.footer {
position: absolute;
right: 0;
bottom: 0;
left: 0;
padding: 1rem;
text-align: center;
}
There's a couple solutions here. Instead of bottom: 0 use:
margin-top: 100vh;
This will set the footer at the bottom of the viewport height.
However, your page has quite a few layout issues, and this is really a band-aid. You should consider utilizing flexbox, min-height, or grid to create a sticky footer.
That being said, the solutions for this using react are what they would be in most any circumstance.
The following solutions are preferable because they are "true" dynamic sticky footers. Meaning, the footer stays at the bottom until the main content extends beyond that area, at which point the footer will begin adjusting its position downward:
The min-height Solution
nav {
height: 40px;
padding: 10px;
background: lightblue;
}
main {
padding: 20px;
background: purple;
min-height: calc(100vh - 170px);
}
footer {
background: magenta;
padding: 10px;
height: 50px;
}
<html>
<body>
<nav>
Navigation
</nav>
<main>
Page content
</main>
<footer>
Footer that stays put
</footer>
</body>
</html>
As can be seen, we set the minimum height of the content to 100vh minus whatever the combined height (plus padding) happens to be of your nav and content containers.
This results in a footer that sticks, along with the ability to drop further if the content exceeds the min-height value.
The same effect can be accomplished using flexbox, which is arguably a more dynamic solution. However, it comes at the expense of an extra container element. We could apply flex to body, but that is rarely a proper solution:
The flex box solution
.container {
display: flex;
min-height: calc(100vh - 40px);
flex-direction: column;
}
nav {
height: 40px;
padding: 10px;
background: lightblue;
}
main {
padding: 20px;
background: purple;
flex: 1;
}
footer {
background: magenta;
padding: 10px;
height: 50px;
}
<body>
// Use className instead of class for react (jsx)
<div class="container">
<nav>
Navigation
</nav>
<main>
Main Content Area
</main>
<footer>
Footer that stays put
</footer>
</div>
</body>
The CSS Grid Solution with min-height
.container {
display: grid;
grid-gap: 1em 0;
grid: auto auto 1fr / 10vw 1fr 10vw;
margin: 0;
min-height: calc(100vh - 40px);
}
nav {
background-color: lightblue;
grid-column: 2;
padding: 20px;
}
main {
background-color: purple;
display: grid;
grid-column: 2;
padding: 20px;
}
footer {
background-color: magenta;
align-self: end;
grid-column: 2;
padding: 20px;
}
// Use className instead of class for react (jsx)
<div class="container">
<nav>
Navigation
</nav>
<main>
Main Content Area
</main>
<footer>
Footer that stays put
</footer>
</div>
Note: Change class to className if you're working on a react project.
I want to use a simple layout, that consists of
An image
Some text
The text should be on the bottom and all remaining space should be used by the image. It seemed a simple task, but it has been a frustrating journey. Finally, I nailed but this solution doesn't work on mobile devices (Android and/or Chrome).
JSFiddle here
It looks like this on the desktop:
Unfortunately, the iPad renders it like this:
The text is barely visible, because the image took all the space. On Android (with Chrome 65 installed) it shows some of the text, but not all of it.
I use the following HTML code
<html>
<body>
<h1>TEST 123</h1>
<div class="wrapper img-top">
<img class="image" src="..." />
<div class="text">
<h2>Header</h2>
<p>...</p>
</div>
</div>
</body>
</html>
The relevant parts of the CSS looks like this (full code on JSFiddle):
* {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
height: 100vh;
overflow: hidden;
}
.wrapper {
display: grid;
grid-gap: 10px;
height: calc(100vh - 85px);
margin-bottom: 20px;
text-align: center;
align-items: center;
}
.wrapper.img-top {
grid-template-rows: 1fr auto;
}
.wrapper.img-top .image {
grid-row: 1;
justify-self: center;
}
.wrapper.img-top .text {
grid-row: 2;
justify-self: center;
}
.wrapper img.image {
max-height: 100%;
max-width: 100%;
}
I guess that there is a problem with the automatic image sizing, but I don't know what to do next? I want to have it responsive, but it just is not going to work.
Your problem is that you put fixed height on img-top. Your img is, let's say, 900 px, it's not the same on screen as iPad and desktop. Since you put your image to be 1 fr of height, it is getting bigger as screen is getting smaller. So you have two solutions, as far as I can tell, first is to restrict the size of your image, max-height: 300px;, or try putting overflow auto on .img-top.
Thanks #Jakub Muda for the suggestion about using flexboxes. I have finally fixed the problem by moving to a flexbox and fix the remaining issues.
After switching to a flexbox, I kept the same problem. The image was sized to 100% of the size of the parent wrapper div. I have fixed this by adding overflow: hidden to the image, so it will not overflow. This worked fine, but some images were distorted, because the aspect-ratio wasn't properly maintained. Adding object-fit: contain fixed this issue.
The complete sample can be found at JSFiddle, but for completeness I have added the CSS here as well:
* {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
height: 100vh;
overflow: hidden;
}
.wrapper {
display: flex;
flex-direction: column;
height: calc(100vh - 85px);
margin-bottom: 20px;
text-align: center;
align-items: center;
}
.wrapper .image {
justify-self: center;
flex: auto;
overflow: hidden; /* Important to make sure the image stays within bounds */
object-fit: contain; /* Important to make sure the image keeps its aspect ratio */
}
.wrapper .text {
justify-self: center;
flex-basis: none;
padding-top: 10px;
}
.wrapper img.image {
max-height: 100%;
max-width: 100%;
}
Here is my code to stick the footer to bottom of the page:
#footer {
background-color: #0F2157;
width: 100%;
bottom: 0px;
min-height: 35px;
padding-top: 5px;
}
When I'm doing it with height it works perfectly fine, but when I'm trying to set the minimum height it leaves a little space under the footer. Any guess how to fix that?
First of all, the height of body, html and container (see element with class 'container') has to have height: 100%;
In this solution I have used flex box. It is supported by all modern browsers and IE11.
It's necessary to add the following properties to container:
display: flex;
flex-direction: column; /*the flex items are placed in column, by default it is in row*/
To move footer to bottom, just add to flex item
margin-top: auto; /* it grabs all free space between flex items and put it before this flex item */
html, body {
height: 100%;
}
.container {
height: 100%;
background-color: green;
display: flex;
flex-direction: column;
}
.header {
height: 20%;
background-color: yellow;
}
.content {
background-color: white;
}
.footer {
min-height: 20%;
background-color: blue;
margin-top: auto;
}
<div class="container">
<div class="header">Header</div>
<div class="content">It's content</div>
<div class="footer">Footer in bottom</div>
</div>
What about using Flexbox? It is supported by IE>=10.
To use that, you have to split your page at least in two separated elements: The "upper"-one (.content) with the whole content of your page and the footer.
The "upper"-one gets the value flex: 1, which is a shorthand for:
flex-grow: 1
flex-shrink: 1
flex-basis: auto
This means, that the "upper"-element could grow to the maximum, while the footer reserves only it's actually required space.
Code snippet
html {
height: 100%;
}
body {
min-height: 100%;
margin: 0;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
}
<!doctype html>
<html>
<head>
</head>
<body>
<div class="content"></div>
<footer class="footer">
Hey footer!
</footer>
</body>
</html>
You used min height 35 px. I think your content's height inside of footer is more than 35px. So check the margin or padding of all footer elements.
It will be better, if you can make a jsfiddle demo.
[SOLVED]
I found this to be working for my example:
#footer {
position: absolute;
bottom: 0;
width: 100%;
}
I have a div called .side-el which I would like to have in a position: fixed; behavior, but as soon as I apply position fixed the width alternates from the right one. The right width would be the one set by flexbox. How can I achieve this goal?
.container {
-webkit-align-content: flex-start;
align-content: flex-start;
-webkit-align-items: flex-start;
align-items: flex-start;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-justify-content: flex-start;
justify-content: flex-start;
* {
box-sizing: border-box;
-webkit-flex-grow: 1;
flex-grow: 1;
-webkit-flex-shrink: 0;
flex-shrink: 0;
}
}
.main-el {
box-sizing: border-box;
padding:0 2em;
width: 70%;
}
.side-el {
box-sizing: border-box;
width: 30%;
}
<div class="container" style="background-color: blue; height: 100px;">
<div class="main-el">
<div style="background-color: red; height: 1000px;">content</div>
</div>
<div class="side-el" >
<div style="background-color: red; height: 100px;">content</div>
</div>
</div>
Here's a way to do this inspired by bootstrap:
.fixed-top {
display: flex;
position: fixed;
top: 0;
left: 0;
right: 0;
}
This gives your flex-box room to breathe and do it's flex-box thing. If your flex-direction is column, you could use top, left, bottom instead.
This works because when you give an element a fixed position and a left and right of 0 or a top and bottom of 0, the element is stretched to fill the space from left to right, or top to bottom. That in turn allows a flex-box to use the amount of space you would expect without position fixed.
You can't.
As explained by the CSS2.1 spec:
Absolutely positioned boxes are taken out of the normal flow.
And the Flexible Box Layout spec confirms that:
An absolutely-positioned child of a flex container does not
participate in flex layout. However, it does participate in the
reordering step (see order), which has an effect in their
painting order.
(Emphasis mine)
#Daniel , I know this is very late but ... while the accepted answer is correct, I don't feel it's very helpful.
I had the same question (which is how I came across this post), and the solution I think I'll go with is to wrap the position fixed element within the flex element.
Here's a (very ugly) example
Relevant Markup
<aside class="Layout-aside" ng-class="{'isCollapsed': collapsed}" ng-controller="AsideCtrl">
<div class="Layout-aside-inner">
<button ng-click="collapsed = !collapsed">
<span ng-show="collapsed">></span>
<span ng-hide="collapsed"><</span>
</button>
<ul class="Layout-aside-content">
<li ng-repeat="i in items">{{i}}</li>
</ul>
</div>
</aside>
Relevant CSS
.Layout-aside {
order: 0;
min-width: 140px;
width: 140px;
background-color: rgba(0, 255, 0, .4);
transition: width .4s, min-width .4s;
}
.Layout-aside.isCollapsed {
min-width: 25px;
width: 25px;
}
.Layout-aside-inner {
position: fixed;
}
.Layout-aside.isCollapsed .Layout-aside-inner {
width: 25px;
}
.Layout-aside.isCollapsed .Layout-aside-content {
opacity: 0;
}
position:sticky was mentioned by Juozas Rastenis above but without code example.
Here's a minimalist example:
* {
box-sizing: border-box;
}
body {
display: flex;
margin: 0;
}
nav {
width: 20%;
height: 100vh;
top: 0; /* this is required for "sticky" to work */
position: sticky;
background: lightblue;
padding: 1rem;
}
main {
height: 3000px; /* cause scroll */
background: lightpink;
flex-grow: 1;
padding: 1rem;
}
<body>
<nav>
sidebar here
</nav>
<main>
content here
</main>
</body>
You can achieve it with a css alternative position: sticky
It acts great but the only problem is browser support (June 2018):
https://caniuse.com/#feat=css-sticky
Hope it gets better soon.
A far simpler solution would be to use overflow-y:scroll and height: 100vh on the main-el container. This will give the appearance of fixed position to the side-el container without resorting to position: fixed.
You are saying you want position:fixed;-like behavior that plays together with flexbox. As mentioned in the accepted answer, applying this property to an element drops it out of the normal flow, so this isn't really possible.
If what you want is to have a fixed sidebar .side-el and a scrollable content box .main-el as the items of a flex container, here's how you might do this:
Disable scrolling in the flex container's parent; let's assume it's
<body>, as you don't provide div.container's parent. Also, hard-set
it's height to viewport-height (100vh) so that no part of the body's
box remains outside view (imagine the body's box normally extending
beyond your screen to contain the entire document; you don't want
that, if you are to disable the ability to move the viewport via
scrolling).
Set the flex container's (.container) height to that of it's parent.
Selectively re-enable scrolling for the content box (.main-el).
In CSS:
body{
overflow: hidden;
height: 100vh;
}
.container {
display: flex;
height: 100%;
}
.main-el {
overflow-y: auto;
}
You can achieve this without position: fixed; by just adding overflow: auto; and height: 100%; to the flex-item that contains the long content:
.container {
display: flex;
}
.main-el {
padding:0 2em;
width: 70%;
overflow: auto;
height: 100%;
}
.side-el {
width: 30%;
}
<div class="container" style="background-color: blue; height: 300px;">
<div class="main-el">
<div style="background-color: red; height: 1000px;">content</div>
</div>
<div class="side-el" >
<div style="background-color: red; height: 100px;">content</div>
</div>
</div>
I had the same issue, I actually just found a way to have flex-box, a width for the nav bar, and center it while in a fixed position.
nav {
display: flex;
height: 50px;
width: 90%;
left: 5%;
position: fixed;
}
I wanted to be able to have a flex-box nav bar in a fixed position but centered. So what I did was do the left 5% since that's equal to half of the 10% width left over. Try it out, it might help you! :)