Using flexbox to get equal height rows, not columns - html

I'm new at using flex in a stylesheet.
I am attempting to force two block level elements to be the same height.
Here is the fiddle: https://jsfiddle.net/r9pwzonx/
.flex {
display: flex;
flex-direction: column;
}
.first {
padding: 1em;
background: blue;
flex: 1;
}
.second {
padding: 1em;
background: red;
flex: 1;
}
<div class="flex">
<div class="first">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</p>
</div>
<div class="second">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quam minus aliquam assumenda consequuntur, laboriosam ducimus ad quis omnis, molestiae a iure nesciunt voluptate rem libero accusantium, deleniti, porro nemo excepturi?</p>
</div>
</div>
I do not see any change in the height of the smaller box to match the height of the larger box.

I do not see any change in the height of the smaller box to match the
height of the larger box.
You cannot do that in a flex box with that flex-direction: columnbecause that the main-axis, thus defining the direction flex items are placed in the flex container. Flexbox is (aside from optional wrapping) a single-direction layout concept.A flex container expands items to fill available free space, or shrinks them to prevent overflow.
If you give row a fixed height , I believe this should work as you expect. If you're not trying to use fixed height.It depends on the the things that inside on that flexboxes.
CODEPEN WITH LINE-HEIGHT
CODEPEN WITH FIXED-HEIGHT

Related

Align two elements on top of each other without a container with a width

I have two elements that I would like to be aligned in a column-like way. These elements also need to be floated to the right of the page. If I float the container containing these two elements to the right, they automatically align in a row-like way. My immediate thought is to specify a width of the container so that they will be forced to move downward. The issue with this is that the two elements are different widths.
<div style="float: right; width: 100px;">
<div style="width: 110px; height:50px; background-color: blue;">
Element 1
</div>
<div style="width: 60px; height:50px; background-color: red;
float:right;">
Element 2
</div>
</div>
paragraph text that will not flow into the bottom element because the container's width prevents it. Filler text.....
If the bottom element is not as wide as the top element, the width of the container makes it wider. This is an issue because I have other text / elements that I would like flow around these side elements, and it looks weird because of the whitespace created by the different in widths.
If I try something like making the parent absolute, as not to effect the other elements on the page, the children don't either.
How can I create elements that are floated in a container without the width of the container affecting the other elements on the page as well? Thanks, Levi
One approach is as below, taking advantage of display: contents comments in the code itself:
/* basic CSS reset to reduce all elements to the same
box-sizing, font, margin and padding: */
*,
::before,
::after {
box-sizing: border-box;
font: normal 1rem / 1.5 sans-serif;
margin: 0;
padding: 0;
}
/* a wrapping element to allow for some dynamic sizing of the
contents: */
main {
/* the width of the <main> element is 80vw (viewport-width units)
unless that is less than 30em (the minimum size it will be) or
unless that size exceeds 1000px (at which point it will take
a width of 1000px maximum): */
width: clamp(30em, 80vw, 1000px);
/* a margin of 1em on the top and bottom top-to-bottom languages: */
margin-block: 1em;
/* a margin of auto on the inline axis, left (start) and right (end)
in left-to-right languages, such as English: */
margin-inline: auto;
}
div.wrapper {
/* for those browsers that are yet to implement
logical properties: */
float: right;
/* equivalent to "float: right" in left-to-right
languages, such as English: */
float: inset-inline-end;
width: 100px;
/* effectively removes this element from the
layout, exposing its contents to the layout
engine: */
display: contents;
}
div.wrapper > div {
/* ensuring that the "display: contents" is
unset, which takes it back to the default
display model: */
display: unset;
/* for those browsers that are yet to implement
logical properties: */
float: right;
/* as above, equivalent to "float: right" in
left-to-right languages, such as English: */
float: inset-inline-end;
height: 50px;
/* forces each element to clear the float of its
siblings: */
clear: both;
/* to hide the overflowing text: */
overflow: hidden;
text-overflow: ellipsis;
}
.wrapper > div:first-child {
background-color: blue;
width: 110px;
}
.wrapper > div:last-child {
background-color: red;
width: 60px;
}
<main>
<div class="wrapper">
<div>
Element 1
</div>
<div>
Element 2
</div>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur perferendis corporis itaque, sequi quod commodi explicabo dolore, totam, libero architecto doloremque nisi illo iste quae ea, laboriosam reprehenderit nemo animi! Lorem ipsum dolor
sit amet, consectetur adipisicing elit. Quia reiciendis sapiente blanditiis provident ad ullam consequatur, temporibus ex accusamus est nihil voluptatum totam cupiditate. Ducimus sit deserunt nostrum, dolorem doloremque. Lorem ipsum dolor sit amet,
consectetur adipisicing elit. Consectetur perferendis corporis itaque, sequi quod commodi explicabo dolore, totam, libero architecto doloremque nisi illo iste quae ea, laboriosam reprehenderit nemo animi! Lorem ipsum dolor sit amet, consectetur adipisicing
elit. Quia reiciendis sapiente blanditiis provident ad ullam consequatur, temporibus ex accusamus est nihil voluptatum totam cupiditate. Ducimus sit deserunt nostrum, dolorem doloremque.</p>
</main>
JS Fiddle demo.
References:
CSS logical properties.
display.
float.
Bibliography:
Compatibility of CSS logical properties, from "Can I Use."

