Flex: make child with same height of absolute sibling - html

I must create a section with two half divs with the same height, but the first must inside the container and other outside, like that sketch:
I have searched other solutions but I couldn't get them to work, like flex:1, align-stretch, probably because of the way I did it. Maybe you can fresh my mind, by suggesting another way.
Here is my code:
.bg-cyan {
background-color: cyan;
}
img {
max-width: 100%;
}
.right-half {
right: 0;
left: 50%;
border: 2px solid purple;
}
.container {
border: 2px solid red;
}
.col-6 {
flex: 1;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.1/css/bootstrap.min.css" integrity="sha384-VCmXjywReHh4PwowAiWNagnWcLhlEJLA5buUprzK8rxFgeH0kww/aWY76TfkUoSX" crossorigin="anonymous">
<section class="position-relative bg-cyan">
<div class="container position-static p-0">
<div class="row align-items-stretch">
<div class="col-6">
<h4 class="text-secondary mb-6">This col must be the same height of sibling absolute -></h4>
<h3>Staying inside the container</h3>
<ul>
<li>Lorem ipsum dolor sit ame;</li>
<li>Lorem ipsum dolor sit ame;</li>
<li>Lorem ipsum dolor sit ame;</li>
<li>Lorem ipsum dolor sit ame;</li>
<li>Lorem ipsum dolor sit ame;</li>
</ul>
</div>
<div class="col-6 position-absolute right-half p-0">
This is absolute positioned because the layout require the image to go outside of container until the page end, with no height setted because of responsive and dynamism.
<img src="https://picsum.photos/956/870">
</div>
</div>
</div>
</section>

I think you don't have to make the right side to absolute, just use the flexbox feature itself. Try this:
.bg-cyan {
background-color: cyan;
}
img {
max-width: 100%;
}
.right-half {
right: 0;
left: 50%;
border: 2px solid purple;
}
.container {
display: 'flex';
border: 2px solid red;
flex-direction: 'row';
}
.col-6 {
flex: 1;
align-self: 'auto';
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.1/css/bootstrap.min.css" integrity="sha384-VCmXjywReHh4PwowAiWNagnWcLhlEJLA5buUprzK8rxFgeH0kww/aWY76TfkUoSX" crossorigin="anonymous">
<section class="position-relative bg-cyan">
<div class="container position-static p-0">
<div class="row align-items-stretch">
<div class="col-6">
<h4 class="text-secondary mb-6">This col must be the same height of sibling absolute -></h4>
<h3>Staying inside the container</h3>
<ul>
<li>Lorem ipsum dolor sit ame;</li>
<li>Lorem ipsum dolor sit ame;</li>
<li>Lorem ipsum dolor sit ame;</li>
<li>Lorem ipsum dolor sit ame;</li>
<li>Lorem ipsum dolor sit ame;</li>
</ul>
</div>
<div class="col-6 p-0">
This is absolute positioned because the layout require the image to go outside of container until the page end, with no height setted because of responsive and dynamism.
<img src="https://picsum.photos/956/870">
</div>
</div>
</div>
</section>

Related

CSS Truncate inline text only if needed

I'm trying to style a reusable component such that it will stay inline but truncate its contents whenever it overflows. What makes it trickier is that I need to have an icon on the right.
The main issue is that I need the icon to stay on the same line, so I compensate for it in the width of the truncated text (width: calc(100% - 40px)), which makes any non-truncating example be that much shorter than it's normal width.
See the snippet below and how the short example is barely visible.
body, .container {
width: 100%;
padding: 0;
margin: 50px 0;
}
.quantity-value {
display: inline-block;
max-width: 100%;
margin-right: 16px;
background: #f1f1f1;
}
.value-and-icon-wrapper {
display: inline-block;
width: 100%;
}
.icon {
padding-left: 5px;
}
.truncated-text {
display: inline-block;
width: calc(100% - 40px);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
vertical-align: top;
-webkit-line-clamp: 1;
}
<!-- Example 1: short -->
<div class="container">
<div class="quantity-value">
<div class="value-and-icon-wrapper">
<span class="truncated-text">67</span>
<span class="icon">ℹ️</span>
</div>
</div>
other content
</div>
<!-- Example 2: long -->
<div class="container">
<div class="quantity-value">
<div class="value-and-icon-wrapper">
<span class="truncated-text">68 long text starting now lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet</span>
<span class="icon">ℹ️</span>
</div>
</div>
other content
</div>
This is because you are using a lot of inline-block and the width of inline-block is defined by its content so if you set 100% - 40px for a child item, it means its width minus 40px
Try to do it differently like below using flexbox:
body, .container {
width: 100%;
padding: 0;
margin: 50px 0;
}
.quantity-value {
display: inline-flex;
max-width: calc(100% - 16px); /* don't forget to account for margin here */
margin-right: 16px;
background: #f1f1f1;
}
.icon {
padding-left: 5px;
}
.truncated-text {
flex:1;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
<!-- Example 1: short -->
<div class="container">
<div class="quantity-value">
<span class="truncated-text">67</span>
<span class="icon">ℹ️</span>
</div>
other content
</div>
<!-- Example 2: long -->
<div class="container">
<div class="quantity-value">
<span class="truncated-text">68 long text starting now lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet</span>
<span class="icon">ℹ️</span>
</div>
other content
</div>
Without flexbox you can do it like below:
body, .container {
margin: 50px 0;
}
.quantity-value {
display: inline-block;
max-width: calc(100% - 16px); /* don't forget to account for margin/padding here */
margin-right: 16px;
background: #f1f1f1;
padding-right:20px;
box-sizing:border-box;
position:relative;
}
.icon {
padding-left: 5px;
position:absolute;
right:0;
top:0;
bottom:0;
}
.truncated-text {
display:block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
<!-- Example 1: short -->
<div class="container">
<div class="quantity-value">
<span class="truncated-text">67</span>
<span class="icon">ℹ️</span>
</div>
other content
</div>
<!-- Example 2: long -->
<div class="container">
<div class="quantity-value">
<span class="truncated-text">68 long text starting now lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet</span>
<span class="icon">ℹ️</span>
</div>
other content
</div>
Try applying the style text-overflow: ellipsis to the div that contains the text to be truncated.
MDN Documentation for text-overflow

CSS Full Height with divs distributing left space

I am building a message box with title, description, and answers.
I have been struggling for days with that, even played with a Codepen, but can't figure to handle this correctly.
I need:
Title to expand to a maximum of 300px before scrolling
Description to expand to a maximum to left space if no answer (or few), distribute space say 80% of space otherwise (I will add a button to hide this space) before scrolling also
Fixed height for message number title
Messages div to expand to a maximum space left
Input area to stay at bottom and able to size up if any user input (again let's say 20% before scrolling?)
Codepen link
<div class="demoContainer">
<div class="page">
<div class="title">
<h1>My awesome title that is so long i will move everything down</h1>
<button>Some stuff to click</button>
</div>
<div class="row">
<div class="colLeft">
<div class="description">
<h2>Author</h2>
<p>lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsumlorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsumlorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsumlorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsumipsum lorem ipsum lorem ipsum lorem ipsumlorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsumipsum lorem ipsum lorem ipsum lorem ipsumlorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsumipsum lorem ipsum lorem ipsum lorem ipsumlorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum </p>
</div>
<div class="between">
<p>Answers</p>
</div>
<div class="messages">
<ul>
<li>
toto
</li>
<li>
tAta
</li>
<li>
tAta
tAta
</li>
<li>
tAta
</li>
<li>
tAta
</li>
<li>
tAta
</li>
>
<li>
tAta
</li>
>
<li>
tAta
</li>
>
<li>
tAta
</li>
>
<li>
tAta
</li>
</ul>
</div>
<div class="input">
<textarea placeholder="Input height adapt to size until a maximum"></textarea>
</div>
</div>
<div class="colRight">
<ul>
<li>
some
</li>
<li>
stuff
</li>
</ul>
</div>
</div>
</div>
<div class="divider"></div>
<div class="page">
<div class="title">
<h1>My awesome short title</h1>
<button>Some stuff to click</button>
</div>
<div class="row">
<div class="colLeft">
<div class="description">
<h2>Author</h2>
<p>lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum </p>
</div>
<div class="between">
<p>Answers</p>
</div>
<div class="messages">
<ul>
<li>
toto
</li>
<li>
tAta
</li>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
</ul>
</div>
<div class="input">
<textarea placeholder="Input height adapt to size until a maximum"></textarea>
</div>
</div>
<div class="colRight">
<ul>
<li>
some
</li>
<li>
stuff
</li>
</ul>
</div>
</div>
</div>
</div>
* {
box-sizing: border-box;
}
.demoContainer {
display: flex;
flex-direction: row;
}
.divider {
width: 8px;
}
.page {
height: 600px;
width: 550px;
background-color: lightgrey;
display: flex;
flex-direction: column;
overflow: auto;
}
.title {
display: inline-flex;
justify-content: space-between;
align-items: center;
max-height: 200px;
}
.title button {
width: 90px;
height: 30px;
}
.row {
display: flex;
/*flex: 1 1 100%;*/
min-height: 0;
height: 100%;
}
.colLeft {
flex: 3 1 auto;
min-height: 0;
height: 100%;
border: 1px solid blue;
display: block;
flex-direction: column;
position: relative;
/*align-items: stretch;
align-content: stretch;*/
}
.description {
border: 1px dashed black;
/*flex: 4 1 100%;*/
max-height: 60%;
overflow: scroll;
}
.between {
border: 1px solid green;
height: 1, 1em;
}
.between>p {
margin: 0;
}
.messages {
border: 1px dashed red;
/*flex: 2 100 auto;*/
overflow: scroll;
}
ul {
max-width: 100%;
}
.input {
width: 100%;
min-height: 1rem;
flex: 1 1 3rem;
display: flex;
border: 1px solid yellow;
position: relative;
bottom: 0;
}
.input>textarea {
width: 100%;
}
.colRight {
flex: 1 1 auto;
border: 1px solid black;
min-width: 150px;
overflow: scroll;
}
The one on the right is a short example of what I would like, but remove <br/> to see the problem.
I tried with display: grid, isplay: block display: flex. I can't seem to find anything satisfying my needs.
My question is: is that even possible? With CSS only?
For everyone wondering, i discovered a few things while digging into css.
First of all is you can set a 100% height on a div to take up the free space if another element is in, but if and only if you set the parent element display: flex; !
With that in mind, it comes easier.
After that, I decided to dive into JS as my problem does not seem to be solvable with CSS only.
I took advantage of the "new" position: sticky; property, and my JS can take care of position it top: 0; or bottom: 0; depending on the scrolling position.
CSS Added :
.stickyBottom{
position: sticky;
bottom: 0;
}
.stickyTop{
position: sticky;
top: 0;
}
JS Code added:
var colLeft = document.getElementsByClassName("messagesInput")[0];
colLeft.onscroll = function(){myFunction()};
// Get the navbar
var between = document.getElementsByClassName("between")[0];
var desc = document.getElementsByClassName("description")[0];
// Get the offset position of the navbar
var sticky = between.offsetTop;
//between.classList.remove("stickyBottom")
function myFunction() {
if (colLeft.scrollTop >= sticky) {
between.classList.remove("stickyBottom")
between.classList.add("stickyTop")
} else {
between.classList.add("stickyBottom")
between.classList.remove("stickyTop");
}
}
It ends up in a way better UX than I initially wanted ! :)
CodePen Link updated accordingly.

Centering element vertically on mobile devices

I have problem problem with centering element on mobile devices, when height decreases, top content is hidden but on desktop is okey. Please see below link for see problem in screenshot
Desktop version
Mobile version
HTML
<div class="modal">
<div class="modal-section">
<div class="modal-area">
<div class="header">
Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet,
consectetur
</div>
<div class="items">
<div class="element">
<div class="img">
<img src="https://via.placeholder.com/150" alt="">
</div>
<div class="desc">
Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet,
consectetur
</div>
</div>
<div class="element">
<div class="img">
<img src="https://via.placeholder.com/150" alt="">
</div>
<div class="desc">
Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet,
consectetur
</div>
</div>
</div>
</div>
</div>
</div>
CSS:
.modal {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: oldlace;
color: #2F2F2F;
z-index: 99999;
overflow: auto;
}
.items {
display: flex;
margin: 20px 0;
justify-content: center;
}
.element {
overflow: hidden;
background: #2F2F2F;
color: #fff;
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75);
margin: 20px;
cursor: pointer;
width: 150px;
}
.img {
height: 150px;
}
example code
https://jsfiddle.net/twzud65n/3/
Seems like you have some elements that don't quite do something and have no styling applied to fit in. What is the suppose of modal-section?
Because you have position: fixed on your modal, you need to tell its children to not overflow their parent. width: 100% does that, height: auto means it can scale as much as needed allowing to scroll.
Try this:
.modal-section {
width: 100%;
height: auto;
}
It's because of justify-content: center which is centering your element (even if it's overflowing). You can turn it off and add margin:auto to .modal-section.
Example
.modal {
display: flex;
flex-flow: column nowrap;
align-items: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: oldlace;
color: #2F2F2F;
z-index: 99999;
overflow: auto;
}
.modal-section {
margin: auto;
}
.items {
display: flex;
margin: 20px 0;
justify-content: center;
}
.element {
overflow: hidden;
background: #2F2F2F;
color: #fff;
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.75);
margin: 20px;
cursor: pointer;
width: 150px;
}
.img {
height: 150px;
}
<div class="modal">
<div class="modal-section">
<div class="modal-area">
<div class="header">
Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet,
consectetur
</div>
<div class="items">
<div class="element">
<div class="img">
<img src="https://via.placeholder.com/150" alt="">
</div>
<div class="desc">
Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet,
consectetur
</div>
</div>
<div class="element">
<div class="img">
<img src="https://via.placeholder.com/150" alt="">
</div>
<div class="desc">
Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet,
consectetur
</div>
</div>
</div>
</div>
</div>
</div>

Display text inline from a separate container div

I'm trying make "the end" in the following code to appear inline with the lorem ipsum, and can't figure out how. Is it possible? I can't change the HTML structure at all. (nor can I add js, etc)
#parent {
width: 300px;
border: 1px solid red;
}
#block2 a {
color: #00f;
}
<div id="parent">
<div id="block1">
<a> Lorem ipsum dolor sit amet, consectetur elit. dolor nulla. Duis lob.</a>
</div>
<div id="block2">
<a>The end</a>
</div>
</div>
I want it to look like this:
If you are able to make changes to the CSS, then this is an easy solution. Just use display: inline, which will make the element only take as much space as necessary (acting like a <span> element).
However, if by chance, you are unable to, then there is no way I can think of for you to achieve this given your situation.
#parent {
width: 300px;
border: 1px solid red;
}
#block1, #block2 {
display: inline;
}
#block2 a {
color: #00f;
}
<div id="parent">
<div id="block1">
<a> Lorem ipsum dolor sit amet, consectetur elit. dolor nulla. Duis lob.</a>
</div>
<div id="block2">
<a>The end</a>
</div>
</div>
You need to set the two block containers to display: inline:
#parent {
width: 300px;
border: 1px solid red;
}
#block2 a {
color: #00f;
}
#block1, #block2 {
display: inline;
}
<div id="parent">
<div id="block1">
<a> Lorem ipsum dolor sit amet, consectetur elit. dolor nulla. Duis lob.</a>
</div>
<div id="block2">
<a>The end</a>
</div>
</div>

