Display flex even space between children regardless of children width - html

I have two instances of the same row-component that has display: flex and justify-content: space-between:
<div class="component-row">
<div>looooooooooong</div>
<div>short</div>
<div>mediummm</div>
</div>
<div class="component-row">
<div>looooooooooong</div>
<div>short</div>
<div>mediummm</div>
</div>
The spacing between the children of each component will be different because the children have different widths. Without changing the order of the children, how can I make sure that both component instances have the same amount of space between each of their children? Within the instance, the space (ex. the space between long and short) doesn't have to be equal - what I want is the space between the 1st and 2nd child of both instances to be the same, and the space between the 2nd and 3rd child of both instances to be the same.

It sounds really easy solution but it is, just give a fixed width on a class and then place it on the .component-row childrens.
.component-row {
display: flex;
justify-content: space-between;
}
.eq1 {
width: 30%;
}
.eq2 {
width: 20%;
}
.eq3 {
width: 35%;
}
<div class="component-row">
<div class="eq1" style="background-color: red;">looooooooooong</div>
<div class="eq2" style="background-color: purple;">short</div>
<div class="eq3" style="background-color: pink;">awdasdsdasad</div>
</div>
<div class="component-row">
<div class="eq1" style="background-color: green;">looooooooooong</div>
<div class="eq2" style="background-color: yellow;">srt</div>
<div class="eq3" style="background-color: blue;">mediummm</div>
</div>

The most obvious would be to give each item a width, though if you can't or don't want, flexbox is not the best solution, a grid is.
As CSS Grid lacks good browser support, CSS Table doesn't, and is the perfect choice to accomplish this task.
.component-container {
display: table;
width: calc(100% - 40px);
}
.component-row {
display: table-row;
}
.component-row div {
position: relative;
display: table-cell;
border: 1px solid gray;
}
.component-row div:nth-child(2) {
left: 20px;
}
.component-row div:nth-child(3) {
left: 40px;
}
<div class="component-container">
<div class="component-row">
<div>looooooooooong</div>
<div>mediummm</div>
<div>short</div>
</div>
<div class="component-row">
<div>short</div>
<div>looooooooooong</div>
<div>mediummm</div>
</div>
</div>

Related

Moving one HTML element before another while maintaining document flow

I am trying to create tab module such as this:
https://codepen.io/oknoblich/pen/tfjFl
However I am having difficulty since I can not change the HTML layout:
<div class="container">
<div class="tab-header">Tab1</div>
<div class="tab-content teal">Content1</div>
</div>
<div class="container current">
<div class="tab-header">Tab2</div>
<div class="tab-content teal">Content2</div>
</div>
The problems are that absolute positioning removes the content from the document flow, while other methods prevents the content from being the full width of the page.
I created two codepen's that illustrates the difficulties:
https://codepen.io/dwigt/pen/pOQpLd (absolute positioning removes content from document flow)
https://codepen.io/dwigt/pen/YOREOJ (flexbox layout does not take up full page-width)
Is there anyway I can replicate the tab functionality using this HTML layout and no javascript?
You can use display: contents (which is unfortunately not too well supported) combined with flexbox layout with wrap, set on the .wrapper element. This way, tab-headers and tab-contents will be treated equally, as if they were at the same level with one another - the .container elements are "transparent" to the layout engine. As a result, they will all be laid out with flexbox logic applied. Finally, to have the three tab headers display first, we set the order of the tab contents to some high value (here 100), and since we have flex wrap enabled, the content is then pushed downwards to a new line, below the headers. See example below:
.wrapper {
max-width: 300px;
display: flex;
flex-wrap: wrap;
height: 100%;
}
.container {
height: 50px;
display: contents;
}
.container .tab-header {
width: 100px;
max-width: 100%;
max-height: 100%;
flex: 1 0 33.33%;
}
.container .tab-content {
display: none;
height: 200px;
order: 100;
}
.container.current .tab-content {
display: block;
width: 300px;
left: 0;
}
.footer {
height: 500px;
width: 300px;
display: block;
}
.red {
background: red;
}
.teal {
background: teal;
}
<div class="wrapper">
<div class="container">
<div class="tab-header">Tab1</div>
<div class="tab-content teal">Content1</div>
</div>
<div class="container current">
<div class="tab-header">Tab2</div>
<div class="tab-content teal">Content2</div>
</div>
<div class="container">
<div class="tab-header">Tab3</div>
<div class="tab-content teal">Content3</div>
</div>
</div>
<div class="footer red">Footer Text</div>
This isn't quite perfect because the first tab is a bit wider, but give this a shot and see if this doesn't get your closer to your goal. It allows your tabs to be 100% and also allows you to add more tabs that space evenly from edge to edge of your container.
Let me know how it works out :D
Add display: table-cell and width: 100% to your css selector label
label {
display: table-cell;
width: 100%;
margin: 0 0 -1px;
padding: 15px 25px;
font-weight: 600;
text-align: center;
color: #bbb;
border: 1px solid transparent;
}

