Confusion when combining flex and absolute positioning - html

I have an app that is essentially a header, main content, and a footer which is always visible. The footer can change size, and there are some tools I want to place on the main content panel above the footer. The main layout is done with flex, and my understanding reading the docs is that absolute positioning combines with flex layouts by positioning relative to the nearest descendant, but that doesn't appear to be my experience. Hoping someone can help me out here.
In the code example below, I am expecting to see the "bottom" div positioned above the footer, but it's actually at the bottom of the window.
Here's the jsfiddle link: http://jsfiddle.net/L809zbey/
The HTML:
<div class="flex">
<div class="header">Sweet header</div>
<div class="content">Main content
<div class="bottom">
This guy should be fixed above the footer.
</div>
</div>
<div class="footer">Equally sweet footer</div>
</div>
CSS:
.flex{
border: 1px solid #ddd;
font: 14px Arial;
display: flex;
flex-direction: column;
}
.header{
background : #007AA2;
flex: 0 0 auto;
}
.content{
background : #FFF;
flex: 1 1 auto;
height: 200px;
}
.footer{
background : #7FCADE;
flex: 0 0 auto;
}
.bottom {
position: absolute;
bottom: 20px;
}

Try adding position:relative; to your .flex class. The .bottom element is currently relative to the body hence why it's stuck to the bottom of the page.

you'll want to add position: relative; to .flex. Things that are positioned absolutely will be positioned relative to the nearest positioned ancestor. If there are none it will be relative to the body

You don't need to position the element absolutely...just make sure it's always at the bottom of the .content div. In this way it will never overlay any actual content which it would do if it has absolute position.
You can achieve this by making the .content div a flex-column and applying margin-top:auto your tools div.
.flex {
border: 1px solid #ddd;
font: 14px Arial;
display: flex;
flex-direction: column;
}
.header {
background: #007AA2;
flex: 0 0 auto;
}
.content {
background: pink;
flex: 1;
display: flex;
flex-direction: column;
height: 200px;
}
.footer {
background: #7FCADE;
flex: 0 0 auto;
}
.bottom {
margin-top: auto;
background: orange;
}
<div class="flex">
<div class="header">Sweet header</div>
<div class="content">Main content
<div class="bottom">
This guy should be fixed above the footer.
</div>
</div>
<div class="footer">Equally sweet footer</div>
</div>

Related

Using flexbox, how to overlay an image and expand to fill parent container

In the following html I want the txt-box div to be centered in the container, overlay the image, and expand to fill the container. It should have a margin of equal width on all sides allowing part of the image to show like a thick border.
The html shown is passable for what I want except the vertical vs. horizontal margins are always slightly different as the browser window is resized.
I feel like what I have here is a hack and that I am using flex-grow incorrectly. I understand flex-grow works to allow the txt-box div to expand since it is the only element with a grow value. If I can get that resolved I should be able to simply set a margin on txt-box and it should work.
What am I not understanding about flex-grow?
.container {
display: flex;
align-items: center;
justify-content: center;
border: solid 2px red;
position: relative;
}
.container img {
width: 100%;
flex-grow: 0;
flex-shrink: 0;
}
.txt-box {
background-color: white;
display: flex;
padding: 5px;
border: solid 2px blue;
flex-grow: 1;
position: absolute;
width: 90%;
height: 80%;
}
<div class="container">
<img src="blocks.png" />
<div class="txt-box">
hello world
</div>
</div>
Thanks to Michael Benjamin for putting me on the path to enlightenment. I finally got it figured out. My original question was actually a portion of what I was trying to accomplish. The answers are to use background-image:url('...') and make sure the table and row elements are display:flex.
JSFiddle
<html>
<head>
<style>
.flex-table {
flex-flow:column;
}
.flex-row {
flex-flow:row;
}
.container {
align-items: center;
justify-content: center;
padding: 20px;
border: solid 2px red;
background-image:url('https://i.imgur.com/BF3ty6o.jpg');
background-size:cover;
background-repeat:no-repeat;
max-width:500px;
}
.txt-box {
justify-self:stretch;
align-self:stretch;
border: solid 2px blue;
background-color: rgba(192,192,192,0.5);
}
body, .flex-table, .flex-row, .container, .txt-box {
display:flex;
flex-grow:1;
}
#media (max-width: 768px) {
.flex-row {
flex-flow:column;
}
}
</style>
</head>
<body>
<div class="flex-table">
<div class="flex-row">
<div class="container">
<div class="txt-box">
hello world 1
</div>
</div>
<div class="container">
<div class="txt-box">
hello world 2
</div>
</div>
<div class="container">
<div class="txt-box">
hello world 3
</div>
</div>
</div>
<div class="flex-row">
<div class="container">
<div class="txt-box">
hello world 4
</div>
</div>
<div class="container">
<div class="txt-box">
hello world 5
</div>
</div>
<div class="container">
<div class="txt-box">
hello world 6
</div>
</div>
</div>
</div>
</body>
</html>
What am I not understanding about flex-grow?
Flex properties don't work on absolutely positioned children of a flex container.
§ 4.1. Absolutely-Positioned Flex
Children
As it is out-of-flow, an absolutely-positioned child of a flex
container does not participate in flex layout.
Therefore, flex-grow: 1 on txt-box is not doing anything. It's just being ignored.
Considering that you want the image simply laying in the background, while the text box has more requirements, I would suggest absolutely positioning the image and leaving the text box in the normal flow.
Then give the text box full width and height, with equal padding on the primary container to keep uniform "margins" across screen sizes.
Here's a demo, with a few extra features to help illustrate the concepts involved.
body {
height: 100vh;
display: flex;
margin: 0;
padding: 10px;
}
.container {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
position: relative;
border: solid 2px red;
}
img {
position: absolute;
height: 100%;
width: 100%;
object-fit: contain; /* also try 'cover' for demo */
}
.txt-box {
z-index: 1;
width: 100%;
height: 100%;
border: solid 2px blue;
background-color: rgba(192,192,192,0.5);
}
* {
box-sizing: border-box;
}
<div class="container">
<img src="http://i.imgur.com/60PVLis.png">
<div class="txt-box">hello world</div>
</div>
jsFiddle demo