How are heights of flex items calculated when flex-direction: column is applied?

I am trying to get my mind around flex box layout and now considering flex-direction: column option.
HTML
<div class="container">
<div class="item">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat similique nihil, mollitia
voluptates iste eos atque unde repellendus iure voluptatibus nulla explicabo laboriosam, harum, eum dicta.
Maiores quia aliquid in.</div>
<div class="item">
Lorem
</div>
</div>
CSS
.container {
display: flex;
flex-direction: column;
}
.item{
flex: 1;
}
As long as our screen displays the first item div's text in multiple rows, the items end up with different main sizes (heights). It was rather surprising to me as row flex-direction in this case would hold the same main sizes of items (widths).
To find out how it happens, I delved into the spec.
9.2. Line Length Determination
2 Determine the available main and cross space for the flex items. For each dimension, if that dimension of the flex container’s content box is a definite size, use that; ... otherwise, subtract the flex container’s margin, border,
and padding from the space available to the flex container in that
dimension and use that value. This might result in an infinite value.
4 Determine the main size of the flex container using the rules of the formatting context in which it participates.
As far as I'm concerned, it is the very case when the available space in the main (vertical) dimension is an infinity value. So it puzzles me how it's possible to determine the container's main size (step 4), noting that sizes of the items are still uncalculated at this point (the container is a block element, so its height value is dependent on its children).
Can anybody provide some explanation and point me out to the place in the spec where our items finally get different height values?1
1: In accordance with the step 4 of 9.7. Resolving Flexible Lengths, main size of an item should be a fraction of its grow factor to the sum of the items' grow factors multiplyed by the free space (the container's height). We have the same grow factors, so why do we see different items heights?
You are running it a complex case where another specification need to be considered and also the min-height constraint.
When using flex:1 the browser is setting flex-basis: 0%. Pay attention to the % because all the trick is there. You have a percentage so you need a reference to resolve it and we are dealing with a height auto so the reference doesn't exist. At the end it's like you didn't set any flex-basis that's why you see no difference.
Now if you use flex-basis: 0px you will have a different behavior
.container {
display: flex;
flex-direction: column;
border: 1px solid;
}
.item {
flex: 1 1 0px;
border: 1px solid red;
min-height: 0;
}
<div class="container">
<div class="item">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quaerat similique nihil, mollitia voluptates iste eos atque unde repellendus iure voluptatibus nulla explicabo laboriosam, harum, eum dicta. Maiores quia aliquid in.</div>
<div class="item">
Lorem
</div>
</div>
Note that I have also introduced min-height: 0. Without it, nothing will happen because an element cannot shrink past its content size.
Now if you set flex-basis to 0px, each element will have an initial height equal to 0px so the height of the container will also be equal to 0px. End of the story! flex-grow and flex-shrink will do nothing since there is no positive or negative free space.
It's different when dealing with a row direction because the container width doesn't depend on its content and is full width. In such case you will have free space for the flex-grow and you end with equal width items.

Can css be used to collapse whitespace around inline elements with varying line heights?