How to Get Float Behavior Inside Flex Element?

Looking to have one large item on the left and a lot of small items on the right. If the browser window is big enough, I'd like the small items to "float" in a columnar manner such that they don't exceed the height of the large item. However, when the browser shrinks, I'd like the small items to wrap down below the large one in a single row.
Here's a codepen to demonstrate: https://codepen.io/anon/pen/WXQdEN
div.container {
display: flex;
flex-wrap: wrap;
}
div.right-variable {
max-height: 320px;
align-items: center;
}
div.test-700 {
width: 700px;
height: 320px;
background: green;
color: #ffffff;
font-size: 40px;
}
div.test-100 {
width: 100px;
height: 100px;
background: red;
outline: 1px solid black;
margin: 2px;
float: left;
}
<table>
<tr>
<td>
<div class="test-700">Example Table</td>
</td>
<td>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
</td>
</tr>
</table>
<div class="container">
<div class="left-fixed">
<div class="test-700">Non-Working Flex</div>
</div>
<div class="right-variable">
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
</div>
</div>
The table shows the desired behavior of the red boxes at large resolutions. As the browser shrinks, the boxes float around to fill the space.
But when the browser gets too small to contain them, I want the flex behavior where the red boxes wrap down under the green one. I understand that this doesn't work because I can't float the items within the flex, but I don't understand how to achieve a similar behavior without float. I'd like to achieve this using flex and CSS only. Is that possible?
Thank you for any assistance.
The main issue here is related to sequence for wrapping and since the browser don't know which to wrap before the other, they start with the outer element.
Also, there is no property that one can set, to define the order, but there is media query, where we can set a breaking point, and in this case, use it to tell when the container is allowed to wrap.
Remove flex-wrap: wrap from the container and add it back at a desired maximum width using a media query.
Then also make the div.right-variable a flex container and have the red elements centered.
Stack snippet
div.container {
display: flex;
}
div.right-variable {
margin: auto 0; /* center vert. */
max-height: 320px;
display: flex;
flex-wrap: wrap;
}
div.test-700 {
width: 700px;
height: 320px;
background: green;
color: #ffffff;
font-size: 40px;
}
div.test-100 {
margin: auto 0; /* center vert. */
width: 100px;
height: 100px;
background: red;
outline: 1px solid black;
margin: 2px;
}
#media (max-width: 816px) {
div.container {
flex-wrap: wrap;
}
}
<div class="container">
<div class="left-fixed">
<div class="test-700">Working Flex</div>
</div>
<div class="right-variable">
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
</div>
</div>

Content inside a div in a new column on overflow