How to center flexbox sticky footer with a set width

I'm using flexbox to make my footer stick to the bottom, and for the most part it's working. My problem is, I need the content to be within a specified width, that I set with max-width and center with margin-left:auto; and margin-right:auto;. When I activate flexbox, the contents are squished by the margin-left and margin-right rules, and do not take up the space defined by max-width. I would like to know why this is happening and how to get my footer to look how I want it to look.
Here is how I want my footer to look:
And here is how flexbox is affecting it:
body {
display: flex;
flex-direction: column;
min-height: 100%;
}
div#content {
flex: 1 0 auto;
}
footer {
flex: 0 0 auto;
max-width: 67.5rem;
margin-left: auto;
margin-right: auto;
padding-left: 1.25rem;
padding-right: 1.25rem;
padding-bottom: 1.875rem;
padding-top: 3.5rem;
}
<body>
<header>...</header>
<div id="content">...</div>
<footer>
<span id="left">left text</span>
<span id="mid">right text url#mail</span>
<span id="icons">...</span>
</footer>
</body>
If I change max-width to width then it works, but then when I test it in my browser using the device-mobile setting to see how it would look on a mobile device, the width property makes the footer too big and messes up the content. If I take out the margin-left and margin-right properties, then my footer looks like this:
As you can see it's no longer centered. I can't use the flex-basis property because that only affects the height of the footer. Please help.
Edit
Here is a snippet with margin-left and margin-right taken out and replaced with display:flex; and justify-content:space-around;. Be sure to click "Full page" to view with a larger viewport.
body {
display: flex;
flex-direction: column;
min-height: 100%;
}
div#content {
flex: 1 0 auto;
}
footer {
flex: 0 0 auto;
max-width: 67.5rem;
padding-left: 1.25rem;
padding-right: 1.25rem;
padding-bottom: 1.875rem;
padding-top: 3.5rem;
display: flex;
justify-content: space-around;
}
<body>
<header>...</header>
<div id="content">...</div>
<footer>
<span id="left">left text</span>
<span id="mid">right text url#mail</span>
<span id="icons">...</span>
</footer>
</body>
This can be done easily with justify-content: space-between;, but looking at your code I feel you may misunderstand a bit how Flexbox itself works. You want your footer to act as a flex container so you can manipulate the child spans as well.
Consider checking out freeCodeCamp's Flexbox Challenges to get a better idea how Flexbox works.
EDIT: CodePen now reflects what OP was meaning to immitate.
Here's a CodePen to play around with.
What this does is makes your footer both a child and container.
First your body becomes a container to allow the main content to grow to fill the space pushing your footer to the bottom of the page. The flex-direction is set to column to flow vertically.
You create a wrapper for your footer, because currently your footer is in the body container which is set to flex-direction:column; where in this case, you want the direction to be row to style horizontally. By default display:flex; will assume you wanted row so direction doesn't need declared. We then justify-content to the center so no matter the width the footer itself will be centered.
You treat your <footer> as both a child and container. As a child we tell it not to grow or shrink and set the basis to auto. As a container, we tell it to distribute space-between its children which allows a consistently equal amount of space between the left & right spans.
body {
display: flex;
height: 100%;
flex-direction: column;
}
.main {
flex: 1 0 auto;
border: 1px solid #000;
}
.wrapper {
display: flex;
justify-content: center;
}
footer {
flex: 0 0 auto;
display: flex;
margin: 1em;
width: 80%;
border: 1px solid #000;
justify-content: space-between;
}
<body>
<div class="main">
<h1>Hello Flex</h1>
<p>This is Flexbox</p>
<h1>Hello Flex</h1>
<p>This is Flexbox</p>
</div>
</body>
<div class="wrapper">
<footer>
<span id="left">left text</span>
<span id="mid">right text url#mail</span>
</footer>
</div>
I gave up trying to get this to center with flexbox. Instead I used the calc function to calculate the padding-left and padding-right of my <footer> tag. Here is what I came up with (I'm using 47.5rem instead of 67.5rem because I think it's easier to see the behavior).
body {
display: flex;
flex-direction: column;
min-height: 100%;
}
div#content {
flex: 1 0 auto;
}
footer {
flex: 0 0 auto;
display: flex;
align-items: center;
padding-left: calc(((100vw - 47.5rem)/2) + 1.25rem);
padding-right: calc(((100vw - 47.5rem)/2) + 1.25rem);
padding-bottom: 1.875rem;
padding-top: 3.5rem;
}
#left {
flex: 1;
order: 1;
}
#mid {
flex: 0 0 auto;
order: 2;
}
#icons {
order: 3;
}
<body>
<header>...</header>
<div id="content">...</div>
<footer>
<span id="left">left text</span>
<span id="mid">right text url#mail</span>
<span id="icons">...</span>
</footer>
</body>

