Center one element along with multiple siblings - html

I have a div with some number of spans in it, that may or may not be of equal width. I know I can use text-align: center to make all the content within a div be centered. However, I want to pick a particular span, and designate that as the true center, rather than the center being the midpoint of the sequence of spans.
One idea I had to simulate this effect was: I'd have my desired middle element with two containers to its left and right; the left one would be right-justified, and vice-versa. These containers would hold the other content in the div. If I could get these two containers to fill up the remaining space in equal amounts, this would have the effect of centering the middle element while keeping the left and right content aligned with the center. Basically, this would require the two containers' width to be set to exactly half the remaining space in the div. (I don't want to change the size of the middle div.) Is this possible to do with just CSS?
Example: with 4 spans, how to I designate span 2 as the true center?
div {
width: 500px;
padding: 4px;
border: 1px dotted black;
}
span {
display: inline-block;
width: 100px;
text-align: center;
margin: 4px;
box-sizing: border-box;
border: 1px dotted black;
}
#b {
/* ??? */
}
<div>
<span id="a">1</span>
<span id="b">2</span>
<span id="c">3</span>
<span id="d">4</span>
</div>

You can use flexbox. Based on this answer,
.outer-wrapper {
display: flex;
padding: 4px;
border: 1px dotted black;
}
.item {
margin: 4px;
text-align: center;
border: 1px dotted black;
}
.left.inner-wrapper, .right.inner-wrapper {
flex: 1;
display: flex;
align-items: flex-start;
min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.left.inner-wrapper {
justify-content: flex-end;
}
.animate {
animation: anim 5s infinite alternate;
}
#keyframes anim {
from { min-width: 0 }
to { min-width: 50vw; }
}
<div class="outer-wrapper">
<div class="left inner-wrapper">
<div class="item animate">1. Left</div>
</div>
<div class="center inner-wrapper">
<div class="item">2. Center</div>
</div>
<div class="right inner-wrapper">
<div class="item">3. Right</div>
<div class="item">4. Right</div>
</div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item animate">2. Center</div></div><div class="right inner-wrapper"><div class="item">3. Right</div><div class="item">4. Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item">2. Center</div></div><div class="right inner-wrapper"><div class="item animate">3. Right</div><div class="item">4. Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item">2. Center</div></div><div class="right inner-wrapper"><div class="item">3. Right</div><div class="item animate">4. Right</div></div></div>
This will attempt to center the desired element, but it will be pushed in case one side doesn't fit, to prevent overlapping.

This can be done using flexbox. You can use display:flex; on the div, and use flex-grow:1; on the 2nd span. That way you can cover the whole div with that span.
Since the 1st and 3rd spans are already equal in width, you'll have the 2nd span in dead center. And then use flex-basis on the 2nd to get it's desired width.
div.container{
width: 500px;
padding: 4px;
border: 1px dotted black;
}
div.row{
display:flex;
align-items:center;
justify-content:center;
}
span {
display: inline-block;
width: 70px;
text-align: center;
margin: 4px;
box-sizing: border-box;
border: 1px dotted black;
transform:translate(50%,0);
}
#b {
}
<html>
<head></head>
<body>
<div class='container'>
<div class="row">
<span id="a">1</span>
<span id="b">2</span>
<span id="c">3</span>
<span id="d">4</span>
</div>
</div>
</body>
</html>

I suggest to do it with a 3 column layout, and use CSS table structure. Make the 1st and 3rd columns to take 50% of total width, and middle column will have only 0, but it will recalculate the width to fit the content and remains center since it's in a table.
Also put white-space: nowrap; there in case there are multiple words inside, but remove it as needed if there is only one word or fixed width.
.container {
display: table;
border-collapse: collapse;
width: 100%;
}
.item {
display: table-cell;
vertical-align: top;
padding: 4px;
border: 1px solid grey;
}
.item-a {
width: 50%;
text-align: right;
}
.item-b {
text-align: center;
white-space: nowrap; /* remove as needed */
}
.item-c {
width: 50%;
}
.item span {
display: inline-block;
border: 1px solid red;
}
.item-b span {
padding: 0 50px; /* for demo only */
}
<div class="container">
<span class="item item-a">
<span>1</span>
</span>
<span class="item item-b">
<span>2</span>
</span>
<span class="item item-c">
<span>3</span>
<span>4</span>
</span>
</div>
jsFiddle