Suppose one is designing a box to frame some content, and wants that box to always have consistent space between its borders and text inside of it, regardless of the text's line-height. Is there a solution aside from custom negative margin on each box?
In theory this should actually be the "responsibility" of the content (in this case, the text), assuming our box is some kind of component allowing transclusion (e.g. web component slots), so I'd be especially interested in any way to style an inline element so that its line-height-generated top and bottom spaces collapse, regardless of line-height value (intentionally not calling them margins to not confuse them with the margin css property).
Here as an runnable example of the issue - the space between the magenta border and the inner text varies due to line height, and if the magenta border wasn't there, it would appear that each box has different padding.
This has probably been answered, but unfortunately since the terms are so generic it's hard to research (though I did try).
.foo {
max-width: 200px;
border: 2px solid blue;
padding: 20px;
line-height: 2;
display: inline-block;
vertical-align: top;
}
.foo>* {
border: 1px solid magenta;
}
.baz {
line-height: 1;
}
.bar {
line-height: 3;
}
<div class="foo">
<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci impedit porro fuga ab magnam.</div>
</div>
<div class="foo">
<div class="baz">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci impedit porro fuga ab magnam.</div>
</div>
<div class="foo">
<div class="bar">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci impedit porro fuga ab magnam.</div>
</div>
One idea that may solve half the issue is to change the line-height of the text to a smaller value than the container. Doing so, the height of the text will be smaller than the linebox and you can align it to the top. For this you need to consider an extra container.
.foo {
max-width: 200px;
border: 2px solid blue;
padding: 20px;
line-height: 2;
display: inline-block;
vertical-align: top;
}
.foo>* {
border: 1px solid magenta;
}
.baz {
line-height: 1;
}
.bar {
line-height: 3;
}
span {
line-height:1;
vertical-align:top;
}
<div class="foo">
<div><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci impedit porro fuga ab magnam.</span></div>
</div>
<div class="foo">
<div class="baz"><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci impedit porro fuga ab magnam.</span></div>
</div>
<div class="foo">
<div class="bar"><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci impedit porro fuga ab magnam.</span></div>
</div>
As you can see the text will always be aligned on the top whataver the line-height but the issue remains on the bottom. It's like we moved the issue to only one side.
Here is a related answer to better understand the alignment trick : https://stackoverflow.com/a/54190413/8620333

Make flex item take 100% width of new line

I have HTML structure like:
<div class="container">
<div class="btn-1"></div>
<div class="btn-2"></div>
<div class="btn-3"></div>
<div class="text">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. A veritatis harum illum assumenda odio ut, quos, ipsam molestias et sint nemo, saepe! Soluta a, quasi sequi, ut corrupti eius molestias.
</div>
</div>
btn-1 should be aligned to the top left, all other buttons (btn-2, btn-3...) should be aligned to the top right.
The text after all these buttons should be 100% width.
Quick mockup:
I figured out the first part (buttons) with:
.container {
display: flex;
justify-content: flex-end;
}
.btn-1 {
/* align first button to the left */
margin-right: auto;
}
Bu not matter what I do, the text doesn't flow to the next line...
Here's my JSFiddle https://jsfiddle.net/an0o7taq/
Thanks for any help!
You need to add flex-wrap: wrap to the container.
By default, flex containers are set to flex-wrap: nowrap, forcing items to remain on a single line.
revised jsfiddle
Spec reference:
5.2. Flex Line Wrapping: the flex-wrap property
You need more container with different flex flows and styles. Tip: learn most important flex props: align-items, flex-flow, justify-content. They all apply to the direct children of the container. So when you want your layout you need more container with different flex flows.
This guide helped me a lot. They also have great examples:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
.container {
display: flex;
flex-flow: column nowrap;
}
.header {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.header-left, .header-right {
display: flex;
flex-flow: row nowrap;
}
.btn {
width: 40px;
height: 40px;
border: 1px solid #ddd;
background-color: #eee;
}
.text {
width: 100%;
}
<div class="container">
<div class="header">
<div class="header-left">
<div class="btn">btn1</div>
</div>
<div class="header-right">
<div class="btn">btn2</div>
<div class="btn">btn3</div>
</div>
</div>
<div class="text">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. A veritatis harum illum assumenda odio ut, quos, ipsam molestias et sint nemo, saepe! Soluta a, quasi sequi, ut corrupti eius molestias.
</div>
</div>

CSS divs next to each other that affect each others width

I have this problem that I can't seem to figure out. After researching I can't seem to find anyone that has solved it. I'm not sure that it can be solved in pure CSS, but I have to ask:
Consider a situation where there are two divs next to each other. The divs have a known width.
The size of the content, however, is not known. When the content of one div becomes very large, that div should take space from the other, as such:
This width should only grow if the known width can't accommodate the content.
Likewise, the blue div should grow if its content is very large:
Is this possible to solve with only CSS, or would I need JS?
flexbox and min-width can do that:
.wrap {
width: 50%;
margin: 1em auto;
border: 1px solid grey;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.wrap div {
flex: 1 0 auto;
max-width: 70%;
}
.left {
background: rgba(255, 0, 0, 0.5);
min-width: 30%;
}
.right {
background: rgba(0, 0, 255, 0.5);
min-width: 30%;
}
<div class="wrap">
<div class="left">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur quas incidunt dolorem doloribus asperiores, iure esse voluptatibus dolore cum sint exercitationem minus aspernatur explicabo perspiciatis distinctio expedita.</div>
<div class="right"></div>
</div>
<div class="wrap">
<div class="left"></div>
<div class="right">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga, accusantium libero omnis, quod ea pariatur porro asperiores enim officia minima!</div>
</div>
if you set a fixed size to div, content will flow in multiple lines instead of div expanding to fit the content.
Instead you need to set minimum width to the div then it can expand, but you will have to set max-width that it can occupy as well so that it wont take full space pushing the second div away.