Aligning child items in a list of flex parents - css

I am trying to do a very simple two-column layout that is giving me a hard time. I am still learning the art of flex layout so I'm sure there is something simple that I'm missing. I want a vertical list of <div>s, each of which is a flexbox with two child <div>s. The width of first child varies based on content. The second child is flex-grow: 1, and I want those items to left-align across the set of parents. Instead, the first child is sized to content, and the second butts up against it on the right.
#resultsList {
display: flex;
flex-direction: column;
}
.result {
display: flex;
align-items: flex-start;
justify-content: flex-start;
}
.result-text {
flex: 1;
}
<div id="resultsList">
<div class="result">
<div class="result-line">Line 147</div>
<div class="result-text">Blah blah</div>
</div>
<div class="result">
<div class="result-line">Line 223</div>
<div class="result-text">Resukt 2</div>
</div>
<div class="result">
<div class="result-line">Line 445</div>
<div class="result-text">Quick brown fox</div>
</div>
</div>
I have tried many combinations of align, justify, etc. but I always get the same (or a worse) result.

Okay so:
I think is this what you mean right?
There's a lot of flex going on here so the basic principles are:
main-container holds everything, displaying it as flex. Fixed width of 600px.
sub-container is each flex item, being display as column.
first-container is a fixed width (in this case: 150px) and flex-grow: 1;
content does not have a flex grow property, and so is only the width of its content.
padder has a flex-grow property, so it will take up the rest of the remaining space.
second-container takes up the rest of the container.
The rest is just the use of borders. Where applicable you can make border-{top|bottom|left|right} to none, so it appears as if the box is extended out. Try using the chrome dev tools to see the width of each component.
.main-container {
width: 600px;
display: flex;
flex-direction: column;
}
.sub-container {
display: flex;
}
.first-container {
border: 1px solid black;
border-right: none;
flex-grow: 1;
display: flex;
max-width: 150px;
}
.content {
border-right: 1px solid black;
padding: 10px;
}
.padder {
flex-grow: 1;
}
.second-container {
border: 1px solid black;
border-left: none;
flex-grow: 2;
padding: 10px;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css">
</head>
<body>
<div class="main-container">
<div class="sub-container">
<div class="first-container">
<div class="content">
<p>text</p>
</div>
<div class="padder"></div>
</div>
<div class="second-container">
<p>text</p>
</div>
</div>
<div class="sub-container">
<div class="first-container">
<div class="content">
<p>sample text</p>
</div>
<div class="padder"></div>
</div>
<div class="second-container">
<p>text</p>
</div>
</div>
<div class="sub-container">
<div class="first-container">
<div class="content">
<p>more sample text</p>
</div>
<div class="padder"></div>
</div>
<div class="second-container">
<p>text</p>
</div>
</div>
</div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>

Related

How to make html elements flow like text

Given I have two (or more) elements, ーlet's use div but they can be span or anything...ー I want the second one to be appended to the first one the same way it would happen with text.
HTML:
<div>First element taking space</div> <div>Second element</div>
What I want:
//<------ 1. parent width big enough -------->
First element taking space Second element
//<---- 2. bit smaller width ------>
First element taking space Second
element
//<- 3. even smaller ->
First element taking
space Second element
What it happens
//<------ 1. parent width big enough -------->
First element taking space Second element
//<---- 2. bit smaller width ------>
First element taking space // even if there's space for the "Second" word in
Second element // the 1st line it starts in the next line
//<- 3. even smaller ->
First element taking // even if there's space for the "Second element" full text
space // it starts in a new line
Second element
This is probably due to the "box" assigned to each element, behaving like this
╔══════════════════════╗
║╔════════════════════╗║
║║First element taking║║
║║space ║║
║╚════════════════════╝║
║╔══════════════╗ ║
║║Second element║ ║
║╚══════════════╝ ║
╚══════════════════════╝
I tried playing with display options (inline, inline-block, flex), white-space (wrap, pre-wrap)... but can't make it work as I want.
Note: the pre-wrap is because I want to preserve spaces as well.
Edit: Added the following snippet with current code:
.root {
display: flex;
align-items: flex-end;
flex-wrap: wrap;
background: pink;
}
.prefix {
white-space: pre-wrap;
}
.text {
white-space: pre-wrap;
}
.colored {
background: red;
}
.big { width: 500px; }
.small { width: 320px; }
.smaller { width: 150px; }
<div class="root">
<div class="prefix">1.> </div>
<div class="text">this is some text of arbitrary width </div>
<div class="text colored">colored text</div>
<div class="text"> more text</div>
</div>
<hr/>
<div class="root small">
<div class="prefix">2.> </div>
<div class="text">this is some text of arbitrary width </div>
<div class="text colored">colored text</div>
<div class="text"> more text</div>
</div>
<hr/>
<div class="root smaller">
<div class="prefix">3.> </div>
<div class="text">this is some text of arbitrary width </div>
<div class="text colored">colored text</div>
<div class="text"> more text</div>
</div>
The solution was very simple and stupid to the point I'm embarrassed: Just use inline elements.
Leaving it here as well in case anyone learning needs it...
.root {
background: pink;
}
.prefix {
display: inline; /* not needed if using native inline tags such as <span> */
white-space: pre-wrap;
}
.text {
display: inline; /* not needed if using native inline tags such as <span> */
white-space: pre-wrap;
}
.colored {
display: inline; /* not needed if using native inline tags such as <span> */
background: red;
}
.big { width: 500px; }
.small { width: 320px; }
.smaller { width: 150px; }
<div class="root">
<div class="prefix">1.> </div>
<div class="text">this is some text of arbitrary width </div>
<div class="text colored">colored text</div>
<div class="text"> more text</div>
</div>
<hr/>
<div class="root small">
<div class="prefix">2.> </div>
<div class="text">this is some text of arbitrary width </div>
<div class="text colored">colored text</div>
<div class="text"> more text</div>
</div>
<hr/>
<div class="root smaller">
<div class="prefix">3.> </div>
<div class="text">this is some text of arbitrary width </div>
<div class="text colored">colored text</div>
<div class="text"> more text</div>
</div>
I don't know if I understood you correctly but I think flexbox would solve your problem, take a look at the snippet below:
.container{
display:flex;
justify-content: center;
align-items: center;
height:100vh;
flex-direction: row;
}
.first-box{
width:auto;
height:auto;
display:flex;
justify-content: center;
align-items: center;
background-color: yellowgreen;
}
.second-box{
width:auto;
height:auto;
display:flex;
justify-content: center;
align-items: center;
background-color: tomato;
}
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<div class="container">
<div class="first-box">This is some text.</div>
<div class="second-box">This is some text but in the second div which has a tomato background-color.</div>
</div>

How can I have auto-width content in flexbox without destroying the layout? (take as much space as necessary and as little space as possible)

I have an example on JSFiddle on how I want to solve my issue with flexbox: I want the left column to fit the width accordingly to the content - break a line if the text is too long. Unfortunately it always takes as little space as possible, which results in breaking the layout.
I have a fiddle below, first you see two blocks with how it looks now, below you see 2 blocks how I want it to look like (I've defined fixed width for visual reasons, but I want it to be dynamically with flexbox, obviously).
I'm pretty sure I can do this easily but I can't see the wood for the trees. Any kind of help is highly appreciated :)
.flex {
display: flex;
background: #333;
max-width: 380px;
}
.first {
flex: 0;
background: #666;
}
.second {
flex: 1;
background: #999;
}
<p>How it looks like with my flexbox approach</p>
<div class="flex">
<div class="first">
Here is my Dynamic Text
</div>
<div class="second">
Next to Text
</div>
</div>
<br />
<div class="flex">
<div class="first">
Here is my Dynamic Text Here is my Dynamic Text
</div>
<div class="second">
Next to Text
</div>
</div>
<hr />
<p>How it should look like</p>
<!-- Ignore all code below, please - everything below is just here for visual reasons -->
<div>
<div style="background: #666; width: 165px; float: left;">Here is my Dynamic Text</div>
<div style="background: #999; float: left;">Next to text</div>
</div>
<div style="clear: both; height: 10px;">
</div>
<div>
<div style="background: #666; width: 302px; float: left;">Here is my Dynamic Text Here is my Dynamic Text</div>
<div style="background: #999;float: left; height: 36px;">Next to text</div>
</div>
Use white-space:nowrap on the second element so it does not collapse.
.flex {
display: flex;
border: 1px solid green;
}
.first {
background: lightblue;
border: 1px solid grey;
}
.second {
white-space: nowrap;
background: lightgreen
}
.narrow {
width: 50%;
<div class="flex">
<div class="first">
Here is my Dynamic Text
</div>
<div class="second">
Next to Text
</div>
</div>
<hr/>
<div class="flex narrow">
<div class="first">
Here is my Dynamic Text Here is my Dynamic Text
</div>
<div class="second">
Next to Text
</div>
</div>

Changing the order of Columns when page loads from desktop to mobile responsive layout

In the below given layout,
When the width of page is lowered than 600px, I want to place Column2 above Column1
I tried using display: flex; flex-direction: column-reverse; but it instead of reversing the order of column it reversed the content order of the column.
Here is snippet.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
box-sizing: border-box;
}
/* Create two equal columns that floats next to each other */
.column {
float: left;
width: 50%;
padding: 10px;
height: 300px; /* Should be removed. Only for demonstration */
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
/* Responsive layout - makes the two columns stack on top of each other instead of next to each other */
#media screen and (max-width: 600px) {
.column {
width: 100%;
/**Uncommenting below will lead to content of column reversed and not the order of column reversed**/
/*display: flex;
flex-direction: column-reverse;*/
}
}
</style>
</head>
<body>
<h2>Responsive Two Column Layout</h2>
<p>Resize the browser window to see the responsive effect (the columns will stack on top of each other instead of floating next to each other, when the screen is less than 600px wide).</p>
<div class="row" style="height: 20px; background-color: red;">
</div>
<div class="row" style="height: 20px; background-color: blue;">
</div>
<div class="row">
<div class="column" style="background-color:#aaa;">
<div class="cls1">
<h2>Column 1</h2>
<p>Some text..</p>
</div>
<div class="cls2">
<h2>Column 1.2</h2>
<p>Some text..</p>
</div>
<div class="cls3">
<h2>Column 1.3</h2>
<p>Some text..</p>
</div>
</div>
<div class="column" style="background-color:#bbb;">
<h2>Column 2</h2>
<p>Some text..</p>
</div>
</div>
</body>
</html>
Any help will be appreciative.
You tried adding display:flex to the column - which made the column a flex container and elements inside of it his flex items. That's why you were reversing content inside the columns and not the columns themselves. You want to instead control columns inside the row. To do that, you need to make the row your flex container (apply display:flex to the row instead of the column). Here is a working CSS for your case:
.row {
display: flex; // makes the row a flex container
}
#media screen and (max-width: 600px) {
.row {
flex-direction: column-reverse;
}
}
.column {
flex-grow: 1; // makes all columns fill the width of the row equally
padding: 0 10px;
}
Here is the correct implementation with working example based on Accepted answer of #ajobi:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
box-sizing: border-box;
}
/* Create two equal columns that floats next to each other */
.column {
float: left;
width: 50%;
padding: 10px;
height: 300px; /* Should be removed. Only for demonstration */
}
.row {
display: flex; // makes the row a flex container
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
/* Responsive layout - makes the two columns stack on top of each other instead of next to each other */
#media screen and (max-width: 600px) {
.row {
flex-direction: column-reverse;
}
.column {
width: 100%;
/**Uncommenting below will lead to content of column reversed and not the order of column reversed**/
/*display: flex;
flex-direction: column-reverse;*/
}
}
</style>
</head>
<body>
<h2>Responsive Two Column Layout</h2>
<p>Resize the browser window to see the responsive effect (the columns will stack on top of each other instead of floating next to each other, when the screen is less than 600px wide).</p>
<div class="row" style="height: 20px; background-color: red;">
</div>
<div class="row" style="height: 20px; background-color: blue;">
</div>
<div class="row">
<div class="column" style="background-color:#aaa;">
<div class="cls1">
<h2>Column 1</h2>
<p>Some text..</p>
</div>
<div class="cls2">
<h2>Column 1.2</h2>
<p>Some text..</p>
</div>
<div class="cls3">
<h2>Column 1.3</h2>
<p>Some text..</p>
</div>
</div>
<div class="column" style="background-color:#bbb;">
<h2>Column 2</h2>
<p>Some text..</p>
</div>
</div>
</body>
</html>