Related

Shift cells in a row upward while maintaining baseline alignment

Here is a table built with flexboxes. The cells in the row are aligned with the align-items: baseline property.
.data-row {
display: flex;
align-items: baseline;
border-top: 2px solid blue;
border-bottom: 2px solid blue;
font: bold 14px monospace;
min-height: 75px;
}
.data-row + .data-row {
border-top: none;
}
.data-cell {
padding: 30px 15px 15px;
}
.data-cell--text {
flex-grow: 1;
}
<div class="data-row">
<div class="data-cell">1111111</div>
<div class="data-cell data-cell--text">Usually one line is enough</div>
<div class="data-cell">1111111</div>
<div class="data-cell">1111111</div>
</div>
<div class="data-row">
<div class="data-cell">2222222</div>
<div class="data-cell data-cell--text">But sometimes too long text gets into some cell and goes to the next line</div>
<div class="data-cell">2222222</div>
<div class="data-cell">2222222</div>
</div>
When text in a cell has two lines or more, I would like the contents of all the cells in the row to rise closer to the top of the row, while maintaining their baseline alignment.
Can this be achieved?
The question was suggested by user #Kate B on Russian SO.
You can wrap the cells with data in two nested flexbox-blocks:
The inner flexbox aligns the cells with the text to their baseline.
And the outer flexbox aligns the indoor one with the center axis.
If a new line appears in the text of any cell, then this cell increases the height of the inner block, and it rises inside the outer one.
https://codepen.io/glebkema/pen/XWaZNEP?editors=1100
/* Heart of the matter */
.outer-row {
display: flex;
align-items: center;
}
.inner-row {
display: flex;
align-items: baseline;
flex-grow: 1;
}
/* Appearance */
.outer-row {
border-top: 2px solid blue;
border-bottom: 2px solid blue;
font: bold 14px monospace;
min-height: 72px;
}
.outer-row + .outer-row {
border-top: none;
}
.data-cell {
padding: 0 15px;
}
.data-cell--text {
flex-grow: 1;
}
<div class="outer-row">
<div class="inner-row">
<div class="data-cell">1111111</div>
<div class="data-cell data-cell--text">One line</div>
<div class="data-cell">1111111</div>
<div class="data-cell">1111111</div>
</div>
</div>
<div class="outer-row">
<div class="inner-row">
<div class="data-cell">2222222</div>
<div class="data-cell data-cell--text">Two <br>lines</div>
<div class="data-cell">2222222</div>
<div class="data-cell">2222222</div>
</div>
</div>
<div class="outer-row">
<div class="inner-row">
<div class="data-cell">3333333</div>
<div class="data-cell data-cell--text">And <br>three <br>lines</div>
<div class="data-cell">3333333</div>
<div class="data-cell">3333333</div>
</div>
</div>

Cannot align divs

I cannot align my inline-block div (which contains multiple equal divs in it) to the center, it positions itself to the bottom
Float, vertical allgnment
.oneline {
width: 220px;
height: 144px;
border: solid 2px #ccc;
display: inline-block;
margin-right: 50px;
margin-bottom: px;
}
<div style="float: right; margin-right:140px;">
<div class="oneline">
<img src="gold.png" align="left">
<pre>IV-III 12€
III-II 12€
II-I 12€
I-SERIES 15€
PLAT SERIES 9€
PL WIN 5€
</pre>
</div>
<p>2 MORE SAME DIVS</p>
<hr>
<p>3 MORE SAME DIVS</p>
</div>
</div>
I added a class .wrapper to the outer-most div and moved your inline styles over to CSS. Added a red border so you could see better...
Flexbox layout makes centering a row or column of content very easy. The display: flex property makes it a flexbox container, and makes all the direct child elements into flex items. The flex-direction makes it a column, row direction is default, and align-items nows controls the horizontal alignment (in row direction it controls vertical alignment).
display: flex;
flex-direction: column;
align-items: center;
Some things will change. For instance, the <hr> element now collapses, so I give it:
hr {
width: 100%;
}
.wrapper {
/* FLEXBOX */
display: flex;
flex-direction: column;
align-items: center;
/* so you can see better, remove this */
border: 1px solid red;
float: right;
margin-right:140px;
}
.oneline {
width: 220px;
height: 144px;
border: solid 2px #ccc;
display: inline-block;
}
hr {
width: 100%;
}
<div class="wrapper">
<div class="oneline">
<img src="gold.png" align="left">
<pre>IV-III 12€
III-II 12€
II-I 12€
I-SERIES 15€
PLAT SERIES 9€
PL WIN 5€
</pre>
</div>
<p>2 MORE SAME DIVS</p>
<hr>
<p>3 MORE SAME DIVS</p>
</div>

