How to correctly align these elements with flexbox? - html

Sorry for the really vague question title but I have no idea how to best describe it...
Take the following code example:
.wrapper {
border: 2px solid green;
}
.container {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border: 2px solid red;
margin: 5px;
height: 64px;
}
.item {
display: flex;
border: 2px solid #0000ff;
padding: 3px;
}
.left {
justify-content: flex-end;
}
.right {
justify-content: flex-start;
}
<div class="wrapper" style="width: 100%">
<div class="container">
<div class="item left">FIXED</div>
<div class="item right">abc</div>
</div>
<div class="container">
<div class="item">FIXED</div>
</div>
<div class="container">
<div class="item left">FIXED</div>
<div class="item right">abcdefgh</div>
</div>
</div>
<br />
<div class="wrapper" style="width: 50%">
<div class="container">
<div class="item left">FIXED</div>
<div class="item right">abc</div>
</div>
<div class="container">
<div class="item">FIXED</div>
</div>
<div class="container">
<div class="item left">FIXED</div>
<div class="item right">abcdefgh</div>
</div>
</div>
Observations:
FIXED represents an element of fixed size, always same width/height.
The right side element can vary on size (mostly width).
The right side element is always aligned to the left.
The left side element is always aligned to the left.
What I'm trying to achieve:
The FIXED element should always be centered on the red row.
THE FIXED element on the first/third rows needs to be aligned to the right side of the FIXED element on the second row.
Here's an image to better demonstrate what I'm looking for:
EDIT: My final solution based on the #vals answer. I had to change this a bit because I'm using CSS Modules with selector composition in a React app and I need a single class per element.
.container {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
/* UNREQUIRED (FOR DEMONSTRATION ONLY) */
border: 2px solid red;
padding: 5px;
}
.container::before {
content: "";
flex: 1 0 14px; /* UNREQUIRED (FOR DEMONSTRATION ONLY) (14px -> 0) */
}
.container-single {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
/* UNREQUIRED (FOR DEMONSTRATION ONLY) */
border: 2px solid red;
padding: 5px;
}
.item {
display: flex;
flex: 0 0 auto;
/* UNREQUIRED (FOR DEMONSTRATION ONLY) */
border: 2px solid #0000ff;
padding: 5px;
}
.item-right {
display: flex;
flex: 1 0 0;
/* UNREQUIRED (FOR DEMONSTRATION ONLY) */
border: 2px solid #0000ff;
padding: 5px;
}
.item-left {
display: flex;
flex: 0 0 auto;
margin-left: auto;
/* UNREQUIRED (FOR DEMONSTRATION ONLY) */
border: 2px solid #0000ff;
padding: 5px;
}
<div class="container">
<div class="item-left">FIXED</div>
<div class="item-right">abc</div>
</div>
<br />
<div class="container-single">
<div class="item">FIXED</div>
</div>
<br />
<div class="container">
<div class="item-left">FIXED</div>
<div class="item-right">abcdefgh</div>
</div>
For anyone interested, the CSS selector composition goes like this:
.container {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.container::before {
flex: 1 0 0;
content: "";
}
.container-single {
composes: container;
}
.item {
display: flex;
flex: 0 0 auto;
}
.item-right {
flex: 1 0 0;
composes: item;
}
.item-left {
margin-left: auto;
composes: item;
}

I have changed the layout slighty, I have add a class on the single container.
Is it ok for the right element to grow ?
.container {
display: flex;
flex-direction: row;
border: 2px solid red;
padding: 5px;
}
.item {
display: flex;
flex-basis: auto;
flex-grow: 0;
border: 2px solid #0000ff;
padding: 5px;
}
.item.right {
flex-basis: 0;
flex-grow: 1;
}
.item.left {
margin-left: auto;
}
.container:not(.single):before {
content: "";
flex-basis: 14px; /* border 2px + padding 5px */
flex-grow: 1;
}
.single .item {
margin: 0px auto;
}
<div class="container">
<div class="item left">FIXED</div>
<div class="item right">abc</div>
</div>
<br />
<div class="container single">
<div class="item">FIXED</div>
</div>
<br />
<div class="container">
<div class="item left">FIXED</div>
<div class="item right">abcdefgh</div>
</div>

Related

Trying to modify the width of the columns in this flexbox

I am trying to render rows with the date on the left and some text on the right.
I cant seem to work out how I changed the widths of the columns though?
Currently my day and text column are the same width.
I'd like to have the day as 50px and the text as 300px.
Is it possible with this code?
.sb-flex-row {
flex-direction: row;
display: flex;
}
.sb-flex-column {
flex-direction: column;
display: flex;
}
.sb-flex-body {
display: flex;
}
.sb-flex-body div:not([class*="flex"]) {
border: 1px solid white;
flex: 1 1 50px;
width: 200px;
}
<div class="sb-flex-body">
<div class="sb-flex-row">
<div style="background: #0980cc;">day</div>
</div>
<div class="sb-flex-column">
<div style="background: #09cc69;">month</div>
<div style="background: #cc092f;">year</div>
</div>
<div class="sb-flex-row">
<div style="background: #0980cc;">text</div>
</div>
</div>
I cleaned up and make it maybe simpler for you to understand. You have an outer wrapper that is flexible. The default direction is row and that is ok. Then you have two blocks. one block dateBlock and the second is a text block. the dateblock contains two blocks (a,b). and b you can assign the direction to the column. Afterward, you can assign the width to the text block and Dateblock. That is it :-)
.wrapper {
display: flex;
gap:10px;
}
.dateBlock {
display: flex;
background: yellow;
gap: 20px;
padding: 10px;
box-sizing: border-box;
}
.textBlock {
background: green;
padding: 10px;
box-sizing: border-box;
width: 300px;
}
.monthYear {
display: flex;
flex-direction: column;
width:50px;
}
.day {
font-size: 30px;
width: 50px;
}
<div class="wrapper">
<div class="dateBlock">
<div class="day">day</div>
<div class="monthYear">
<div>month</div>
<div>year</div>
</div>
</div>
<div class="textBlock">text</div>
</div>
I rearranged your markup a bit to easily target these divs in the style sheet. You can see the changes I made to your CSS under /* changes */. Also, take note of the HTML I adjusted.
.sb-flex-row {
flex-direction: row;
display: flex;
}
.sb-flex-column {
flex-direction: column;
display: flex;
}
.sb-flex-body {
display: flex;
}
/* changes */
.sb-flex-body div:not([class*="flex"]) {
border: 1px solid white;
width: 50px;
}
.sb-flex-row > div {
min-width: 300px;
}
<div class="sb-flex-body">
<div class="sb-flex-column">
<div style="background: #0980cc;">day</div>
<div style="background: #09cc69;">month</div>
<div style="background: #cc092f;">year</div>
</div>
<div class="sb-flex-row">
<div style="background: #0980cc;">text</div>
</div>
</div>