How to align an element at the bottom of this variable size flex element

In this jsfiddle, I want the Author element to be aligned between the various card elements. I can't see how to stretch the element containing the details to match the variably sized elements in the same row.
The goal is to have the Author lines lining up horizontally across the rows.
.container {
display: flex;
flex-flow: row wrap;
margin: 10px;
}
.card {
width: 200px;
margin: 10px;
}
.product_detail {
display: flex;
flex-direction: column;
justify-content: space-between;
border: 1px solid pink;
}
.detail_item {
border: 1px solid blue;
flex: 1;
}
img {
width: 100%;
}
<div class='container'>
<div class="card">
<section>
<img src="https://c.booko.info/covers/34edd12eb5c21388/v/600.jpeg" itemprop="image" size="500x750">
</section>
<section class="product_detail">
<div itemprop="name" class='detail_item'>
A Book Title
</div>
<div class="detail_item">A Subtitle might be here</div>
<div itemprop="author" class='detail_item'>Author</div>
</section>
</div>
<div class="card">
<section>
<img src="https://c.booko.info/covers/34edd12eb5c21388/v/600.jpeg" itemprop="image" size="500x750">
</section>
<section class="product_detail">
<div itemprop="name" class='detail_item'>
A Book Title which is much longer and takes up a few lines
</div>
<div class="detail_item">A Subtitle might be here</div>
<div itemprop="author" class='detail_item'>Author</div>
</section>
</div>
<div class="card">
<section>
<img src="https://c.booko.info/covers/34edd12eb5c21388/v/600.jpeg" itemprop="image" size="500x750">
</section>
<section class="product_detail">
<div itemprop="name" class='detail_item'>
A Book Title
</div>
<div class="detail_item">A Subtitle might be here</div>
<div itemprop="author" class='detail_item'>Author</div>
</section>
</div>
</div>
As I understood it, you are trying to have the Author div anchored to the bottom of each card.
Assuming I understood correctly, you were pretty close. Here's what was missing:
the .card div needed to be a flex container
the .product_detail section needed to stretch to fill its available space
the Author div needed to be anchored to the bottom
Here's the CSS that changed:
.card {
display: flex;
flex-direction: column;
}
.product_detail {
flex: 1;
}
.detail_item[itemprop="author"] {
margin-top: auto;
}
Here's an updated Fiddle
Note: if you don't want the .detail_item divs to be vertically evenly distributed, you can just remove the flex: 1; property from .detail_item which would look like this.
Hope this helps. Good luck!