How to use flex to align button with centered text but icon to one side? [duplicate]

I'm using flexbox to align my child elements. What I'd like to do is center one element and leave the other aligned to the very left. Normally I would just set the left element using margin-right: auto. The problem is that pushes the center element off center. Is this possible without using absolute positioning?
HTML & CSS
#parent {
align-items: center;
border: 1px solid black;
display: flex;
justify-content: center;
margin: 0 auto;
width: 500px;
}
#left {
margin-right: auto;
}
#center {
margin: auto;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
Add third empty element:
<div class="parent">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right"></div>
</div>
And the following style:
.parent {
display: flex;
}
.left, .right {
flex: 1;
}
Only left and right are set to grow and thanks to the facts that...
there are only two growing elements (doesn't matter if empty) and
that both get same widths (they'll evenly distribute the available space)
...center element will always be perfectly centered.
This is much better than accepted answer in my opinion because you do not have to copy left content to right and hide it to get same width for both sides, it just magically happens (flexbox is magical).
In action:
.parent {
display: flex;
}
.left,
.right {
flex: 1;
}
/* Styles for demonstration */
.parent {
padding: 5px;
border: 2px solid #000;
}
.left,
.right {
padding: 3px;
border: 2px solid red;
}
.center {
margin: 0 3px;
padding: 3px;
border: 2px solid blue;
}
<div class="parent">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right"></div>
</div>
EDIT: See Solo's answer below, it is the better solution.
The idea behind flexbox is to provide a framework for easily aligning elements with variable dimensions within a container. As such, it makes little sense to provide a layout where the width of one element is totally ignored. In essence, that is exactly what absolute positioning is for, as it takes the element out of the normal flow.
As far as I know, there is no nice way of doing this without using position: absolute;, so I would suggest using it... but If you REALLY don't want to, or can't use absolute positioning then I suppose you could use one of the following workarounds.
If you know the exact width of the "Left" div, then you could change justify-content to flex-start (left) and then align the "Center" div like this:
#center {
position: relative;
margin: auto;
left: -{half width of left div}px;
}
If you do not know the width, then you could duplicate "Left" on the right side, use justify-content: space-between;, and hide the new right element:
Just to be clear, this is really, really ugly... better to use absolute positioning than to duplicate content. :-)
#parent {
align-items: center;
border: 1px solid black;
display: flex;
justify-content: space-between;
margin: 0 auto;
width: 500px;
}
#right {
opacity: 0;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
<span id="right">Left</span>
</div>
.parent {
display: flex;
}
.left {
flex: 1;
}
.parent::after {
flex: 1;
content: '';
}
<div class="parent">
<div class="left">Left</div>
<div>Center</div>
</div>
I have another solution. In my opinion, Adding an empty block to the center element is fine but code-wise it bit ugly.
Since this is 4 years old I figured I'd update this with a much easier CSS Grid solution.
#parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
border: 1px solid black;
margin: 0 auto;
width: 500px;
}
#center {
text-align: center;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
If you don't want to rely on positioning, the only way I've found that makes it truly centered is to use a combination of auto margin and negative margin prevent the centered element to getting pushed over by the left aligned element. This requires that you know the exact width of the left aligned element though.
.container {
height: 100px;
border: solid 10px skyblue;
display: flex;
justify-content: center;
}
.block {
width: 120px;
background: tomato;
}
.justify-start {
margin-right: auto;
}
.justify-center {
margin-right: auto;
margin-left: -120px;
}
<div class="container">
<div class="block justify-start"></div>
<div class="block justify-center"></div>
</div>
As far as I know this is possible with the following code.
https://jsfiddle.net/u5gonp0a/
.box {
display: flex;
justify-content: center;
background-color: green;
text-align: left;
}
.left {
padding: 10px;
background-color: pink;
}
.center {
padding: 10px;
background-color: yellow;
margin: 0 auto;
}
<div class="box">
<div class="left">left</div>
<div class="center">center</div>
</div>
Try this no hacks :)
CSS
.container{
width: 500px;
margin: 0 auto;
}
.box{
display: flex;
align-items: center;/* just in case*/
justify-content: space-between;
}
.box p:nth-child(2){
text-align: center;
background-color: lime;
flex: 1 1 0px;
}
HTML
<div class="container">
<div class="box">
<p>One</p>
<p>Two</p>
</div>
</div>
http://codepen.io/whisher/pen/XpGaEZ
If you have a grid system you can use it to do what you want without "extra" css.
Below with bootstrap (V 4.X)
Note: It uses flex under the hood
<div class="row">
<div class="col text-left">left</col>
<div class="col text-center">center</col>
<div class="col text-right">right</col>
</div>
Doc bootstrap: https://getbootstrap.com/docs/4.6/layout/grid/
Et voilà ! :)
Solution 1: give 50% width to center element and use justify-content:space-between
#parent {
display: flex;
justify-content: space-between;
}
#center {
flex-basis: 50%;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
Solution 2: Add one dummy element and hide it.
#parent {
display: flex;
justify-content: space-between;
}
#right {
visibility:hidden;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
<span id="right">Right</span>
</div>