How to apply flex-grow?

I'm trying to create a flex row with a growth of 2 and then a wrap but can't understand why it is not working properly.
Here is the CSS and HTML.
.flex {
height: 50px;
width: 50px;
background-color: black;
}
.flex1 {
height: 50px;
width: 50px;
background-color: yellow;
margin-left: 50px;
}
.flex2 {
height: 50px;
width: 50px;
background-color: green;
margin-left: 50px;
}
.flexcontainer {
display: flex;
flex-wrap: wrap;
flex-grow: 2;
flex-direction: row;
}
<div class="flexcontainer">
<div class="flex">
<div class="flex1">
<div class="flex2">
</div>
</div>
</div>
</div>
The way you implement the flex-grow is totally wrong because the flex-grow have to be applied to child elements as shown in below code snippet as a example.
#content {
display: flex;
justify-content: space-around;
flex-flow: row wrap;
align-items: stretch;
}
.box {
flex-grow: 1;
border: 3px solid rgba(0,0,0,.2);
}
.box1 {
flex-grow: 2;
border: 3px solid rgba(0,0,0,.2);
}
<h4>This is a Flex-Grow</h4>
<div id="content">
<div class="box" style="background-color:red;">A</div>
<div class="box" style="background-color:lightblue;">B</div>
<div class="box" style="background-color:yellow;">C</div>
<div class="box1" style="background-color:brown;">D</div>
<div class="box1" style="background-color:lightgreen;">E</div>
<div class="box" style="background-color:brown;">F</div>
</div>
To read more about flex-grow, you should learn from there : https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow

How to make flex item height of its parent?

I have a simple nav type layout using flex to space items with different widths horizontally. The items have lines between but as they different heights because the content had different heights
How can I make the items the height of the parent so all dividing lines go to the top of the parent.
https://codepen.io/anon/pen/zbEMVd
* {
font-family: sans-serif;
}
.wrap {
border: 1px solid grey;
display: flex;
padding: 5px;
justify-content: space-between;
max-width: 1200px;
}
.item:not(:last-of-type) {
border-right: 2px solid red;
}
.item-1 {
width: 150px;
}
.item-2 {
width: 50px;
}
.item-3 {
width: 50px;
}
.item-4 {
width: 50px;
}
.item-5 {
flex: 1;
}
.item-6 {
width: 50px;
}
<div class="wrap">
<div class="item item-1">One</div>
<div class="item item-2">Two Two Two Two Two </div>
<div class="item item-3">Three Three Three</div>
<div class="item item-4">Four</div>
<div class="item item-5">Five</div>
<div class="item item-6">Six</div>
</div>
Remove align-self from .item, and add display:flex; align-items: flex-end; instead.
.item{
display: flex;
align-items: flex-end;
/* ... */
}
https://codepen.io/anon/pen/ZPXVra
Make the item element a reverse-column flexbox (and remove align-self: flex-end from it) to get the effect - see demo below:
* {
font-family: sans-serif;
}
.wrap {
border: 1px solid grey;
display: flex;
padding: 5px;
justify-content: space-between;
max-width: 1200px;
}
.item {
/* align-self: flex-end; */
display: flex; /* ADDED */
flex-direction: column-reverse; /* ADDED */
background: #ddd;
}
.item:not(:last-of-type) {
border-right: 2px solid red;
}
.item-1 {
width: 150px;
}
.item-2 {
width: 50px;
}
.item-3 {
width: 50px;
}
.item-4 {
width: 50px;
}
.item-5 {
flex: 1;
}
.item-6 {
width: 50px;
}
<div class="wrap">
<div class="item item-1">One</div>
<div class="item item-2">Two Two Two Two Two </div>
<div class="item item-3">Three Three Three</div>
<div class="item item-4">Four</div>
<div class="item item-5">Five</div>
<div class="item item-6">Six</div>
</div>

