Center vertically a unknown height text in a unknown height div - css

I know this is a common issue, and I've already asked a similar one.
But I could not find the solution this time.
I am trying to vertically center a text which can have different height in a DIV which can have different height.
And I am trying to solve this only with CSS, without touching the HTML.
Example : http://jsfiddle.net/F8TtE/
<div id="test">
<div id="sumup">
<h1 class="titre">Title</h1>
<div id="date">hello guys</div>
</div>
</div>
My goal is to have the text centered vertically and horizontally whatever its size.

Here it is :
#test {
text-align:center;
}
#test::before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
#sumup {
display: inline-block;
vertical-align: middle;
}
#test {
height : 180px;
text-align:center;
background: yellow;
}
#sumup {
background-color: #123456;
}
#test:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
#sumup {
display: inline-block;
vertical-align: middle;
}
<div id="test">
<div id="sumup">
<h1 class="titre">Title</h1>
<div id="date">hello guys</div>
</div>
</div>
EDIT: It's now 2015 and thankfully the web changes. Assuming you don't support obsolete browsers, it's usually simpler and cleaner to vertically center elements with the Flex model.
#test {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#test {
height : 180px;
background: yellow;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#sumup {
background-color: #123456;
}
<div id="test">
<div id="sumup">
<h1 class="titre">Title</h1>
<div id="date">hello guys</div>
</div>
</div>

Here's another way using display:table-cell since I don't quite understand how dystroy's answer works.
#test {
width:100%;
height : 400px;
display:table;
}
#sumup {
width : 100%;
height : 100%;
background-color: #123456;
display:table-cell;
vertical-align:middle;
}
http://jsfiddle.net/F8TtE/3/

CSS with display solution:
#test {
display:table;
}
#sumup {
display:table-cell;
}
The Demo http://jsfiddle.net/F8TtE/7/

Related

Equal height columns, with defined aspect ratio, and vertically centered content?

I have equal height columns with centered content:
http://codepen.io/anon/pen/BzKwgE
<div class="cont">
<div class="item item-first">
<p>First</p>
</div>
<div class="item item-second">
<p>Second Second Second Second Second Second Second Second Second Second Second Second Second Second Second Second Second </p>
</div>
<div class="item item-third">
<p>Third</p>
</div>
</div>
* {
box-sizing: border-box;
}
.cont {
width: 70%;
display: table;
}
.item {
display: table-cell;
vertical-align: middle;
text-align: center;
padding: 20px;
width: 33%;
}
.item-first {
background: blue;
}
.item-second {
background: green;
}
.item-third {
background: blue;
}
This is working great. However I also need my columns to have a 16x9 aspect ratio. In rare cases there will be a lot of content, in which case its OK to change the aespect ratio.
Ive got this working below however it stops the content being vertically centered:
http://codepen.io/anon/pen/pbyWMj
* {
box-siing: border-box;
}
.cont {
width: 70%;
display: table;
}
.item {
display: table-cell;
vertical-align: middle;
text-align: center;
padding: 20px;
width: 33%;
}
.item:before {
padding-bottom: 56.25%; // 16:9 ratio
display: block;
content: '';
float: left;
width: 1px;
}
.item-first {
background: blue;
}
.item-second {
background: green;
}
.item-third {
background: blue;
}
I can see that this is happening due to the padding hack. Is there a way to have equal height columns, vertically centered content, and the 16x9 aspect ratio?
Im supporting IE9. Ideally it would look the same, but a usable fallback is also acceptable.
You can use inline-block and vertical-align on the elements inside each item. Try this:
.item {
display:table-cell;
vertical-align:middle;
text-align: center;
width: 33%;
}
.item:before {
padding-bottom: 56.25%;
display: inline-block;
content: '';
width: 0;
vertical-align:middle;
margin-right:-4px;
}
.item p {
display:inline-block;
vertical-align:middle;
padding:20px;
}
Codepen Update

Display table on flex item