2 Inner divs - one should be center and not collide with the other [duplicate]

I'm using flexbox to align my child elements. What I'd like to do is center one element and leave the other aligned to the very left. Normally I would just set the left element using margin-right: auto. The problem is that pushes the center element off center. Is this possible without using absolute positioning?
HTML & CSS
#parent {
align-items: center;
border: 1px solid black;
display: flex;
justify-content: center;
margin: 0 auto;
width: 500px;
}
#left {
margin-right: auto;
}
#center {
margin: auto;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
Add third empty element:
<div class="parent">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right"></div>
</div>
And the following style:
.parent {
display: flex;
}
.left, .right {
flex: 1;
}
Only left and right are set to grow and thanks to the facts that...
there are only two growing elements (doesn't matter if empty) and
that both get same widths (they'll evenly distribute the available space)
...center element will always be perfectly centered.
This is much better than accepted answer in my opinion because you do not have to copy left content to right and hide it to get same width for both sides, it just magically happens (flexbox is magical).
In action:
.parent {
display: flex;
}
.left,
.right {
flex: 1;
}
/* Styles for demonstration */
.parent {
padding: 5px;
border: 2px solid #000;
}
.left,
.right {
padding: 3px;
border: 2px solid red;
}
.center {
margin: 0 3px;
padding: 3px;
border: 2px solid blue;
}
<div class="parent">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right"></div>
</div>
EDIT: See Solo's answer below, it is the better solution.
The idea behind flexbox is to provide a framework for easily aligning elements with variable dimensions within a container. As such, it makes little sense to provide a layout where the width of one element is totally ignored. In essence, that is exactly what absolute positioning is for, as it takes the element out of the normal flow.
As far as I know, there is no nice way of doing this without using position: absolute;, so I would suggest using it... but If you REALLY don't want to, or can't use absolute positioning then I suppose you could use one of the following workarounds.
If you know the exact width of the "Left" div, then you could change justify-content to flex-start (left) and then align the "Center" div like this:
#center {
position: relative;
margin: auto;
left: -{half width of left div}px;
}
If you do not know the width, then you could duplicate "Left" on the right side, use justify-content: space-between;, and hide the new right element:
Just to be clear, this is really, really ugly... better to use absolute positioning than to duplicate content. :-)
#parent {
align-items: center;
border: 1px solid black;
display: flex;
justify-content: space-between;
margin: 0 auto;
width: 500px;
}
#right {
opacity: 0;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
<span id="right">Left</span>
</div>
.parent {
display: flex;
}
.left {
flex: 1;
}
.parent::after {
flex: 1;
content: '';
}
<div class="parent">
<div class="left">Left</div>
<div>Center</div>
</div>
I have another solution. In my opinion, Adding an empty block to the center element is fine but code-wise it bit ugly.
Since this is 4 years old I figured I'd update this with a much easier CSS Grid solution.
#parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
border: 1px solid black;
margin: 0 auto;
width: 500px;
}
#center {
text-align: center;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
If you don't want to rely on positioning, the only way I've found that makes it truly centered is to use a combination of auto margin and negative margin prevent the centered element to getting pushed over by the left aligned element. This requires that you know the exact width of the left aligned element though.
.container {
height: 100px;
border: solid 10px skyblue;
display: flex;
justify-content: center;
}
.block {
width: 120px;
background: tomato;
}
.justify-start {
margin-right: auto;
}
.justify-center {
margin-right: auto;
margin-left: -120px;
}
<div class="container">
<div class="block justify-start"></div>
<div class="block justify-center"></div>
</div>
As far as I know this is possible with the following code.
https://jsfiddle.net/u5gonp0a/
.box {
display: flex;
justify-content: center;
background-color: green;
text-align: left;
}
.left {
padding: 10px;
background-color: pink;
}
.center {
padding: 10px;
background-color: yellow;
margin: 0 auto;
}
<div class="box">
<div class="left">left</div>
<div class="center">center</div>
</div>
Try this no hacks :)
CSS
.container{
width: 500px;
margin: 0 auto;
}
.box{
display: flex;
align-items: center;/* just in case*/
justify-content: space-between;
}
.box p:nth-child(2){
text-align: center;
background-color: lime;
flex: 1 1 0px;
}
HTML
<div class="container">
<div class="box">
<p>One</p>
<p>Two</p>
</div>
</div>
http://codepen.io/whisher/pen/XpGaEZ
If you have a grid system you can use it to do what you want without "extra" css.
Below with bootstrap (V 4.X)
Note: It uses flex under the hood
<div class="row">
<div class="col text-left">left</col>
<div class="col text-center">center</col>
<div class="col text-right">right</col>
</div>
Doc bootstrap: https://getbootstrap.com/docs/4.6/layout/grid/
Et voilà ! :)
Solution 1: give 50% width to center element and use justify-content:space-between
#parent {
display: flex;
justify-content: space-between;
}
#center {
flex-basis: 50%;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
</div>
Solution 2: Add one dummy element and hide it.
#parent {
display: flex;
justify-content: space-between;
}
#right {
visibility:hidden;
}
<div id="parent">
<span id="left">Left</span>
<span id="center">Center</span>
<span id="right">Right</span>
</div>

