Align flex-box items to baseline of last text line in a block - css

I am trying to achive the last example on the following image, using flex-box.
From what I see, the align-items: baseline; property works great when the blocks only have 1 line.
The property align-items: flex-end; creates some issues mainly because the left and right items have different font-sizes and line-heights. Although the edges of the items are aligned, the white space created by the font size and line-height differences looks really bad when the item has no borders.
I'm trying to find a good all-around solution without any JS.
Thanks in advance.

You can wrap the contents of the flex items inside inline-block wrappers:
.flex {
display: flex;
align-items: baseline;
}
.inline-block {
display: inline-block;
}
.item { border: 1px solid red; }
.item:first-child { font-size: 200%; }
.flex::after { content: ''; position: absolute; left: 0; right: 0; border-top: 1px solid blue; }
<div class="flex">
<div class="item">
<div class="inline-block">Lorem<br />Ipsum<br />Dolor</div>
</div>
<div class="item">
<div class="inline-block">Foo bar</div>
</div>
</div>
That will work because, according to CSS 2.1,
The baseline of an 'inline-block' is the baseline of its last line box
in the normal flow, unless it has either no in-flow line
boxes or if its 'overflow' property has a computed value other than
'visible', in which case the baseline is the bottom margin
edge.

At the time of writing the CSS box model alignment working draft proposes a ‘first’ and ‘last’ value to be added to ‘align-items’. The would allow:
align-items: last baseline
Current it only appears to be supported by Firefox so is one for the future.
https://developer.mozilla.org/en-US/docs/Web/CSS/align-items

Related

Can't understand css flexbox in this situation [duplicate]

I have three elements I'm trying to align in my layout.
First, I have a div for feedback, and then a search input, and then a div element for suggestions.
I want the first and last element to have a width of 20%, and the search input to have a width of 60%. Using Flexbox I achieve what I want.
But there's a feature that grows all the divs to the highest element. This means that when search results pop up, the feedback and suggestion elements grow in height with the search div resulting in a messed up layout.
Is there a trick to not grow the divs with the highest element? Just make the divs (#feedback and #suggestions) have the height of the content in them?
#container_add_movies {
display: flex;
}
#container_add_movies #feedback {
width: 20%;
background-color: green;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#container_add_movies #suggestions {
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>
Feedback
</div>
<div id='search'>
Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>
</div>
<div id='suggestions'>
Suggestions
</div>
</div>
http://codepen.io/alucardu/pen/PPjRzY
You're encountering the flex equal height columns feature.
An initial setting of a flex container is align-items: stretch.
This means that flex items automatically expand the full length of the cross axis of the container. In a row-direction container, the cross axis is vertical (height).
The tallest item sets the height for all siblings. As the tallest item expands, its siblings follow along. Hence, equal height for all items.
To override this default setting, add align-items: flex-start to the flex container:
#container_add_movies {
display: flex;
align-items: flex-start;
}
#container_add_movies {
display: flex;
align-items: flex-start; /* NEW */
}
#container_add_movies #feedback {
width: 20%;
background-color: green;
display: block;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#container_add_movies #suggestions {
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>Feedback</div>
<div id='search'>
Search<br>Search<br>Search<br>Search<br>Search<br> Search
<br>Search<br>Search<br>Search<br>Search<br>
</div>
<div id='suggestions'>Suggestions</div>
</div>
... or align-self: flex-start to the flex items:
#feedback {
align-self: flex-start;
width: 20%;
background-color: green;
}
#suggestions {
align-self: flex-start;
width: 20%;
background-color: yellow;
}
#container_add_movies {
display: flex;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#feedback {
align-self: flex-start; /* NEW */
width: 20%;
background-color: green;
}
#suggestions {
align-self: flex-start; /* NEW */
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>Feedback</div>
<div id='search'>
Search<br>Search<br>Search<br>Search<br>Search<br> Search
<br>Search<br>Search<br>Search<br>Search<br>
</div>
<div id='suggestions'>Suggestions</div>
</div>
align-items sets the default value of align-self. With align-self you can override the default on individual items.
More details in the spec:
8.3. Cross-axis Alignment: the align-items and align-self
properties
Flex items can be aligned in the cross axis of the current line of the
flex container, similar to justify-content but in the perpendicular
direction.
align-items sets the default alignment for all of the flex
container’s items, including anonymous flex items.
align-self allows this default alignment to be overridden for
individual flex items.
A bit of history
Since the beginnings of CSS, there have been two layout challenges that have regularly frustrated, perplexed, and annoyed front-end developers:
How to center things, especially vertically, and
How to create equal height columns (tables aside)
Today, with the advent of flexbox, these problems are over.
Centering things has never been easier:
#container {
display: flex;
justify-content: center; /* center flex items along the main axis */
align-items: center; /* center flex items along the cross axis */
}
Simple. Easy. Efficient. The craziness is over.
In terms of equal height columns, flexbox also excels: It does this by default.
#container {
display: flex;
flex-direction: row; /* not even necessary; default rule */
align-items: stretch; /* not even necessary; default rule */
}
The align-items: stretch rule tells flex items to expand along the cross-axis as much as possible. Hence, in a row-direction container all items can be equal height. More craziness tamed by flexbox.
From one popular answer for equal height columns:
Give overflow: hidden to the container and large (and equal)
negative margin and positive padding to columns. Note that this
method has some problems, e.g. anchor links won't work within your
layout.
Now that's a hack!
The pendulum is now beginning to swing the other way: Designers are asking how to TURN OFF equal height columns.
You can add align-items: flex-start to your #container_add_movies. Here's an example
to have the unequal columns in bootstrap 4, first of all it needs to know how it is making it equal heights of the columns,so the reason is the
align-items: stretch
to remove this property it need to add align-items: flex-start so for this I have added the class="align-items-start" and the issue is fixed,
Setting the child element that was causing the problem to flex:none did the trick for me.

