Text not centered with justify-content: center - html

I've got a div with display: flex. Its content is centered horizontally and vertically.
When content is too long in the div, the content wraps. But the alignment is broken in this case. See the snippet.
If I add text-align: center it displays correctly. But why doesn't it center without text-align: center?
.box{
width: 100px;
height: 100px;
background-color: lightgreen;
margin: 10px;
}
.flex{
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
.with-align{
text-align: center;
}
<div class="box flex">
some long text here
</div>
<div class="box flex with-align">
some long text here
</div>

The HTML structure of a flex container has three levels:
the container
the item
the content
Each level represents a separate, independent element.
The justify-content property, which is set on flex containers, controls flex items. It has no direct control over the children of the item (the text, in this case).
When you set justify-content: center on a row-direction container the item shrinks to the content width (i.e., shrink-to-fit) and is horizontally centered. The content, being inside the item, goes along for the ride.
Everything is centered nicely, when the content is narrower than the flex container.
On the other hand, when the content is wider than the flex container, the flex item can no longer be centered. In fact, the item cannot be aligned at all (start, end, center) because there is no free space – the item is consuming the full width of the container.
In such cases, the text can wrap. But justify-content: center doesn't apply to the text. It never did. The text was always subject to the default text-align: start (left in LTR / right in RTL).
Therefore, to center the text directly, add text-align: center to the flex item (or the flex container, it doesn't really matter due to inheritance).
article {
display: flex;
align-items: center;
justify-content: center;
}
.center {
text-align: center;
}
/* demo styles only */
article {
width: 100px;
height: 100px;
margin: 10px;
background-color: lightgreen;
}
<article>
<p>some long text here</p>
</article>
<article>
<p class="center">some long text here</p>
</article>

Related

How to fit CSS flex contents within its width? [duplicate]

This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
How to hide overflowing content in CSS?
(3 answers)
Closed 1 year ago.
I have 3 DIV components where:
.child-left: aligns its contents to the left on the screen
.child-center: aligns its contents to the center on the screen
.child-right: aligns its contents to the right on the screen
However, when the contents (or text) get really long in .child-center, the contents overflow each other even though it has its own width. Please see the below screenshot:
I'd like to know:
Why the content (Long text...) in .child-center does not fit within the width?
How do I fix the issue with the minimal changes? (I'd like to keep using display: flex, I DO NOT want to use text-align: center)
What I want to achieve is this:
Please help me out!
Code:
.parent {
display: flex;
align-items: center;
width: 100%;
}
.child-left {
display: flex;
justify-content: flex-start;
width: 20%;
background-color: green;
white-space: nowrap;
}
.child-center {
display: flex;
justify-content: center;
width: 60%;
background-color: red;
white-space: nowrap;
}
.child-right {
display: flex;
justify-content: flex-end;
width: 20%;
background-color: yellow;
white-space: nowrap;
}
<div class="parent">
<div class="child-left">
<span>11111111111111111111111111</span>
</div>
<div class="child-center">
<span>Long text Long text Long text Long text Long text Long text Long text Long text Long text</span>
</div>
<div class="child-right">
<span>22222222222222222222222222</span>
</div>
</div>

Using flex, one element centrally aligned and others spaced between the centre and right

I'm having a bit of trouble to produce the below with flex box. I'd like a centrally aligned "title" with some buttons to the right (2,3,4).
The code below gets me close, but it's not perfectly aligned and loses it when the window resizes.
Any suggestions?
.header {
display: flex;
height: 50px;
align-items: center;
justify-content: center;
}
.title {
width: 250px;
margin-left: auto;
margin-right: 15%;
}
.btn-group {
margin-right: 15%;
}
<div class="header">
<h1 class="title"></h1>
<div class="btn-group">
<button id="btn_1" class="selected">2</button>
<button id="btn_2">3</button>
<button id="btn_3">4</button>
</div>
</div>
Here's a clean and simple process to get you to your layout:
First, note that CSS pseudo-elements (i.e., ::before and ::after), when applied to flex containers, are treated as flex items.
Create a pseudo-element to serve as the first flex item in the container.
Make the pseudo consume all available space (i.e., set it to flex: 1)
Do the same with your button group (.btn-group) on the opposite end (i.e., set it to flex: 1)
Now, with the outer items pressuring from both sides, the title is pinned to the middle of the container.
Make the button group container a flex container.
Set that container to justify-content: center.
Now, the individual buttons are horizontally centered on the right side of the already centered title.
.header {
display: flex;
height: 50px;
align-items: center;
}
.header::before {
content: "";
flex: 1;
}
.btn-group {
flex: 1;
display: flex;
justify-content: center;
}
<div class="header">
<h1 class="title">1</h1>
<div class="btn-group">
<button id="btn_1" class="selected">2</button>
<button id="btn_2">3</button>
<button id="btn_3">4</button>
</div>
</div>
To better understand the concepts and methodology at work here, see this post:
Center and right align flexbox elements
Here are my suggestions when using flexbox layout. You do not need to set the width on the element because the width will resize dynamically. When you set display as flex in the container, the x-axis would change to row by default then use flex property for 'title' class to expand the width to double the width of 'btn-group'. As the result, the second div will push all the way to the right and you can add the width of margin-right as how much you want it to be. Also, I would create another div after header and give it a class name as 'title' instead of giving it on h1. That way you would have two children that allow you to control it. See below how I fixed it:
h1 {
text-align: center;
}
.header {
border: 1px solid red;
display: flex;
align-items: center;
justify-content: center;
}
.title {
flex: 1;
}
<div class="header">
<div class="title">
<h1>This is a title</h1>
</div>
<div class="btn-group">
<button id="btn_1" class="selected">2</button>
<button id="btn_2">3</button>
<button id="btn_3">4</button>
</div>
</div>

Why does property align-content:flex-end; have effect on displaying items when there are not multiple lines of items?

#flex-container {
height: 200px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
align-content: flex-end;
border: 2px solid;
}
#first-box {
background-color: gray;
width: 200px;
margin: 5px;
}
#second-box {
background-color: aqua;
width: 200px;
margin: 5px;
}
<div id="flex-container">
<div id="first-box">Box 1 </div>
<div id="second-box">Box 2</div>
</div>
Rule is: There must be multiple lines of items for this property to have any effect!
Why then have effect on displaying when there are not multiple lines of items?
Those two boxes should be centered on browser but there are on the bottom.
Rule is: There must be multiple lines of items for this property to have any effect!
The rule isn't exactly like that. There must be a multi-line flex container and this is not defined by the number of lines but by the flex-wrap property.
Read the below until the end to get the full explanation
From the specification:
The align-content property aligns a flex container’s lines within the flex container when there is extra space in the cross-axis .. Note, this property has no effect on a single-line flex container1.
and
Initial: stretch
So by default your one line is stretched to fill all the available space and the content is centred inside. If you select flex-end, your line will fit its content and will be placed at the bottom. The content is still centred inside but since the height is now defined by the content, the vertical centring is useless.
The trick here is to understand that centring in flexbox happen inside a line and not the container but in most of the case that line is stretched to fit the container height2. By changing align-content and flex-wrap it's no more the case.
flex-end
Lines are packed toward the end of the flex container. The cross-end edge of the last line is placed flush with the cross-end edge of the flex container, and each preceding line is placed flush with the subsequent line.
stretch
Lines stretch to take up the remaining space. If the leftover free-space is negative, this value is identical to flex-start. Otherwise, the free-space is split equally between all of the lines, increasing their cross size.
Some examples to better illustrate. The pink and yellow coloration represent the flexbox lines.
.box {
display: inline-flex;
vertical-align: top;
width: 100px;
height: 100px;
border: 1px solid;
align-items: center;
flex-wrap: wrap;
}
span {
width: 100%;
height: 10px;
margin: 5px;
background: red;
}
<div class="box" style="background:yellow;">
<span></span>
</div>
<div class="box" style="background:linear-gradient(yellow 50%,pink 50%);">
<span></span>
<span></span>
</div>
<div class="box" style="align-content:flex-end">
<span style="box-shadow:0 0 0 5px yellow"></span>
</div>
<div class="box" style="align-content:flex-end">
<span style="box-shadow:0 0 0 5px yellow"></span>
<span style="box-shadow:0 0 0 5px pink"></span>
</div>
1Now the tricky part is the use of flex-wrap
A single-line flex container (i.e. one with flex-wrap: nowrap) lays out all of its children in a single line, even if that would cause its contents to overflow.
A multi-line flex container (i.e. one with flex-wrap: wrap or flex-wrap: wrap-reverse) breaks its flex items across multiple lines, ...
If you specify wrap as flex-wrap, it's no more considered as single-line even if there is only one line thus align-content apply like described above.
If you keep it nowrap then nothing will happen because it's a single-line flexbox container and by default that line is always stretched to fill the space:
.box {
display: inline-flex;
vertical-align: top;
width: 100px;
height: 100px;
border: 1px solid;
align-items: center;
}
span {
width: 100%;
height: 10px;
margin: 5px;
background: red;
}
<div class="box" >
<span></span>
</div>
<div class="box" >
<span></span>
<span></span>
</div>
<div class="box" style="align-content:flex-end">
<span ></span>
</div>
<div class="box" style="align-content:flex-end">
<span ></span>
<span ></span>
</div>
2Note: Only multi-line flex containers ever have free space in the cross-axis for lines to be aligned in, because in a single-line flex container the sole line automatically stretches to fill the space.
If you go to the "try it" page for "CSS align-content Property" at w3schools.com you can insert your CSS and see exactly what it does. As far as I can see it is acting as expected and as Temani explains. You can also tweak the code until it does what you actually want.

