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

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.

Related

flex align-items center is not centering

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;
}

Css flex - one item on the right, the other centered on the left space

I'm new to css and even newer to flex.
I couldn't find an answer, so I started a new one..
I have the following container and item:
.container {
display: flex;
justify-content: space-between;
align-items: center;
}
.item {
color: rgb(51, 51, 51);
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
This way I get 2 items on both sides (one left and one right).
I would like to know how to do the following:
The left item, will be on the left as before. From the point it ends, to the point the container ends - I with the right element to be centered.
The left item, will be on the left as before. The right item will be 10px left from the right end of the container.
Thanks!
The solution to this problem is using nested flexboxes. Get rid of the display: block; on .item - you can't mix flex and block display rules like that.
What you want to do is set up series of containers:
one top level flex container
two equally sized flex containers inside of the the top level container
Markup will look like this:
<main class="container">
<section class="left-container">
<div class="item"></div>
</section>
<section class="right-container">
<div class="item"></div>
</section>
</main>
In the CSS layer, you give the top-level .container flex and then justify-content: space-between which pushes the containers to the sides.
.container {
display: flex;
justify-content: space-between;
}
In the two nested containers, you need to make them both display: flex; as well. Now you can control the positioning of your .item elements like you want. align-items: center controls the vertical axis so .left-container gets only that positioning while the right container gets justify-content: center; to control the vertical alignment.
.left-container {
background-color: darkgray;
display: flex;
align-items: center;
height: 200px;
width: 50%;
}
.right-container {
background-color: lightgray;
display: flex;
align-items: center;
justify-content: center;
height: 200px;
width: 50%;
}
Styling on the item is pretty simple - I just gave height and width for demo purposes. They aren't necessary. If you want to do precise tweaks, use margin on .item to push slightly from these standards.
.item {
background-color: red;
height: 100px;
width: 100px;
}
Codepen:
https://codepen.io/staypuftman/pen/PmLyNM

How can I align text in the same tag differently?

So I have some text in-between an h2 tag, and I basically want to have the entire h2 tag centered on the page. But I also want to have some text on a second line, that is aligned to the right.
So it would look something like this:
You can use CSS flexbox for a clean and simple solution.
main { /* 1 */
display: flex;
justify-content: center;
}
h2 {
display: inline-flex; /* 2 */
flex-direction: column;
align-items: center;
margin: 0;
}
h2>span {
margin-left: auto; /* 3 */
}
<main>
<h2>
WebsiteName<span>.com</span>
</h2>
</main>
Notes:
Block level container; gives h2 the space to be horizontally centered.
Make h2 an inline-level container, so the box is only as wide as the content. This allows the first and second lines to align right.
Align second line to the right.
Alternative method, using absolute positioning, based on feedback in the comments:
h2 {
display: inline-flex;
flex-direction: column;
align-items: center;
margin: 0;
position: absolute;
left: 50%;
transform: translateX(-50%);
}
h2>span {
margin-left: auto;
}
<h2>
WebsiteName<span>.com</span>
</h2>
You can try the tag or the float property with the defined class.
by adding the following syntax:
.class_name tag_name

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 */
}

How can I make text right justified in a HTML element with display: flex?

I have the following HTML:
<div class="outer">
<div class="inner1">Hello</div>
<div class="inner2">World</div>
</div>
With the following CSS:
.outer {
display: flex;
}
.inner1 {
display: flex;
width: 5em;
text-align: right;
}
.inner2 {
display: flex;
width: 5em
}
I would like the text inside the inner1 class to be right justified. I thought the text-align: right would cause this to happen, but it does not.
How can I modify the above HTML and CSS to make the inner1 text, "Hello", be right justified? Why does having display: flex affect this behavior?
You were almost there. You just needed to add the justify-content property.
Add one line of code to your CSS:
.inner1 {
display: flex;
width: 5em;
/* text-align: right; REMOVE; not necessary */
justify-content: flex-end; /* NEW */
}
DEMO: http://jsfiddle.net/5qLdnk5p/1/
Here's a slightly enhanced demo to make the feature more noticeable:
DEMO: http://jsfiddle.net/5qLdnk5p/
From the spec:
justify-content
The justify-content property aligns flex items along the main axis
of the current line of the flex container.
flex-end
Flex items are packed toward the end of the line.
UPDATE
From the comment section:
This is working for me. The only confusion for me is that it says that
justify-content aligns flex-items. Since when is the content (text)
itself considered a flex item? Moreover, is the .inner1 div considered
a flex item, and will the entire div be moved around along the axis
too? – #mareoraft
The inline content in a flex container gets wrapped in an anonymous flex item, which is able to inherit properties from the parent. However, anonymous items (like anonymous block and anonymous inline boxes) are unselectable and therefore unstyleable. So if you want to apply styles to the text consider wrapping it in a <span>, <div> or other element.
The div with class .inner1, as a child of the flex container (.outer), is a flex item. All flex item properties apply. .inner1 also doubles as a (nested) flex container, so all flex container properties apply, as well.
How can I modify the above HTML and CSS to make the inner1 text, "Hello", be right justified?
I know it's a simple example, but check if the following suits your needs:
.wrapper {
border: 1px solid #000;
display: flex;
padding: 2px;
width: 100%;
}
.wrapper > div {
border: 1px solid #000;
flex: 1;
padding: 10px;
}
.left {
text-align: right;
}
.right {
text-align: left;
}
<div class="wrapper">
<div class="left">left (right aligned)</div>
<div class="right">right (left aligned)</div>
</div>
I recommend reading more about the flex property in A Complete Guide to Flexbox
Another method would be setting the following CSS:
Set the text aligning property to: text-align: justify and setting the read direction to: direction:rtl. Other answers are also very good answers.
These adjustments are CSS2 based.
.outer {
display: flex;
}
.inner1 {
display: flex;
width: 5em;
direction:rtl;
text-align:justify;
}
.inner2 {
display: flex;
width: 5em;
}
<div class="outer">
<div class="inner1">Hello</div>
<div class="inner2">World</div>
</div>