Unknown offset. (inline-flex element + clearfix) [duplicate]

I have a weird behaviour of an inline-flex element when applying a clearfix to it. When I set a clearfix to an element which has an inline-flex display property the strange white space appears before it:
But when the inline-block is used the behaviour is different:
I don't understand why inline-flex has a different behaviour than inline-block.. and why it has that weird space.
.a,
.b {
border: 1px solid red;
}
.a {
text-align: center;
}
.b {
display: inline-flex;
height: 20px;
width: 20px;
}
.cf:before,
.cf:after {
content: " ";
display: table;
}
.cf:after {
clear: both;
}
<div class="a">
<div class="b cf"></div>
</div>
JSFiddle Demo
Try set a vertical-align: top to your inline-flex | inline-block element to fix this offset.
https://jsfiddle.net/jeca65my/2/
Thank's to #NenadVracar on this solution
display: inline-flex
When you use display: inline-flex, you establish a flex container.
An initial setting of a flex container is flex-direction: row.
This means that all in-flow child elements of the container (including in-flow pseudo-elements) will line up in a row. The display value of these children (table, in this case) is overridden/ignored, in accordance with the rules of a flex formatting context.
Your flex container has two flex items (the pseudo-elements) in one line:
.a,
.b {
border: 1px solid red;
}
.a {
text-align: center;
}
.b {
display: inline-flex;
height: 20px;
width: 20px;
}
.cf:before,
.cf:after {
content: "x";
display: table;
}
.cf:after {
clear: both;
}
<div class="a">
<div class="b cf"></div>
</div>
display: inline-block
When you use display: inline-block, you establish a block formatting context.
The display property of child elements is respected.
Your pseudo-elements with display: table are block elements which, by default, occupy the full available width. Hence, the pseudos are creating two rows:
.a,
.b {
border: 1px solid red;
}
.a {
text-align: center;
}
.b {
display: inline-block;
height: 20px;
width: 20px;
}
.cf:before,
.cf:after {
content: "x";
display: table;
}
.cf:after {
clear: both;
}
<div class="a">
<div class="b cf"></div>
</div>
vertical-align: baseline
Because both versions of your code use inline-level display values, this calls into play the vertical-align property, who's initial value is baseline.
The white space you are seeing below div.b when set to display: inline-flex is due to baseline alignment.
The white space you are seeing below div.b when set to display: inline-block is due to baseline alignment in combination with the effects of two block element children.
Here is a more detailed explanation:: https://stackoverflow.com/a/36975280/3597276
The clear property
.cf:after {
clear: both;
}
Your clearfix method is not the source of any of the white space. In fact, it's having no effect on your layout and can be safely removed.
You use the clear property only when dealing with floats.
From the spec:
9.5.2 Controlling flow next to floats: the clear
property
This property indicates which sides of an element's box(es) may not be
adjacent to an earlier floating box.
Not only are there no floated elements in your layout, but if there were, the float and clear properties are nonetheless ignored in a flex formatting context.
3. Flex Containers: the flex and inline-flex display
values
float and clear do not create floating or clearance of flex item, and do not take it out-of-flow.
You have to imagine your page as a flow. Every element of your page is in the flow (DOM). You are using the position property to change the position in the flow.
block
A block element will Always start a new line. (ie: div)
inline-block
Inline blocks elements are blocks like div but with inline properties in it. (ie: span)
inline-flex
This is used the same way as inline-block in the flow. It makes a container that is inline but with the flex layout.
For your example, an interesting thing to do in order to focus on the difference between inline-block and inline-flex is to add text in your child div. You'll see that the comportment of your child div will once again change because it has text in it. JSFiddle example
EDIT : I found a sentence on SO that resumes well the situation. thank's to #BoltClock on This post :
display: inline-flex does not make flex items display inline. It makes the flex container display inline.