Centered content is cut out of parent with fixed height and scrollbar

I have a parent with overflow-y and a fixed height. I wish to center align its child. The content of the child can vary in size, and sometimes it overflows the parent and triggers a scrollbar. In those cases, the top and bottom content of the child is cut out.
I wish the child to be center aligned, but only if it's smaller than the parent. Or it could always be center aligned, but then the content shouldn't be cut out.
Check out the problem here: https://jsfiddle.net/gumy023z/
.parent {
background-color: red;
height: 40px;
overflow-y: scroll;
/* Comment out the flex, and all the content will be available */
display: flex;
justify-content: center;
align-items: center;
}
<div class="parent">
<div class="child">
This is a test <br> This is a test <br> This is a test
</div>
</div>
The alignment will work in the flex axis of a flexbox. So you can switch to a column flexbox and give min-height: 0 (which overrides the default min-width: auto setting for a flex item) for the child element - see demo below:
.parent {
background-color: red;
height: 40px;
overflow-y: auto;
display: flex;
flex-direction: column; /* ADDED */
justify-content: center;
align-items: center;
}
.child {
min-height: 0; /* ADDED */
}
<div class="parent">
<div class="child">
1. This is a test <br> 2. This is a test <br> 3. This is a test
</div>
</div>

Center a flex item when its siblings have different widths [duplicate]

