flex align-items center is not centering - html

I have a code - https://codepen.io/anon/pen/MQjpBG
It's a simple list with a colored block and text in each li
I need the list to be vertical and the text and block to be vertically aligned.
I'm trying to do this with flex and align-items but the text and block never center exactly
Am I doing something wrong, is there a better way to do this.
.element{
display: flex;
list-style: none;
&__item{
display: flex;
align-items: center;
margin-right: 10px;
&:last-of-type{
margin-right: 0;
}
&-square{
background: red;
//display: block;
display: inline-block;
height: 20px;
width: 20px;
}
&-text{
font-weight: bold;
}
}
}
I want the block and text to fit like so.
The align-items: center; seems to do it but its slightly off, like

There's nothing centering them (in your codepen).
Add this to your code:
.element{
display: flex;
justify-content: center; /* horizontal alignment */
.element__item {
display: flex; /* nested flex container */
align-items: center; /* vertical alignment */
}
revised codepen

Unfortunately, it looks like the issue is a function of the font chosen. Different fonts will have different descender heights (e.g. the tail of a "g") as well as different positioning of the base line relative to the full text box, and it appears that some fonts will have these values set such that they may not be visually centered.
I modified your CodePen example and forcibly set the font-family of the first element to Arial while leaving the second as the default (on Firefox on macOS 10.15/Catalina), and the Arial version definitely looks much more vertically centered:
You may be able to fix this by changing the font used, but obviously this isn't a change that can be made lightly on a large codebase.

To make the list to be vertical, just add "flex-direction"
display: flex;
list-style: none;
flex-direction: column;

For horizontally center aligned:
.element {
justify-content: center;
}
For vertical center alignment of squares and text:
.element__item-square {
vertical-align: middle;
}
.element__item-text {
vertical-align: middle;
}

Related

Display inline-flex preventing float right from working on span elements

mocked up an example of my issue (simplified) in this codepen: https://jsfiddle.net/bhuaL0vf/12/
I'm basically unsure of what styles on the styled-link are preventing the open-text from floating right to the end of the row - so that it sits right at the end as opposed to cosied up-beside it. I've re-created this elsewhere with these styles however inline-flex is not necessary there so I am assuming it is to do with that.
TEMPLATE:
<li class="styled-link">
<span class="open-text">Open</span>
List item one
</li>
STYLES:
.styled-link {
display: inline-flex;
align-items: center;
font-size: 12px;
color: #63666a;
}
.open-text {
float: right;
font-size: 14px;
display: block;
margin-right: 35px;
}
Apologies if I'm missing something really obvious, a little unfamiliar with inline-flex.
You can replace inline-flex with flex and justify the flex items using justify-content property to achieve the desired alignment as per your needs.
For example:
.styled-link {
display: flex; /* Replaced inline-flex to flex /*
align-items: center;
font-size: 12px;
color: #63666a;
justify-content: space-between; /* Add space between flex items */
}
/* Removed float */
.open-text {
font-size: 14px;
display: block;
margin-right: 35px;
}

Is it possible to shrinkwrap flex items with wrapping text inside them?

I have an unassuming nav menu:
<div>
<ul>
<li><span>Real Estate & Development</span></li>
<li><span>New & Expanding Business</span></li>
{ … }
</ul>
</div>
This menu needs the following visual properties:
Items distributed horizontally within their container by putting equal space between them
Text in items can wrap to make items take up less horizontal space
All text is vertically centered.
I can't get all three of these at the same time.
This SCSS:
div > ul {
display: flex;
justify-content: space-between;
> li {
display: table;
table-layout: fixed;
word-wrap: break-word;
> a {
display: table-cell;
text-align: center;
vertical-align: middle;
}
}
}
…gets me great spacing with vertical centering, but the text doesn't wrap, so the items overflow the container:
If I delete the display: table stuff:
div > ul {
display: flex;
justify-content: space-between;
> li {
// DELETED display: table;
// DELETED table-layout: fixed;
word-wrap: break-word;
> a {
display: table-cell;
text-align: center;
vertical-align: middle;
}
}
}
…then I get good text wrapping, but the spacing between the items is all off:
I've tried lots of other combinations of CSS properties, but nothing has gotten me any closer than these two. Here's a pen with my code. Is there any incantation that will get me all the things I want from this menu?
EDIT: My Pen now includes a third attempt that uses another Flex container instead of display: table-cell. The spacing is better, but still not great. I guess this may just come down to the text-wrapping width issue described in this answer, and I may just have to hard code some line breaks or use JavaScript.
EDIT 2: The thing about that, though, is that the items aren't maxing out at a set size. On my third attempt there, the ones that wrap and end up bigger than the width of the wrapped text do not end up the same size as each other. And in fact the space-between isn't doing much of anything, because the top-level flex items are filling the entire space; the space-between them is 0px.
Use flex instead of table-cell on the a elements, and then put width: min-content on the spans inside them:
div > ul {
display: flex;
justify-content: space-between;
> li > a {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
span {
width: min-content;
}
}
}
You might get more text wrapping than you bargained for this way, but you can control that with non-breaking spaces.
Text should already wrap automatically inside flex items. It is working for me with the following code:
SCSS:
ul {
padding: 0;
list-style: none;
display: flex;
background-color: grey;
height: 50px;
align-items: center;
justify-content: space-between;
li {
text-align: center;
flex: 1;
}
}
HTML:
<div>
<ul>
<li><span>Real Estate & Development</span></li>
<li><span>New & Expanding Business</span></li>
<li><span>New & Expanding Business</span></li>
</ul>
</div>
Fiddle
You can adjust spacing between items with justify-content:
.container {
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}
cssTricks page for Flexbox
You can make items take equal width by setting flex-basis: 0; flex-grow: 1; on the li elements.

Text inside a div positioned with flex linebreaks before and after certain tags

I have been searching around, but for the life of me I cannot figure out what's going on. My text is getting wrapped at certain tags, while I want it all on one line.
I have aligned three DIV elements next to each other through the use of display: flex;
This all works out quite nicely and display is exactly the way I want it. Except for the fact that, for some unexplicable reason (at least to me), if I put a text snippet in one of those divs and that text snippet contains something between tags like <span></span> or <b></b>, the text is automatically wrapped before and after the tag onto a new line.
I have the code here:
.pagetitlewrapper {
width: 99%;
background-color: #c1dbff;
border-radius: 25px 25px 0px 0px;
padding: 10px;
display: flex;
text-align: center;
}
.pagetitleleft,.pagetitlecenter,.pagetitleright {
width: 33%;
align-items: stretch;
display: flex;
justify-content: center;
flex-direction: column;
}
.pagetitleleft {
text-align: left;
font-size: 9;
}
.pagetitlecenter {
text-align: center;
}
.pagetitleright {
text-align: right;
font-size: 9;
resize: vertical;
}
<div class='pagetitlewrapper'>
<div class='pagetitleleft'>Welkom, FNAME LNAME</div>
<div class='pagetitlecenter'><h1>Nexus Consult DMS</h1></div>
<div class='pagetitleright'>
Licensed to <span>DON'T WRAP</span> - License valid until xx/xx/xxxx.
</div>
</div>
Around the DON'T WRAP, I have put <span> tags to illustrate the problem. If you remove these tags, the text is all displayed on one line as I want it. Basically I want to be able to make DON'T WRAP bold without it wrapping the text before and after.
I have been searching the web, to no avail. I found a couple of code snippets online which surprisingly did the same thing. I wonder why nobody ran into this problem before?
I have tried to play a bit with white-space: nowrap; in CSS, but that didn't seem to work either.
Anyone has any idea? Someone can point me in the right direction?
Thanks,
Kenneth
Why it break line is because of the display: flex; flex-direction: column on the pagetitleleft/center/right elements, which make the span a flex column item and take 100% width.
By dropping the display: flex on the pagetitleleft/center/right elements and set align-items: center to their parent, their text will center vertically
.pagetitlewrapper {
width: 99%;
background-color: #c1dbff;
border-radius: 25px 25px 0px 0px;
padding: 10px;
display: flex;
align-items: center;
}
.pagetitleleft,.pagetitlecenter,.pagetitleright {
width: 33%;
}
.pagetitleleft {
text-align: left;
font-size: 9;
}
.pagetitlecenter {
text-align: center;
}
.pagetitleright {
text-align: right;
font-size: 9;
resize: vertical;
}
<div class='pagetitlewrapper'>
<div class='pagetitleleft'>Welkom, FNAME LNAME</div>
<div class='pagetitlecenter'><h1>Nexus Consult DMS</h1></div>
<div class='pagetitleright'>
Licensed to <span>DON'T WRAP</span> - License valid until xx/xx/xxxx.
</div>
</div>
This behavior makes sense and is defined in the flexbox specification.
4. Flex Items
Each in-flow child of a flex container becomes a flex item, and each
contiguous run of text that is directly contained inside a flex
container is wrapped in an anonymous flex item.
Your right column (.pagetitleright) is a flex container with flex-direction: column:
.pagetitleleft,.pagetitlecenter,.pagetitleright {
width: 33%;
align-items: stretch;
display: flex;
justify-content: center;
flex-direction: column;
}
In this container, you have three flex items:
<anonymous-flex-item>Licensed to</anonymous-flex-item>
<span>Licensed to</span>
<anonymous-flex-item>- License valid until xx/xx/xxxx.</anonymous-flex-item>
As a result, you're getting three flex items stacked vertically.
It doesn't matter if you use span, b, strong, em. Whatever elements you create in the container become flex items and behave accordingly.
If you don't want these elements to stack vertically, then don't use flex-direction: column.
There is a simple solution. just add white-space: pre-wrap;
Some-Flex-Container {
display: flex;
white-space: pre-wrap; /* solution */
}

Align icon vertically to the center of the first line of text

Here are the eyes with align-items: center property. They are OK for one-line text and FAIL for multiline text:
Here are the eyes with align-items: baseline (or flex-start). They are better for multiline text but not ideal for all of them because I want to align the eye to the center of first line of the text:
What I’m trying to achieve is this:
See how the eye image is centered at the first line of the text?
Is it possible to do it elegantly with flexbox properties, without using padding or margin?
(This is a simplified example. In the real problem I don’t want to introduce padding because it will affect other items.)
Here is jsfiddle to play with: http://jsfiddle.net/sqp1wdap/
I found the solution: http://jsfiddle.net/sqp1wdap/3/
Align both Eye and Text to flex-start
Make line-height for text same as Eye height
Here is the edited code:
.LegendItem_Eye {
width: $slotWidth;
display: flex;
justify-content: center;
align-items: flex-start; // ← edit (1)
background: #eee;
}
.LegendItem_Text {
padding: 0 3px;
flex: 1;
align-self: flex-start; // ← edit (1)
background: #eaa;
line-height: $fontSize; // ← edit (2)
}
And here is how it looks like:
Of course, if the icon height equals the line height it will be 'aligned' to the first line.
Normally, those two things will be different. You can't actually change the line height or the icon height without impacting the visual design.
So the solution for this would be to wrap the icon with a flex container which height equals the text line-height. This container will do the vertical centering of the icon. If the icon is larger than the container then it will just overflow from top and bottom.
So in your example (I'm just exaggerating the height for clarity, you could also try with very smalls values, like 8px and see how it works in both scenarios)
.LegendItem_Eye {
width: $slotWidth;
display: flex;
justify-content: center;
align-items: center;
background: #eee;
height: 100px; /* <-- set this */
}
.LegendItem_Text {
padding: 0 3px;
flex: 1;
background: #eaa;
line-height: 100px; /* <-- equal to this, no need to set this, just use right value above */
}
Notice that you don't actually need to change the text line-height, just set the eye container height to whatever that value should be.
Fiddle working for cases in which line-height is bigger than icon: http://jsfiddle.net/ofdwemva/
Fiddle working for cases in which line-height is smaller than icon: http://jsfiddle.net/ofdwemva/1/
I found the solution without altering line-height property of the text.
Same like oluckyman's answer before, align both Eye and Text to flex-start.
Add hidden pseudo-element on Eye which resembles the height of the Text.
Use center alignment for the Eye which will aligns the Eye itself and the pseudo-element we've created.
Here is a link to JSFiddle and summary of what I did:
.LegendItem {
min-height: $itemHeight;
font-size: $fontSize;
margin: 2px 0;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: flex-start; // <-- Change this
}
.LegendItem_Eye {
width: $slotWidth;
display: flex;
justify-content: center;
align-items: center;
background: #bbb;
}
.LegendItem_Eye::before { // <-- Add this
content: "A";
width: 0px;
visibility: hidden;
}
.LegendItem_Text {
padding: 0 3px;
flex: 1;
background: #eaa; // <-- Remove align-self
}
And it will look like this.
A lot of the answers here are going to be depending on your situation - the current (and wrongly) accepted answer would only work if your designer does not mind that you butcher the line height which is no good for most.
If you want to do this ultimately your goal is to get the icons container to be the same height as one line of text and then align the icon within this container to be centered.
A decent method of doing this is by duplicating a bit of text with the same css as the text you want to be centered against then hiding it, This will ensure that the container is now the same height as the text. Now you simply center align the icon.
Heres an example in react (the css is the same)
export function CheckmarkListItem({ point }: Iprops) {
return (
<Div>
<IconContainer>
<SvgWrap size={20} mixin={svgMix}>
<Checkmark />
</SvgWrap>
<HiddenDiv>
<Typo tag="p">Mock text</Typo>
</HiddenDiv>
</IconContainer>
<PointDiv>
<Typo tag="p">{point}</Typo>
</PointDiv>
</Div>
);
}
const Div = styled.div`
display: flex;
text-align: left;
gap: 15px;
${(props) => props.theme.breakpoints.up.md} {
gap: 30px;
}
align-items: flex-start;
`;
const PointDiv = styled.div``;
const IconContainer = styled.div`
display: flex;
align-items: center;
`;
const svgMix = css`
margin: 0;
`;
const HiddenDiv = styled.div`
visibility: hidden;
width: 0;
`;
.LegendItem_Eye {
width: $slotWidth; // keep width
float:left; // float left
line-height:1.3; // define line height
}
That should be all you need. Demo.
I am not sure whether there is an elegant way to do it with flex but i can provide you a crack for the same and that will not affect any-other elements as far as i guess:
you can add custom styling for font-awesome.css
.fa{
position: absolute;
top: 0;
left: 0;
text-align:center;
padding:3px;
}
And for your custom style you can do this:
.LegendItem_Eye {
width: $slotWidth;
display: flex;
justify-content: center;
align-items: center;
background: #eee;
position: relative; /* Added this new rule */
}
I know this is not the proper solution but you can give this a try unless it harms other elements. :)
jSFiddle

HTML-CSS Center Text horizontally and vertically in a link

I am trying to make a link which has a height and a width of 200px.
The text of the link shall be centered vertically and horizontally.
This is my CSS so far:
a:link.Kachel {
width: 200px;
height: 200px;
margin: 0 auto;
display: block;
text-align: center;
background: #383838;
display: -webkit-box;
display: -moz-box;
display: box;
-webkit-box-align: center;
-moz-box-align: center;
box-align: center;
}
and this the HTML-code:
<tr>
<td>
<a class="Kachel" href="#">Test</a>
</td>
</tr>
The text is horizontally centered but not vertically.
Any idea how to get the text centered both horizontally and virtically?
remove everything else, and just replace height with line-height
a:link.Kachel{
width: 200px;
line-height: 200px;
display: block;
text-align: center;
background: #383838;
}
jsfiddle: http://jsfiddle.net/6jSFY/
In CSS3, you can achieve this with a flexbox without any extra elements.
.link {
display: flex;
justify-content: center;
align-items: center;
}
If the text is only on one line, you can use line-height:200px; - where the 200px is the same as the height value.
If the text is on multiple lines and will always be on the same number of multiple lines, you can use padding combined with line-height. Example with 2 lines:
line-height:20px;
padding-top:80px;
This way the two lines will take up a total of 40px and the padding top puts them perfectly in the middle. Note that you'd need to adjust the height accordingly.
JSFiddle example.
If there is more than one link and it will have any number of lines, you will need some accompanying JavaScript to fix the padding on each.
If the number of rows (or the inner element height) is not known, there is another trick using display: table and vertical-align:
.wrapper{
display: table;
}
.link{
display: table-cell;
vertical-align: middle;
}
Example
Full article with details
Small point to add. If you remove the underline (text-decoration: none;) then the text will not be perfectly centred vertically. Links leave space for the underline. To my knowledge there is no way to override this except to add little extra top padding.
Maybe using padding? Like:
padding-top: 50%;
In CSS3, you can try to use line-break with the justify text.
text-align: justify;
line-break: anywhere;