Positioning of elements in a box with Flexbox

I have been trying to make a row of responsive boxes present a nicer look. After lots of effort and googling, I am here to get a word from experts. Please check the image below:
Outermost red is a bootstrap flexible row with display:flex;
Each box, the first of which is represented by green box, has flex: 1 ...;
Until this point, there is no issue and my CSS works perfect on all screen sizes showing all the boxes in same height and width. I just have two issues which I need help on.
Issue 1:
I need that lower part of box (represented by orange border) may always get positioned to the bottom of green box. This way all the buttons will appear in same line.
I tried to use a wrapper div in each box and then set position attribute for wrapper to relative and those of inner divs (yellow & orange) to absolute. Then I set the lower one to bottom: 0px;. But it does not work with flex and needs me to mention fixed height of wrapper which I cannot mention.
Issue 2:
In the box with the blue border I need the text of all lines to be justified except the last line which should be left aligned.
Issue 1
Assign display: flex to the div that is presented by the green box. After that, add align-self: flex-end; to the orange box. The orange box should now be displayed at the end of the green box.
Issue 2
Use the following fix to achieve what you want:
.blue-box {
text-align: justify;
-moz-text-align-last: right;
text-align-last: left;
}
The problem is that this wis not supported by Safari on Mac and iOS devices. You would have to add more markup to also cover Safari. An example would be to wrap each text line into a p tag if it's possible. Then you could do this:
.blue-box p {
text-align: justify;
}
.blue-box p:last-child {
text-align: left;
}
Please report back if the fixes do work for you or not.
The best way to solve this is to use flexbox.
.promo-boxes {
width: 100%;
display: flex;
justify-content: space-between;
background-color:black;
}
.promo-box {
width: 100px;
border: solid 1px #ccc;
background-color:red;
display: flex;
}
.btns-wrapper {
margin-top: auto;
align-self: flex-end;
}
<div class="promo-boxes">
<div class="promo-box">
<div>test 2</div>
<div class="btns-wrapper">
<button>
subscribe
</button>
</div>
</div>
<div class="promo-box">
<div>
test 3
</div>
<div class="btns-wrapper">
</div>
</div>
<div class="promo-box">
<div>
test 4 <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
loooong
</div>
<div class="btns-wrapper">
</div>
</div>
</div>