How to align content of a div to the bottom

Say I have the following CSS and HTML code:
#header {
height: 150px;
}
<div id="header">
<h1>Header title</h1>
Header content (one or multiple lines)
</div>
The header section is fixed height, but the header content may change.
I would like the content of the header to be vertically aligned to the bottom of the header section, so the last line of text "sticks" to the bottom of the header section.
So if there is only one line of text, it would be like:
-----------------------------
| Header title
|
|
|
| header content (resulting in one line)
-----------------------------
And if there were three lines:
-----------------------------
| Header title
|
| header content (which is so
| much stuff that it perfectly
| spans over three lines)
-----------------------------
How can this be done in CSS?
Relative+absolute positioning is your best bet:
#header {
position: relative;
min-height: 150px;
}
#header-content {
position: absolute;
bottom: 0;
left: 0;
}
#header, #header * {
background: rgba(40, 40, 100, 0.25);
}
<div id="header">
<h1>Title</h1>
<div id="header-content">And in the last place, where this might not be the case, they would be of long standing, would have taken deep root, and would not easily be extirpated. The scheme of revising the constitution, in order to correct recent breaches of it, as well as for other purposes, has been actually tried in one of the States.</div>
</div>
But you may run into issues with that. When I tried it I had problems with dropdown menus appearing below the content. It's just not pretty.
Honestly, for vertical centering issues and, well, any vertical alignment issues with the items aren't fixed height, it's easier just to use tables.
Example: Can you do this HTML layout without using tables?
If you're not worried about legacy browsers use a flexbox.
The parent element needs its display type set to flex
div.parent {
display: flex;
height: 100%;
}
Then you set the child element's align-self to flex-end.
span.child {
display: inline-block;
align-self: flex-end;
}
Here's the resource I used to learn:
http://css-tricks.com/snippets/css/a-guide-to-flexbox/
Use CSS positioning:
/* Creates a new stacking context on the header */
#header {
position: relative;
}
/* Positions header-content at the bottom of header's context */
#header-content {
position: absolute;
bottom: 0;
}
As cletus noted, you need identify the header-content to make this work.
<span id="header-content">some header content</span>
<div style="height:100%; position:relative;">
<div style="height:10%; position:absolute; bottom:0px;">bottom</div>
</div>
I use these properties and it works!
#header {
display: table-cell;
vertical-align: bottom;
}
After struggling with this same issue for some time, I finally figured out a solution that meets all of my requirements:
Does not require that I know the container's height.
Unlike relative+absolute solutions, the content doesn't float in its own layer (i.e., it embeds normally in the container div).
Works across browsers (IE8+).
Simple to implement.
The solution just takes one <div>, which I call the "aligner":
CSS
.bottom_aligner {
display: inline-block;
height: 100%;
vertical-align: bottom;
width: 0px;
}
html
<div class="bottom_aligner"></div>
... Your content here ...
This trick works by creating a tall, skinny div, which pushes the text baseline to the bottom of the container.
Here is a complete example that achieves what the OP was asking for. I've made the "bottom_aligner" thick and red for demonstration purposes only.
CSS:
.outer-container {
border: 2px solid black;
height: 175px;
width: 300px;
}
.top-section {
background: lightgreen;
height: 50%;
}
.bottom-section {
background: lightblue;
height: 50%;
margin: 8px;
}
.bottom-aligner {
display: inline-block;
height: 100%;
vertical-align: bottom;
width: 3px;
background: red;
}
.bottom-content {
display: inline-block;
}
.top-content {
padding: 8px;
}
HTML:
<body>
<div class="outer-container">
<div class="top-section">
This text
<br> is on top.
</div>
<div class="bottom-section">
<div class="bottom-aligner"></div>
<div class="bottom-content">
I like it here
<br> at the bottom.
</div>
</div>
</div>
</body>
The modern way to do it would be using flexbox. See the example below. You don't even need to wrap Some text... into any HTML tag, since text directly contained in a flex container is wrapped in an anonymous flex item.
header {
border: 1px solid blue;
height: 150px;
display: flex; /* defines flexbox */
flex-direction: column; /* top to bottom */
justify-content: space-between; /* first item at start, last at end */
}
h1 {
margin: 0;
}
<header>
<h1>Header title</h1>
Some text aligns to the bottom
</header>
If there is only some text and you want to align vertically to the bottom of the container.
section {
border: 1px solid blue;
height: 150px;
display: flex; /* defines flexbox */
align-items: flex-end; /* bottom of the box */
}
<section>Some text aligns to the bottom</section>
display: flex;
align-items: flex-end;
Inline or inline-block elements can be aligned to the bottom of block level elements if the line-height of the parent/block element is greater than that of the inline element.*
markup:
<h1 class="alignBtm"><span>I'm at the bottom</span></h1>
css:
h1.alignBtm {
line-height: 3em;
}
h1.alignBtm span {
line-height: 1.2em;
vertical-align: bottom;
}
*make sure you're in standards mode
I have encountered the problem several times and there are good solutions but also not so good ones. So you can achieve this in different ways with flexbox, with the grid system or display table. My preferred variant is a mix of flex and 'margin-bottom: auto'. Here is my personal collection of text-bottom possibilities:
1. Flex / margin-top: auto;
.parent {
min-height: 200px;
background: green;
display: flex;
}
.child {
margin-top: auto;
background: red;
padding:5px;
color:white;
}
<div class="parent">
<div class="child">Bottom text</div>
</div>
2. Flex / align-self: flex-end
.parent {
display: flex;
min-height: 200px;
background: green;
}
.child {
align-self: flex-end;
background: red;
padding: 5px;
color: white;
}
<div class="parent">
<div class="child">Bottom text</div>
</div>
3. Flex / align-items: flex-end;
.parent {
min-height: 200px;
background: green;
display: flex;
align-items: flex-end;
}
.child {
padding: 5px;
background: red;
color: white;
}
<div class="parent">
<div class="child">Bottom text</div>
</div>
4. Grid / align-self: end;
.parent {
min-height: 200px;
background: green;
display: grid;
}
.child {
align-self: end;
background: red;
padding:5px;
color:white;
}
<div class="parent">
<div class="child">Bottom text</div>
</div>
5. Table / vertical-align: bottom;
Personal I don't like this approach with table.
.parent {
min-height: 200px;
background: green;
display: table;
width:100%;
}
.child {
display: table-cell;
vertical-align: bottom;
background: red;
padding:5px;
color:white;
}
<div class="parent">
<div class="child">Bottom text</div>
</div>
With spacer
6. Flex; / flex: 1;
.parent {
min-height: 200px;
background: green;
display: flex;
flex-flow: column;
}
.spacer {
flex: 1;
}
.child {
padding: 5px;
background: red;
color: white;
}
<div class="parent">
<div class="spacer"></div>
<div class="child">Bottom text</div>
</div>
7. Flex / flex-grow: 1;
.parent {
min-height: 200px;
background: green;
display: flex;
flex-direction: column;
}
.spacer {
flex-grow: 1;
}
.child {
padding: 5px;
background: red;
color: white;
}
<div class="parent">
<div class="spacer"></div>
<div class="child">Bottom text</div>
</div>
8. Inline-block / PseudoClass::before
.parent {
min-height: 200px;
background: green;
}
.child::before {
display:inline-block;
content:'';
height: 100%;
vertical-align:bottom;
}
.child {
height:200px;
padding: 5px;
background: red;
color: white;
}
<div class="parent">
<div class="child">Bottom text</div>
</div>
❤️ My personal preferred versions are: 1., 2. and 3.
You can simply achieved flex
header {
border: 1px solid blue;
height: 150px;
display: flex; /* defines flexbox */
flex-direction: column; /* top to bottom */
justify-content: space-between; /* first item at start, last at end */
}
h1 {
margin: 0;
}
<header>
<h1>Header title</h1>
Some text aligns to the bottom
</header>
You can use following approach:
.header-parent {
height: 150px;
display: grid;
}
.header-content {
align-self: end;
}
<div class="header-parent">
<h1>Header title</h1>
<div class="header-content">
Header content
</div>
</div>
Here is another solution using flexbox but without using flex-end for bottom alignment. The idea is to set margin-bottom on h1 to auto to push the remaining content to the bottom:
#header {
height: 350px;
display:flex;
flex-direction:column;
border:1px solid;
}
#header h1 {
margin-bottom:auto;
}
<div id="header">
<h1>Header title</h1>
Header content (one or multiple lines) Header content (one or multiple lines)Header content (one or multiple lines) Header content (one or multiple lines)
</div>
We can also do the same with margin-top:auto on the text but in this case we need to wrap it inside a div or span:
#header {
height: 350px;
display:flex;
flex-direction:column;
border:1px solid;
}
#header span {
margin-top:auto;
}
<div id="header">
<h1>Header title</h1>
<span>Header content (one or multiple lines)</span>
</div>
If you have multiple, dynamic height items, use the CSS display values of table and table-cell:
HTML
<html>
<body>
<div class="valign bottom">
<div>
<div>my bottom aligned div 1</div>
<div>my bottom aligned div 2</div>
<div>my bottom aligned div 3</div>
</div>
</div>
</body>
</html>
CSS
html,
body {
width: 100%;
height: 100%;
}
.valign {
display: table;
width: 100%;
height: 100%;
}
.valign > div {
display: table-cell;
width: 100%;
height: 100%;
}
.valign.bottom > div {
vertical-align: bottom;
}
I've created a JSBin demo here: http://jsbin.com/INOnAkuF/2/edit
The demo also has an example how to vertically center align using the same technique.
The best possible solution to move a div to the bottom is as follows.
Basically what you need to do is to set display flex and flex-direction as a column to the parent and add a 'margin-top: auto' to its child which needs to be floated to the bottom of the container
Note: I have used bootstrap and its classes.
.box-wrapper {
height: 400px;
border: 1px solid #000;
margin: 20px;
display: flex; // added for representation purpose only. Bootstrap default class is already added
flex-direction: column;
}
.link-02 {
margin-top: auto;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css" rel="stylesheet" />
<div class="box-wrapper d-flex flex-column col-4">
<div>incidunt blanditiis debitis</div>
<div class="news-box">
<img class="d-block" alt="non ipsam nihil" src="https://via.placeholder.com/150">
<p>Labore consectetur doloribus qui ab et qui aut facere quos.</p>
</div>
<a href="https://oscar.com" target="_blank" class="link-02">
This is moved to bottom with minimal effort
</a>
</div>
All these answers and none worked for me... I'm no flexbox expert, but this was reasonably easy to figure out, it is simple and easy to understand and use. To separate something from the rest of the content, insert an empty div and let it grow to fill the space.
https://jsfiddle.net/8sfeLmgd/1/
.myContainer {
display: flex;
height: 250px;
flex-flow: column;
}
.filler {
flex: 1 1;
}
<div class="myContainer">
<div>Top</div>
<div class="filler"></div>
<div>Bottom</div>
</div>
This reacts as expected when the bottom content is not fixed sized also when the container is not fixed sized.
You don't need absolute+relative for this. It is very much possible using relative position for both container and data. This is how you do it.
Assume height of your data is going to be x. Your container is relative and footer is also relative. All you have to do is add to your data
bottom: -webkit-calc(-100% + x);
Your data will always be at the bottom of your container. Works even if you have container with dynamic height.
HTML will be like this
<div class="container">
<div class="data"></div>
</div>
CSS will be like this
.container{
height:400px;
width:600px;
border:1px solid red;
margin-top:50px;
margin-left:50px;
display:block;
}
.data{
width:100%;
height:40px;
position:relative;
float:left;
border:1px solid blue;
bottom: -webkit-calc(-100% + 40px);
bottom:calc(-100% + 40px);
}
Live example here
Hope this helps.
Here's the flexy way to do it. Of course, it's not supported by IE8, as the user needed 7 years ago. Depending on what you need to support, some of these can be done away with.
Still, it would be nice if there was a way to do this without an outer container, just have the text align itself within it's own self.
#header {
-webkit-box-align: end;
-webkit-align-items: flex-end;
-ms-flex-align: end;
align-items: flex-end;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
height: 150px;
}
a very simple, one-line solution, is to add line-heigth to the div, having in mind that all the div's text will go bottom.
CSS:
#layer{width:198px;
height:48px;
line-height:72px;
border:1px #000 solid}
#layer a{text-decoration:none;}
HTML:
<div id="layer">
text at div's bottom.
</div>
keep in mind that this is a practical and fast solution when you just want text inside div to go down, if you need to combine images and stuff, you will have to code a bit more complex and responsive CSS
An addition to the other flex-box solutions mentioned:
You can use flex-grow: 1 on the first div. This way, your second div will be aligned to the bottom while the first will cover all remaining space.
On the parent div, you must use display: flex and flex-direction: column.
/* parent-wrapper div */
.container {
display: flex;
flex-direction: column;
}
/* first-upper div */
.main {
flex-grow: 1;
}
Check fiddle: https://jsfiddle.net/1yj3ve05/
if you could set the height of the wrapping div of the content (#header-content as shown in other's reply), instead of the entire #header, maybe you can also try this approach:
HTML
<div id="header">
<h1>some title</h1>
<div id="header-content">
<span>
first line of header text<br>
second line of header text<br>
third, last line of header text
</span>
</div>
</div>
CSS
#header-content{
height:100px;
}
#header-content::before{
display:inline-block;
content:'';
height:100%;
vertical-align:bottom;
}
#header-content span{
display:inline-block;
}
show on codepen
I found this solution bassed on a default bootstrap start template
/* HTML */
<div class="content_wrapper">
<div class="content_floating">
<h2>HIS This is the header<br>
In Two Rows</h2>
<p>This is a description at the bottom too</p>
</div>
</div>
/* css */
.content_wrapper{
display: table;
width: 100%;
height: 100%; /* For at least Firefox */
min-height: 100%;
}
.content_floating{
display: table-cell;
vertical-align: bottom;
padding-bottom:80px;
}
#header {
height: 150px;
display:flex;
flex-direction:column;
}
.top{
flex: 1;
}
<div id="header">
<h1 class="top">Header title</h1>
Header content (one or multiple lines)
</div>
#header {
height: 250px;
display:flex;
flex-direction:column;
background-color:yellow;
}
.top{
flex: 1;
}
<div id="header">
<h1 class="top">Header title</h1>
Header content (one or multiple lines)
</div>
I have devised a way which is a lot simpler than what's been mentioned.
Set the height of the header div. Then inside that, style your H1 tag as follows:
float: left;
padding: 90px 10px 11px
I'm working on a site for a client, and the design requires the text to be at the bottom of a certain div. I've achieved the result using these two lines, and it works fine. Also, if the text does expand, the padding will still remain the same.
try with:
div.myclass { margin-top: 100%; }
try changing the % to fix it. Example: 120% or 90% ...etc.
The site I just did for a client requested that the footer text was a high box, with the text at the bottom I achieved this with simple padding, should work for all browsers.
<div id="footer">
some text here
</div>
#footer {
padding: 0 30px;
padding-top: 60px;
padding-bottom: 8px;
}
*{
margin:0;
}
div{
width:300px;
background:cornflowerblue;
color:#fff;
height:150px;
display:flex;
justify-content:space-between;
flex-direction:column;
}
<div>
<h4>Heading</h4>
<p>This is a paragraph</p>
<!-- <p> Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it</p> -->
</div>
Just simply use display:flex and flex-direction:column to make child sync in vertical order then apply justify-content:space-between to justify height of parent div with its children content. so that you can achieve your goal. Try this snippet to resolve issue.
I really appreciate your interest.
Seems to be working:
#content {
/* or just insert a number with "px" if you're fighting CSS without lesscss.org :) */
vertical-align: -#header_height + #content_height;
/* only need it if your content is <div>,
* if it is inline (e.g., <a>) will work without it */
display: inline-block;
}
Using less makes solving CSS puzzles much more like coding than like... I just love CSS. It's a real pleasure when you can change the whole layout (without breaking it :) just by changing one parameter.
A perfect cross-browser example is probably this one here:
http://www.csszengarden.com/?cssfile=/213/213.css&page=0
The idea is both to display the div at the bottom and also making it stick there. Often the simple approach will make the sticky div scroll up with the main content.
Following is a fully working minimal example. Note that there's no div embedding trickery required. The many BRs are just to force a scrollbar to appear:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<style>
* {
margin: 0;
padding: 0;
}
#floater {
background: yellow;
height: 200px;
width: 100%;
position: fixed;
bottom: 0px;
z-index: 5;
border-top: 2px solid gold;
}
</style>
</head>
<body>
<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/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<div id="floater"></div>
</body>
</html>
If you are wondering your code might not be working on IE, remember to add the DOCTYPE tag at the top. It's crucial for this to work on IE. Also, this should be the first tag and nothing should appear above it.
2015 solution
<div style='width:200px; height:60px; border:1px solid red;'>
<table width=100% height=100% cellspacing=0 cellpadding=0 border=0>
<tr><td valign=bottom>{$This_text_at_bottom}</td></tr>
</table>
</div>
http://codepen.io/anon/pen/qERMdx
your welcome