Creating divs that have a width of the top div in a foreach

so I have a goal but I have no idea if it's possible or not:
Here's an image of what i got: https://screencast.com/t/88ImEmMif
And code:
<style type="text/css">
#contrainer {
width: 100%;
}
#main {
width: 600px;
margin:0 auto;
}
.wrapper {
display: inline-block;
}
.parent {
flex-direction: column;
}
.child {
border: 1px solid #0EA2E8;
margin: 2px;
padding: 5px;
display: inline-block;
}
</style>
<div id="container">
<div id="main">
<div class="anchors">
<div class="wrapper">
<div class="parent">
<?php
$links = array("https://google.com","foo", "bar", "hello", "world","google.com","google.com/adwords/","foo", "bar", "hello", "world","https://google.com/gmail","https://google.com/adwords/");
foreach($links as $link) {
echo '<div class="child">'.$link.'</div>';
}
?>
</div>
</div>
</div>
</div>
</div>
And here is what I'm looking to do: https://screencast.com/t/ze5fCya3wpbJ
So each of the boxes will have the same width in col's depending on the length in the box.
You could give a try to flex setting a fixed height:
example using lorem ipsum text. (your pHp is not the HTML output)
div {/* your .parent */
display: flex;
height: 4em;/* makes about 2 lines before wrapping to next */
flex-direction: column;
flex-wrap: wrap;
width: 500px;
margin: auto;
}
b {/* your .child */
border: solid 1px turquoise;
margin: 2px;
padding:2px;
}
<div>
<b>lorem</b>
<b>Pellentesque</b>
<b>habitant</b>
<b>morbi</b>
<b>tristique</b>
<b>senectus</b>
<b>et</b>
<b>netus</b>
<b>et</b>
<b>malesuada</b>
<b>fames</b>
<b>ac</b>
<b>turpis</b>
<b>egestas.</b>
</div>
An alternative would be using FlexBox on the outer div, applying the styles flex-wrap: wrap; and justify-content: space-between; to make them evenly spaced and distributed inside the outer div. Thanks to FlexBox each of the inner contents will have their own width.
.box {
width: 600px;
margin:0 auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
p {
margin: 0 0 5px;
padding: 3px 5px;
border: 1px solid black;
}
<div class="box">
<p>Bulbasaur</p>
<p>Ivysaur</p>
<p>Venusaur</p>
<p>Charmander</p>
<p>Charmeleon</p>
<p>Ash</p>
<p>Charizard</p>
<p>Squirtle</p>
<p>Wartortle</p>
<p>Blastoise</p>
<p>Ekans</p>
<p>Pikachu</p>
<p>Paras</p>
<p>Abra</p>
</div>

How to override flexbox justify-content: space-between?

Is it possible to override space-between so that the last item would horizontally align to the next to last? Or should I just drop space-between and go with flex-start and custom margins?
JSfiddle Demo
.wrapper {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-start;
justify-content: space-between;
width: 300px;
margin: 30px auto;
padding: 0;
box-sizing: border-box;
position: relative;
}
.item {
width: 90px;
height: 90px;
background-color: #111;
margin-bottom: 10px;
}
.next-to-last {
background-color: blue;
}
.last-item {
background-color: red;
}
<div class="wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item next-to-last"></div>
<div class="item last-item"></div>
</div>
Fake element method:
You can add a fake element for the 4th item so that 5 and 6 are next to each other.
This will work if you use visibility: hidden to hide the element and preserve the space occupied by it. The common alternative display: none will not work since the item is not calculated in the flexbox alignment.
.wrapper {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-start;
justify-content: space-between;
width: 300px;
margin: 30px auto;
padding: 0;
box-sizing: border-box;
position: relative;
}
.item {
width: 90px;
height: 90px;
background-color: #111;
margin-bottom: 10px;
}
.next-to-last {
background-color: blue;
}
.last-item {
background-color: red;
}
.invisible {
visibility: hidden;
}
<div class="wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item invisible"></div> <!-- Invisible fake element -->
<div class="item next-to-last"></div>
<div class="item last-item"></div>
</div>
Custom margin method:
If you don't want to create an additional element then you need to use your own suggestion of flex-start and custom margin.
.wrapper {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-start;
justify-content: flex-start;
width: 300px;
margin: 30px auto;
padding: 0;
box-sizing: border-box;
position: relative;
}
.item {
width: 90px;
height: 90px;
background-color: #111;
margin-bottom: 10px;
margin-right: 10px;
}
.next-to-last {
background-color: blue;
margin-left: 100px;
}
.last-item {
background-color: red;
}
<div class="wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item next-to-last"></div>
<div class="item last-item"></div>
</div>