Stacking divs from the bottom right

I am adding colour blocks (divs with bg colours) to a parent div. Each parent div can have a number of these colour blocks which are to display in the bottom right of the parent, with a maximum of three to a row.
My code (below) does what is required for 3 or less colours, but if a forth colour is added it jumps to the line below leaving two empty spaces on the bottom line. What I would like to happen is for the forth colour to be displayed on the line above so the bottom line has no blanks.
You can see the problem in action here along with a hardcoded example of what I would like to happen.
<style>
.container {
position: relative;
width: 200px;
height: 142px;
}
.colorSwatches {
position: absolute;
bottom: 0px;
right: 0px;
max-width: 100px;
max-height:60px;
text-align:right
}
.swatch {
display: inline-block;
width: 25px;
margin: 2px;
height: 25px;
background-color: rgb(255, 0, 0); ///or whatever
}
</style>
<div class="container">
<div class="colorSwatches">
<div class="swatch"></div>
<div class="swatch"></div>
<div class="swatch"></div>
<div class="swatch"></div>
</div>
</div>
Thanks for any help.
I think you can pull off that layout with some flexbox magic:
set your .swatches container, in your case .colorSwatches, with display: flex prop
then to this container and a flex-wrap rule of: flex-wrap: wrap-reverse, so that the children inside it will wrap, on to the next line, in opposite direction of the flex-direction, which by default is row I think.
and lastly, add to the container, the justify-content: flex-end; so that the items inside will start laying out at the end of their container.
Here's a jsfiddle demo and a couple of resources:
Flexbox
Justify-content
Flex-wrap

Horizontally center text in row with floats on both sides, with flexbox?

Here's a CSS puzzle for you all.
I'm using flexbox in my layout. I have a header with a few buttons on the left side, some text in the center, and another button on the right. Here's an ascii drawing:
[btn][btn2][btn3][ text ][btn4]
Unfortunately, this looks weird because the text isn't centered in the header. What I really want is this:
[btn][btn2][btn3][ text ][btn4]
Ideally, I'd like to continue using flexbox to achieve this because it makes most of the horizontal layout really easy, but I'm willing to fall back to floats and/or positioning if need be.
One problem with positioning the text element absolutely is that long text will under/overlap the buttons on the side. I currently use text-overflow: ellipsis and as a bonus, I would love to continue to if possible:
[btn][btn2][btn3][ long text causes elli... ][btn4]
I'm also okay with adding extra container elements if that helps. Perhaps there's a way to solve this by adding left buttons and right buttons in containers and then ensuring those containers are always the same width?
Edit: I think I took a step in the right direction with this CodePen. It properly centers the text. The only downside is that the h1 needs a fixed or percentage width, and if that width is wider than the space available, it seems to just overlap the neighboring elements.
You came very close to a working sample. I forked your CodePen with a solution that don't require widths of any kind. It's using the power of flex to position elements.
The H1 will always be in the middle, with a width of the same size as the surrounding left-btnsand right-btns, using flex: 1;
You can, of course, specify your H1 to a fixed width as you did, or make it for example flex: 2; to have it take up 50% space instead of 33%.
Here's the fork on CodePen. I've removed unnecessary code.
And the code:
HTML
<div class="wrapper">
<div class="left-btns">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<h1>center me! center me! center me! test woah asdf veasdf veasdf veasdf veasdf ve</h1>
<div class="right-btns">
<div class="box"></div>
</div>
</div>
<h1>center me!</h1>
CSS
.wrapper {
background: green;
display: flex;
margin: 5px;
}
h1 {
flex: 1;
text-align: center;
margin: 5px;
background: yellow;
overflow: hidden;
text-overflow: ellipsis;
white-space: noWrap;
}
.box {
width: 50px;
height: 50px;
margin: 1px;
background: red;
}
.left-btns,
.right-btns {
margin: 5px;
display: flex;
flex: 1;
background: blue;
}
.right-btns {
justify-content: flex-end;
}

Resources