CSS Flexbox float elements [duplicate]

This question already has answers here:
Is it possible for flex items to align tightly to the items above them?
(5 answers)
Make a div span two rows in a grid
(2 answers)
Closed 5 years ago.
I'm trying to float two elements at the right of a "figure" element using flex but it end up floating just div1 at the right of figure and div2 is moved bellow, if I make div1 and div2 narrow enough, they are floated inline at the right of figure.
This is the CSS:
.container {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
Desired Result:
Actual Result:
How it works?
First, you make a flex-container (flexc in this case) and apply the display:flex property on it which aligns the elements by default in row alignment. If you want an element to preserve its dimensions set it to flex:0 0 auto; else you can make use of flex:1; which shrinks or grows as the browser is resized.
Then to align the contents in column (div1 and div2) you can just wrap then in a different container and since div isn't an inline container, and the flex property doesn't have any effect on any other than the direct children of the flex parent, they are aligned in seperate lines.
.flexc {
display: flex;
justify-content: flex-start;
}
#fig {
flex: 0 0 auto;
width: 200px;
height: 200px;
background: gray;
text-align: center;
color: white;
margin: 10px;
border: 2px solid black;
}
#d1,
#d2 {
width: 200px;
height: 50px;
background: purple;
text-align: center;
color: white;
margin: 10px;
border: 2px solid black;
}
<div class="flexc">
<div id="fig">Figure</div>
<div class="col">
<div id="d1">div1</div>
<div id="d2">div2</div>
</div>
</div>
Without altering the html:
.flexc {
display: flex;
flex-direction:column;
position:relative;
}
#fig {
flex: 0 0 auto;
width: 200px;
height: 200px;
background: gray;
text-align: center;
color: white;
margin: 10px;
border: 2px solid black;
}
#d1,
#d2 {
position:absolute;
left:250px;
width: 200px;
height: 50px;
background: purple;
text-align: center;
color: white;
margin: 10px;
border: 2px solid black;
}
#d2{
top:70px;
}
<div class="flexc">
<div id="fig">Figure</div>
<div id="d1">div1</div>
<div id="d2">div2</div>
</div>
Not sure what your HTML looks like, but display: flex is best used on the container wrapping all the elements you want aligned. Imagine it to be the largest box that you put smaller boxes inside.
Codepen example demonstrating this: https://codepen.io/corviday/pen/VyYdar
Following this hierarchy with .container as your largest box, since you want two columns, you can divide it further into two smaller boxes (.left in red and .right in blue in this case).
From there you would need to group div1/div2 together to float the way you'd like, and would be the items that fill the box .right.
You can use Bootstrap to resolve or put div1 and div2 in one div main to drop div main
Bootstrap exemple
<div class='container'>
<div class="col-md-12">
<div class="col-md-6">
1 text
</div>
<div class="col-md-6">
<div class="col-md-6">
2 text
</div>
<div class="col-md-6">
3 text
</div>
</div>
</div>
</div>
I think the best layout engine to use for your use case is hinted at in your description of the problem: Floats.
Here is a solution that doesn't require you to alter your html.
<div class="container">
<div class="medium-box">figure</div>
<div class="small-box">div 1</div>
<div class="small-box">div 2</div>
</div>
.container{
width: 500px;
}
.medium-box {
height: 200px;
width: 200px;
margin: 10px;
background: grey;
float:left
}
.small-box {
float:left;
height: 30px;
width: 200px;
background: blue;
margin: 10px;
}
https://codepen.io/stacyvlasits/pen/aVPZbY

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>