I don't find a way to have a vertical alignment of div which wrap to a second column on overflow...
I have a div with a fixed height, inside I have a dynamicaly variable number of texts each wrapped in a div with a fixed width.
I want to display texts in vertical alignment. If there is not enough space, a second column shall be used.
I tried with float and display: inline-block but the element are not below each other.
I think it will be easier to understand with a picture:
A pure CSS solution will be the best!
Here are the base html code of the problem:
<div class="container" style="height: 70px; background-color: lightblue;">
<div style="width: 100px;">Alsace</div>
<div style="width: 100px;">Bretagne</div>
<div style="width: 100px;">Centre</div>
<div style="width: 100px;">Lorraine</div>
<div style="width: 100px;">Picardie</div>
</div>
Context: on the left of the main div, I have a country map with different county which can be selected, when a county is selected I want to display it's name close to the map. That's why I want the texts the closest to the left side.
Even better method:
.container {
display: flex;
flex-flow: column wrap;
}
Thanks to #Roberrrt
This can be done with display: flex;
Demo: https://jsfiddle.net/88p36j74/
You set the wrapper height to 'item height' x 'vertical item count'.
.container {
display: flex;
flex-direction: column;
align-content: flex-start;
flex-wrap: wrap;
height: 250px;/* 5 items x 50px = 250px*/
}
.container div {
height: 50px;
width: 100px;
background: red;
}
You could use column-count. 1
.container {
height: 90px;
background-color: lightblue;
column-count: 2;
column-fill: auto;
}
.container>div { width: 100px; height: 20px; }
<div class="container">
<div>Alsace</div>
<div>Bretagne</div>
<div>Centre</div>
<div>Lorraine</div>
<div>Picardie</div>
</div>
1 column-count support
Bonjour =)
You need to wrap your divs in two other divs, representing the columns you want.
This would give something like:
<div class="container" style="height: 70px; background-color: lightblue;">
<div class="column" style="float:left;">
<div style="width: 100px;">Alsace</div>
<div style="width: 100px;">Bretagne</div>
<div style="width: 100px;">Centre</div>
<div style="width: 100px;">Lorraine</div>
</div>
<div class="column" style="float:left;">
<div style="width: 100px;">Picardie</div>
</div>
</div>
Something like that should work, you may need to add fixed width on both divs though.

How to divide parent div's height between child divs

