How to make html elements flow like text - css

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>

Related

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!

Aligning child items in a list of flex parents

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>

Div to expand vertically, but be scrollable if it has filled its container

UPDATE:
I made a fiddle for testing.
An illustration of what I'd like to achieve: (Rows and columns are Bootstrap 4 rows and columns.)
The page should only have scrollbars if the second row is already
"fully compressed" (0 height) and still the header + first row +
footer can't fit in the viewport.
The second row doesn't have to fill
in all remaining pale green place. It's height can be flexible.
Flexbox? Max-width? Overflow... How should I start? What could be a good solution?
HTML:
<div class="page">
<div class="header">
...<br>...
</div>
<div class="main">
<div class="container-fluid">
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body"> .... </div>
</div>
</div>
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body"> .... </div>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body scrollable"> THIS <br> SHOULD <br> BE <br> THE <br> SCROLLABLE <br> CONTENT </div>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
...
</div>
</div>
CSS:
div.page {
background-color: palegreen;
display: flex;
flex-direction: column;
min-height: 100vh;
max-height: 100vh;
}
div.header,
div.footer {
background-color: grey;
padding: 0.5em;
}
div.main {
display: flex;
flex-grow: 1;
}
div.row {
margin-top: 1em;
}
div.scrollable {
/* ??? */
}
The key is how you calculate the height for the <main> and usage of flex, esp. flex-grow, flex-shrink.
<header>, <main> and <footer>
The second row doesn't have to fill in all remaining pale green place. It's height can be flexible.
So I assume you want the <header> and <footer> always stay on top and bottom. Instead of regular absolute positioning approach, I want to explicitly set the heights for them, as well as for <main>.
HTML
<header>header</header>
<main class="container-fluid"></main>
<footer>footer</footer>
SCSS
$custom-header-height: 3rem;
$custom-footer-height: 2rem;
header, footer {
background-color: var(--gray);
// In order to position the text to the center, like your picture
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
}
header {
height: $custom-header-height;
}
footer {
height: $custom-footer-height;
}
main {
// Calculate the height for main, which is 100% viewport height -
// height of header - height of footer
height: calc(100vh - #{$custom-header-height} - #{$custom-footer-height});
background-color: var(--teal);
}
Result
This gives you the playground you can build stuff on.
First Row
The first row is free to expand as high as its contents, but you don't want it to take up any free space. That's why you set flex-grow: 0;. Also when you resize the window and the space for first row is shrinking, you don't want the cards go over the row. That's why you set flex-shrink: 0;. We might as well use the shortcut flex: 0 0 auto; for those 2.
But in order to set that, the first row (as well as the second row) needs to be flexbox children. So we set display:flex; on its parent - <main>.
HTML
<header>header</header>
<main class="container-fluid">
<div class="row first-row">
<div class="col-6">
<div class="card">...</div>
</div>
<div class="col-6">
<div class="card">...</div>
</div>
</div>
</main>
<footer>footer</footer>
SCSS (In addition)
main {
display: flex;
flex-flow: column nowrap;
}
.first-row {
// I purposely make first row's background yellow so that you can see it
background-color: var(--yellow);
flex: 0 0 auto;
}
Result
Second Row
The key here is to make the <card> not to grow when there is space, but shrink on limited space, which is the default of flexbox children: flex: 0 1 auto;
But again, in order to use that, its parent needs to display: flex;. Here the parent is col-6 since we want to use bootstrap grid system.
HTML
<header>header</header>
<main class="container-fluid">
<div class="row first-row">
<div class="col-6">
<div class="card">...</div>
</div>
<div class="col-6">
<div class="card">...</div>
</div>
</div>
<div class="row second-row">
<div class="col-6">
<div class="card">
...
...
...
</div>
</div>
</div>
</main>
<footer>footer</footer>
SCSS (In addition)
.second-row {
// I purposely make second row's background to be blue so that you can see it
background-color: var(--blue);
// Any column, class name starts as "col-"
[class*="col-"] {
display: flex;
flex-flow: column nowrap;
// So that when the second row is compressed to 0, it doesn't show
// the row completely.
min-height: 0;
.card {
// flex-grow: 0;
// flex-shrink: 1;
// Might as well just set it
// flex: 0 1 auto;
// But this is the default of flexbox children so we don't need to set
// it here.
.card-body {
overflow-y: auto;
}
}
}
}
Result
The second row doesn't have to fill in all remaining pale green place. It's height can be flexible.
An illustration of what I'd like to achieve
The page should only have scrollbars if the second row is already "fully compressed" (0 height) and still the header + first row + footer can't fit in the viewport
Notes
There is still a funkiness when the second row is fully compressed. The scrollbar is still hanging there and I don't know how to get rid of it.
The code can be simplified a little bit without usage of bootstrap grid system.
Demo
https://codepen.io/anon/pen/XBqyxZ
Sorry for this lengthy post. If you want to know more about flexbox, here is a great guide: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
I would but a set the height (or max-height if you prefer) on the card and then set overflow to scroll.
<html>
<div class="box">
<div class="content">
Dispassionate extraterrestrial observer citizens of distant epochs
permanence of the stars billions upon billions vastness is bearable only
through love brain is the seed of intelligence.
</div>
</div>
</html>
<style>
.box {
width: 500px;
overflow: scroll;
}
</style>

Resources