Centered grid of dynamic cards (divs) with more block elements inside

I want a dynamically generated grid of fixed size cards to be horizontally centered in a container of variable width, basically this: https://foodgawker.com/
My question is similar to Center a grid of Divs (dynamically generated) or How to center a grid of divs? (the example is from there), except they both recomend using display: inline-block instead of float : left, which only works as long as there are no further block elements inside the cards.
Here is the example from the previous question with one block element added inside the card, the whole layout breaks: http://jsbin.com/vozusukigo/1/edit?html,css,output. Also the foodgawker.com uses float : left, not display: inline-block.
Here is a JS Bin for your convenience, I am grateful for any help.
EDIT: The last row should aligned to left as in the example. To my horror the accepted answer to similar question uses JQuery (and none of the flexbox answers have fixed size gaps).
These kinda solutions especially are made easy now thanks to the Flexbox concept in CSS3.
https://jsbin.com/vetanocaxi/1/edit?html,css,output
Having the same HTML, the CSS can be written as below
.ct {
background-color : #ffff00;
display: flex;
justify-content: flex-start; /* center if you want to the center */
align-items: center;
flex-wrap: wrap;
}
.el {
width : 50px;
height : 50px;
background-color : #ff9999;
margin : 5px;
display: flex;
justify-content: center; /* center inside flex items */
align-items: center; /* center inside flex items */
}
No floats required & even better you can easily have complex structure within individual flex items without effecting the outer layout structure.
.ct {
background-color : #ffff00;
display: flex;
justify-content: flex-start; /* center if you want to the center */
align-items: center;
flex-wrap: wrap;
}
.el {
width : 50px;
height : 50px;
background-color : #ff9999;
margin : 5px;
display: flex;
justify-content: center; /* center inside flex items */
align-items: center; /* center inside flex items */
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="ct">
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
<div class="el"><p>flex</p></div>
</div>
</body>
</html>
Flexbox can be used to achieve this effect like this: http://jsbin.com/vunubuqobo/edit?html,css,output
Main assumption is a fixed width for all cards. A small nuisance is a bunch of media queries to set .center_wrapper's width right, but that is easy to overcome with Less/SCSS/etc.
Note: use jsbin link above to check out responsiveness.
.cards_wrapper {
background: red;
}
#media(min-width: 122px) {
.center_wrapper { width: 122px; }
}
#media(min-width: 296px) {
.center_wrapper { width: 244px; }
}
#media(min-width: 416px) {
.center_wrapper { width: 366px; }
}
#media(min-width: 524px) {
.center_wrapper { width: 488px; }
}
#media(min-width: 646px) {
.center_wrapper { width: 610px; }
}
.center_wrapper {
display: flex;
flex-wrap: wrap;
padding: 10px;
margin: 0 auto;
background: yellow;
}
.card {
height: 100px;
width: 100px;
border: 1px solid;
margin: 10px;
text-align: center;
}
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<div class="cards_wrapper">
<div class="center_wrapper">
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<p>block element</p>
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
<div class="card">
<img src="./Index - My ASP.NET MVC Application_files/noImageAvailable.png">
</div>
</div>
</div>
</body>
</html>
To be honest I can't see any problem by using display: inline-block and have block elements inside the repeating divs. Also aligning the last row to the left is simple and doesn't require a single line of JavaScript or any complex workarounds.
According to the link you have posted you could achieve the layout with the following HTML structure and CSS code
body {
background: #eee;
}
#wrapper {
font-size: 0;
padding: 10px 0;
}
.item {
width: calc(25% - 4px);
background: white;
overflow: hidden;
border-radius: 3px;
display: inline-block;
font-size: initial;
margin: 2px;
}
p {
padding: 4px 20px;
}
img {
width: 100%;
}
<div id="wrapper">
<div class="item">
<img src="https://photo.foodgawker.com/wp-content/uploads/2016/12/2845923.jpg" alt="" />
<p>All the nutty deliciousness of pecan pies - these no bake Rice Krispie Pecan Pie Cookies are vegan-friendly & dairy-free friendly!</p>
</div>
<div class="item">
<img src="https://photo2.foodgawker.com/wp-content/uploads/2016/12/2845735.jpg" alt="" />
<p>This Barbecue Chicken Cornbread Casserole is an easy dinner that comes together in just 15 minutes!!</p>
</div>
<div class="item">
<img src="https://photo.foodgawker.com/wp-content/uploads/2016/12/2845542.jpg" alt="" />
<p>Vegan Meringue Kisses, made using aquafaba</p>
</div>
<div class="item">
<img src="https://photo2.foodgawker.com/wp-content/uploads/2016/12/2845725.jpg" alt="" />
<p>Healthy spicy creole pulled pork made in the slow cooker! {Gluten Free, Dairy Free, Paleo}</p>
</div>
<div class="item">
<img src="https://photo.foodgawker.com/wp-content/uploads/2016/12/2845855.jpg" alt="" />
<p>Praline chocolates with a crispy dark chocolate coating and a soft caramelized nuts filling. Chocolatey, nutty and insanely delicious!</p>
</div>
</div>

Resources