My question is simple. Is it possible to have display: table on a flex item?
When I set it on an item, the layout doesn't work as expected - the second flex item doesn't grab the available vertical/horizontal space.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
display: table;
background-color: red;
}
.content > span {
display: table-cell;
vertical-align: middle;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Of course you can, but not necessarily a good solution though.
May I suggest you use flex all the way.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
background-color: red;
display: flex;
align-items: center;
justify-content: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Side note:
A table element is special and doesn't behave as normal block or inline elements. To make it work with display: table, you need to set a height to your parent as well as to the table, like in this sample, http://jsfiddle.net/LGSon/0bzewkf4.
Still, as you can see, the table height is 200px because flex has some flaws when it comes to limit height's, so it is not display:table that breaks your flex, it is flex who is somewhat broken.
Here is another answer of mine, showing yet another workaround where flex doesn't behave: Normalizing Flexbox overflow in IE11
It's a big question why you use table in flexbox...
But you can set width to your table and inherit min-height from parent
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
display: table;
flex:1;
background-color: red;
width:100%;
min-height:inherit;
}
.content > span {
display: table-cell;
vertical-align: middle;
height: 100%;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
You should not need to use a table layout at all here. Just add align-self: center; to .content- > span {.... And make the span element become a flex item as well, by adding display:flex to the .content element. The reason why the table layout is not working for you is because vertcal-align has no effect on the alignment of flex items. So mixing a flex-layout with a table-layout by changing the display property of a flex-item seems not to be a good idea, because you are loosing the flexibility of the flex-layout.
Properties not affecting flexible boxes
Because flexible boxes use a different layout algorithm, some properties do not make sense on a flex container:
column-* properties of the multiple column module have no effect on a flex item.
float and clear have no effect on a flex item. Using float causes the display property of the element to compute to block.
vertical-align has no effect on the alignment of flex items.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
display: flex;
background-color: red;
}
.content > span {
flex: 1;
align-self: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Tables are row or horizontally oriented so wouldn't you get weird results if placed within a flex-column? I changed everything to a good old block, they stack very well in a column flow--vertical harmony.
.content is dead center by using: position: relative; top: 50%; and translateY(360%); for vertical and text-align: center; for horizontal. Oh and of course turning that span into a useful block.
Changed the following:
.content {
flex: 1;
background-color: red;
}
.content > span {
display: block;
position: relative;
top: 50%;
transform: translateY(360%);
text-align: center;
}
I changed display: table to table-row is this what you wanted?
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
background-color: red;
}
.content > span {
display: block;
position: relative;
top: 50%;
transform: translateY(360%);
text-align: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>

Two dynamic CSS columns?

So, I have three divs:
<div class="takeremaining">
<div class="centeredcontent">
This is my centered content
</div>
</div>
<div class="dynamicallyallocated">
This is my dynamic content
</div>
I'd like the rightmost div dynamicallyallocated to be dynamically sized based on the content using display: inline-block; and the other div takeremaining to take the remaining space in the parent div. I've tried this with my css:
.takeremaining {
display: inline-block;
width: 100%;
float: left;
background-color: #0000ff;
}
.centeredcontent {
display: table;
margin: 0 auto;
background-color: #00ffff;
}
.dynamicallyallocated {
display: inline-block;
float: right;
background-color: #00ff00
}
but, as you can see by this JSFiddle demo, the div dynamicallyallocated is bumped beneath takeremaining. I believe this is because of width: 100%; in takeremaining, but I'm not sure how to give it a dynamic width based on the conditional width of dynamicallyallocated. What would you suggest?
Here is a solution for you.
.container {
display: table;
width: 100%;
}
.takeremaining {
display: table-cell;
width: 100%;
text-align: center;
background-color: #0000ff;
}
.centeredcontent {
display: inline-block;
background-color: #00ffff;
}
.dynamicallyallocated {
display: table-cell;
width: 0;
background-color: #00ff00;
white-space: nowrap
}
<div class="container">
<div class="takeremaining">
<div class="centeredcontent">
This is my centered content
</div>
</div>
<div class="dynamicallyallocated">
This is my dynamic content
</div>
</div>

How to add text after an h1 but keep the h1 centered

I have an H1, and a link that needs to go after it (actually an image link, but I'm using text in the example below to simplify the code)
What I would like is for the link to appear after the H1 on the same line, but for the H1 to remain centered in it's containing div.
Right now, the link displaces the header from center...
Here's what I have
<div id="container">
<h1>Hello World</h1> <a id="gear" href="/aaa">Long text so you can see the displacement</a>
</div>
#container {
width: 400px;
text-align: center;
background-color: pink;
}
#container h1 {
display: inline-block;
}
And a fiddle of the same thing: http://jsfiddle.net/7xzq60x4/
In pictures:
now:
****HEADER TEXTlink****
what I want:
******HEADER TEXTlink**
Thanks in advance
Is this what you want?
#container {
width: 400px;
text-align: center;
background-color: pink;
position: relative;
}
#container h1 {
display: inline-block;
}
#container span {
position: absolute;
right: -75px;
top: 65%;
}
<div id="container">
<h1>Hello World</h1><span><a id="gear" href="/aaa">Long text so you can see the displacement</a></span>
</div>
Fiddle: http://jsfiddle.net/7xzq60x4/2/
Something which you might like...
#container {
width: 400px;
text-align: center;
background-color: pink;
position: relative;
}
#container h1 {
display: inline-block;
}
#container span {
position: absolute;
right: 25px;
top: 35%;
}
<div id="container">
<h1>Hello World</h1><span><a id="gear" href="/aaa">Small Text</a></span>
</div>
you may use the flex property + a pseudo element : http://jsfiddle.net/7xzq60x4/8/
#container {
width: 400px;
text-align: center;
background-color: pink;
display:flex;
}
#container a {
text-align:left;
}
#container:before {
content:'';
}
#container h1 {
white-space:nowrap;/* if this is what you 'd like */
}
#container h1 , #container a, #container:before{
flex:1;
margin:auto;
}
<div id="container">
<h1>Hello World</h1> <a id="gear" href="/aaa">Long text so you can see the displacement</a>
</div>
or the table layout http://jsfiddle.net/7xzq60x4/9/
#container {
width: 400px;
text-align: center;
background-color: pink;
display:table;
table-layout:fixed;
}
#container a {
text-align:left;
}
#container:before {
content:'';
}
#container h1, #container a, #container:before {
display:table-cell;
vertical-align:middle;
}
<div id="container">
<h1>Hello World</h1> <a id="gear" href="/aaa">Long text so you can see the displacement</a>
</div>
If you're okay with using flexbox, this can be achieved quite easily. This will need a few prefixes for compliance with all browsers, and may not go back to support IE9.
#container {
/* Use flexbox. */
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
/* Tells flexbox to place all items on a single line. */
-ms-flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row;
/* Lastly tells flexbox to ensure all items are aligned on the center. */
align-items: center;
width: 400px;
text-align: center;
background-color: pink;
}
<div id="container">
<h1>Hello World</h1>
<a id="gear" href="/aaa">Long text so you can see the displacement</a>
</div>
For more information, try this quick guide.