This question already has answers here:
Keep the middle item centered when side items have different widths
(12 answers)
Closed 5 years ago.
I know flexbox offers a great solution for centering items. But I run into an issue when I have 3 items and I'd like the center (2nd) item to be centered with respect to the window, regardless of the size of the other 2 items.
In my pen you can see the second item "Client Index" is off-center because the content on the right is larger than the content on the left. How can I force it to center itself?
.flex {
display: flex;
align-items: center;
justify-content: space-between;
}
<div class="flex">
<span style="font-size:12px;">small</span>
<span style="font-size:20px;">Client Index</span>
<span style="font-size:18px;">Lots of content that moves the center</span>
</div>
My Codepen
One way would be to set flex-grow: 1; flex-basis: 0 so the 3 columns are distributed evenly, then you can center the text or the content in the middle one.
I'm using text-align to center the middle column. You could also use display: flex; justify-content: center; to do the same thing.
.flex {
display: flex;
align-items: center;
justify-content: space-between;
}
.flex > span {
flex: 1 0 0;
}
.flex > span:nth-child(2) {
text-align: center;
}
<div class="flex">
<span style="font-size:12px;">small</span>
<span style="font-size:20px;">Client Index</span>
<span style="font-size:18px;">Lots of content that moves the center</span>
</div>
Use nested flex containers and auto margins.
.flex-container {
display: flex;
}
.flex-item {
flex: 1;
display: flex;
justify-content: center;
}
.flex-item:first-child>span {
margin-right: auto;
}
.flex-item:last-child>span {
margin-left: auto;
}
/* non-essential */
.flex-item {
align-items: center;
border: 1px solid #ccc;
background-color: lightgreen;
height: 40px;
}
<div class="flex-container">
<div class="flex-item"><span>short</span></div>
<div class="flex-item"><span>medium</span></div>
<div class="flex-item"><span>lonnnnnnnnnnnnnnnnnnnng</span></div>
</div>
Here's how it works:
The top-level div is a flex container.
Each child div is now a flex item.
Each item is given flex: 1 in order to distribute container space equally.
Now the items are consuming all space in the row and are equal width.
Make each item a (nested) flex container and add justify-content: center.
Now each span element is a centered flex item.
Use flex auto margins to shift the outer spans left and right.
You could also forgo justify-content and use auto margins exclusively.
But justify-content can work here because auto margins always have priority. From the spec:
8.1. Aligning with auto
margins
Prior to alignment via justify-content and align-self, any
positive free space is distributed to auto margins in that dimension.