I have a random number of child div. The parent div height is known and fixed. I want the child divs' height to be the parent div's height divided by the number of child divs. (In my example there is two child divs but i can't know how many child divs there will be)
HTML
<div class="calendar-default">
<div class="calendar-plage" style="background-color: red;"> </div>
<div class="calendar-plage" style="background-color: green;"> </div>
</div>
CSS
.calendar-default{
background-color: black;
position: relative;
height: 100px;
width: 100px;
}
.calendar-plage{
height: auto; /* ??? */
}
The Fiddle explain my problem best : https://jsfiddle.net/z2anpsy7/
I managed to do it with javascript but i'd like to do it with CSS only. Is it possible ?
Ps: It's inside an AngularJS app, if you know an elegant angular way of solving my problem it's also great !
You can do this with flexbox and flex-direction: column;
.calendar-default {
background-color: black;
position: relative;
height: 100px;
display: flex;
flex-flow: column wrap;
}
.calendar-plage {
flex: 1 0 auto;
}
<h2>2 children</h2>
<div class="calendar-default">
<div class="calendar-plage" style="background-color: red;"> </div>
<div class="calendar-plage" style="background-color: green;"> </div>
</div>
<h2>3 children</h2>
<div class="calendar-default">
<div class="calendar-plage" style="background-color: red;"> </div>
<div class="calendar-plage" style="background-color: green;"> </div>
<div class="calendar-plage" style="background-color: blue;"> </div>
</div>
To spread the childs horizontally, we use display: table-cell and to spread the childs vertically, we can use display: table-row. But display: table-row needs some content in it, which I am providing through pseudo element as you can see in the below example.
Try to add more childs, they spread and fit inside the parent container automatically.
.parent {
height: 100px;
width: 100px;
display: table;
border: 1px solid black;
}
.child {
display: table-row;
width: 100px;
background-color: tomato;
}
.child:nth-child(2n) {
background-color: beige;
}
.child::after {
content:"";
}
Working Fiddle
.calendar-default{
position: relative;
height: 100px;
width: 100px;
}
.calendar-plage{
height:50%
}
<div class="calendar-default">
<div class="calendar-plage" style="background-color: red;"> </div>
<div class="calendar-plage" style="background-color: green;"> </div>
</div>

Set div to have its siblings width

I'm looking for a CSS solution to the following:-
<div style="display:inline;">
<div>The content of this div is dynamically created but will always be wider than
the below div.
</div>
<div> Need this div to have the same width as the above div.
</div>
</div>
The wrapper div has an inline display and works as expected, both child divs have dynamically generated content. I need the bottom one to take the width of the previous sibling.
Many thanks for any suggestions in advance.
Here's another Flexbox solution which allows for the second child to wrap to match the width of the variable height sibling.
.wrapper > div {
border: 1px solid;
}
.child {
display: flex;
}
.child div {
flex-grow: 1;
width: 0;
}
.wrapper {
display: inline-block;
}
<div class="wrapper">
<div>This div is dynamically sized based on its content</div>
<div class="child"><div>This div will always be the same width as the preceding div, even if its content is longer (or shorter too).</div></div>
</div>
Edit:
To support multiple divs under .child, where each div is on its own line, add break-after: always; ...
.child div {
flex-grow: 1;
width: 0;
break-after: always;
}
Floats and tables are so 2000 and late. With today's browsers we can make the two sibling DIVs match each other's width, regardless which is bigger/smaller.
Here's a Flexbox solution fit for 2016:
.wrapper {
display: inline-block;
}
.parent {
display: flex;
flex-direction: column;
}
/* For visualization */
.child {
border: 1px solid #0EA2E8;
margin: 2px;
padding: 1px 5px;
}
<div class="wrapper">
<div class="parent">
<div class="child">Child number one</div>
<div class="child">Child #2</div>
</div>
</div>
Set your div to display:inline-block instead, this way your div will expand with the content inside of it.
http://jsfiddle.net/CpKDX/
2023 keep it simple...
Use grid and the fr unit. Then you can split up into as many equally sized rows or columns as you want:
.container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 1em;
}
.container > div {
border: 1px solid black;
padding: 0.5em;
}
<div class="container">
<div>I'm a part of a grid. I will be split up into equal parts with my other sibling(s) depending on how many columns the grid is given.</div>
<div>I am a sibling element.</div>
</div>
Here is still a flexbox-based approach.
The essential idea: in an outermost wrapper, elements that need to be of equal width are wrapped into another wrapper.
.wrapper {
display: inline-block;
}
.flex-wrapper {
display: flex;
flex-direction: column;
}
.demo-bar {
height: 4px;
background-color: deepskyblue;
}
<div class="wrapper">
<div class="flex-wrapper">
<div contenteditable>Some editable text.</div>
<div class="demo-bar"></div>
</div>
</div>
Another practical example: an adaptive progress bar with the same width below a media (video or audio) element.
video.addEventListener("timeupdate", () =>
progress.style.width = `${video.currentTime / video.duration * 100}%`
)
.wrapper {
display: flex;
flex-direction: column;
position: relative;
align-items: center;
}
video {
display: block;
max-width: 100%;
}
.progress-bar {
height: 0.25rem;
background: #555;
}
#progress {
width: 0%;
height: 100%;
background-color: #595;
}
<div class="wrapper">
<div data-css-role="wrapper">
<video id="video" controls>
<source src="https://raw.githubusercontent.com/mdn/interactive-examples/master/live-examples/media/cc0-videos/flower.webm">
</video>
<div class="progress-bar">
<div id="progress"></div>
</div>
</div>
</div>
UPDATE: This works with me, I've just tried it:
<div style="max-width:980px;border:1px solid red;">
<div style="background:#EEE;float:left;">
<div style="width:auto;border:1px solid blue;float:left;">If you use 100% here, it will fit to the width of the mother div automatically.</div>
<div style="border:1px solid green;"> The div will be 100% of the mother div too.</div>
</div>
<div style="clear:both;"></div>
</div>
Is this what you want? The borders and background are just to show the divs ;)
Just go like this:
Let's say you want the whole divs be max. 980px (otherwise just leave that out or replace with 100%)...
<div style="max-width:980px;">
<div style="width:100%;">If you use 100% here, it will fit to the width of the mother div automatically.
</div>
<div style="width:100%;"> The div will be 100% of the mother div too.
</div>
</div>
The second option would be, to use one more div... or you use style="width:auto;" for the dynamic div...
Not sure if I understood what you are trying to do, but looks like setting a 100% width to the last div should work:
<div style="width:100%;">
BTW the style in the first div is not well defined, you should use a colon instead of a equal sign in the properties definition:
<div style="display:inline;">
If your willing to give up on a couple of <div>s then I have the solution for you:
<div style=“display: inline-block;”>
<table>
<tr>
<td>The table automatically makes its siblings the same width</td>
</tr>
<tr>
<td>So this will be as wide</td>
</tr>
</table>
</div>
Remember to set the div display:inline-block;