vertical align bottom for a specific child

I have a parent element that has 2 children. I want to move 1st child to top, and second one to bottom. The parent element has a scroll and its children size isn't fixed. Children size expands dynamically depending on theirs content
So If theirs size are smaller than parent's one they would look like in the left picture, else they should expand parents div like in the right picture. Usually to move element to edges I'd use absolute position like this:
.parent {
position: relative;
}
.top-child {
position: absolute;
top: 0;
}
.bottom-child {
position: absolute;
bottom: 0;
}
But this case brakes the flow. Parent width and height wouldn't adjust depending by children size. Another solution is to use vertical-align
.parent {
display: table-cell;
vertical-align: bottom;
}
But in this scenario all children would move to bottom.
Here's jsfiddle. Green background is parent. topdiv and bottomdiv and childrens.
How should I CSS divs to attach children to edges without breaking the flow?
you can achieve this use display:table and table-row:
#scroller {
height:300px; /* this height is the min height before you want to scroll */
overflow:auto;
}
.table {
min-height:100%;
width:100%;
display:table;
}
.row {
display:table-row;
}
.row:first-child {
height:100%; /* this is needed to "push" the second row to the bottom (it will actually be 100% minus the bottom row height */
background:blue;
}
.row:last-child {
background:green;
}
<div id="scroller">
<div class="table">
<div class="row">expands to fill space</div>
<div class="row">stays at bottom</div>
</div>
</div>
Example fiddle
Fiddle with content and scrolling
Update
Applying my styles to your fiddle
Something like this?
.main {
width: 300px;
height: 300px;
overflow-y: auto;
border: 1px solid #999;
margin-bottom: 30px;
}
.parent {
min-height: 100%;
display: flex;
flex-direction: column;
}
.child-a {
flex: 1;
background: #ccc;
}
.child-b {
background: #ddd;
}
<div class="main">
<div class="parent">
<div class="child-a">
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
</div>
<div class="child-b">
<p>Amet ipsum dolor</p>
</div>
</div>
</div>
<div class="main">
<div class="parent">
<div class="child-a">
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
<p>Lorem ipsum dolor</p>
</div>
<div class="child-b">
<p>Amet ipsum dolor</p>
</div>
</div>
</div>