How can I make a border-layout using css?

I want to create a border layout for a web-app, where there is a fixed size header, footer, a sidebar, and the main center content that expands to fill the remaining space.
Think of it like your browser, where the toolbars and status-bar have a fixed size, the sidebar can change size, but the website in the center expands to fill the remaining size.
To clarify, I want to specify the height of the entire design in pixels, for example 600px. Then I want the sidebar and the center <div> tags to expand down to fill the space available, even if their contents aren't large enough to fill the space.
The web-browser analogy can be used here too. Even if the page you are looking at in the browser isn't taller than the browser window, the browser doesn't resize.
Is there any way to do this with CSS?
div { border : 1px solid #d3d3e3 }
#north { margin:0; padding:1em; }
#south { margin:0; padding:1em; }
#east { margin:0; padding:1em; width:6em; height:22em; float:left; margin-right:1.1em }
#west { margin:0; padding:1em; width:6em; height:22em; float:right; margin-left:1.1em }
#center { margin:0; padding:1em; padding-bottom:0em; }
#center:after { content:' '; clear:both; display:block; height:0; overflow:hidden }
<div id="north">North</div >
<div id="east">East</div>
<div id="west">West</div>
<div id="center">Center</div>
<div id="south">South</div>
Live link: http://jsfiddle.net/marrok/dGw6K/2/
The CSS table layout can handle this nicely.
.borderLayout {
display: table;
width: 100%
}
.borderLayout .top {
display: table-row;
}
.borderLayout .left {
display: table-cell;
vertical-align: middle;
width: 10%;
}
.borderLayout .center {
display: table-cell;
vertical-align: middle;
}
.borderLayout .right {
display: table-cell;
vertical-align: middle;
width: 10%;
}
.borderLayout .bottom {
display: table-row;
}
JSFiddle
I couldn't manage to find an answer to this question that worked for me, so I tried various attempts. This is a simple solution I managed to put together using flexbox.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
/*div { border : 1px solid #d3d3e3 }*/
html { height: 100%; }
body { height: 100%; }
.borderLayout {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
width: 100%;
height: 100%;
}
.borderLayout .top {
width: 100%;
}
.borderLayout .middle {
flex-grow: 1;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
width: 100%;
}
.borderLayout .middle .side {
}
.borderLayout .middle .center {
vertical-align: middle;
flex-grow: 1;
}
.borderLayout .bottom {
width: 100%;
}
</style>
</head>
<body>
<div class="borderLayout" style="width: 100%; height: 100%; background-color: cyan;" >
<div class="top" id="north" style="height: 150px; background-color: red;">North</div >
<div class="middle" style="background-color: magenta;" >
<div class="side borderLayout" id="west" style="width: 10%; background-color: yellow;">
<div class="top" style="height: 100px; background-color: #FF8000;">West 1</div>
<div class="middle">West 2</div>
<div class="bottom" style="height: 75px; background-color: #FF8080;">West 3</div>
</div>
<div class="center" id="center" style="background-color: white;">Center</div>
<div class="side" id="east" style="width: 20%; background-color: green;">East</div>
</div>
<div class="bottom" id="south" style="height: 50px; background-color: blue;">South</div>
</div>
</body>
</html>
The method you refer to sounds like a job for footer stick - this is old already, but works a charm still ... the man in blue - footerStickAlt
Similar question here.
And I'm sure if you use the same criteria in that question and the question linked in that to run a search, you'll come up with more.
try flexbox, works with firefox and webkit
http://www.html5rocks.com/en/tutorials/flexbox/quick/
the current implementation is not updated, but it is good enough
but you can probably do this with tables (that are similar to the flexbox)
hope this helps

Resources