How to make flexbox child not create horizontal scrolling - css

The scenario here is that I am importing a React header component that uses Flexbox onto a page that is wrapped in a lot of Flexbox css. I only have have access to myDiv (and can create as many divs as I want wrapped around it), but I am struggling with getting the header component to either truncate or wrap onto multiple lines.
My problems are solved if I specify a specific width of the page in pixels, but is there some way to tell the header component not to expand outside the space it is given? This also needs to work in IE11.
Would love some tips on how to debug this scenario. Thanks!
.myDiv { // Can edit this class
}
.outerContainer3 { // Cannot edit this class
margin-top: 0;
flex-direction: column;
flex: 1 0 auto;
display: flex;
}
.outerContainer2 { // Cannot edit this class
flex: 1 0 auto;
display: flex;
flex-direction: row;
}
.outerContainer1 { // Cannot edit this class
position: relative;
flex: 1 1 auto;
}
.headerContainer2 { // Cannot edit this class
align-items: center;
display: flex;
justify-content: space-between;
}
.headerContainer1 { // Cannot edit this class
min-width: 0%;
flex-shrink: 1;
width: 100%;
}
.header { // Cannot edit this class
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
<div class="outerContainer3">
<div class="outerContainer2">
<div class="outerContainer1">
<div>
<div>
<div class="myDiv">
<div class="headerContainer2">
<div class="headerContainer1">
<h1 class="header">asdfkasdjlfkasdjfla sjdlfkja sldkfj alskfj lskdjf laskdjf laskjf akjf lsakfjs lak jfkjflakj flkajds lakj f</h1>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

If you're able to add some css, then this one could help you.
Update:
I've added the 'position: absolute;' to the rule in this way the h1 element is not expanding out of the div element and it's working in the IE.
Also you're possibly interested in the property 'word-wrap' with the value 'break-word'. This should help you to wrap the very very long words(or urls) without the white-space.
.myDiv { // Can edit this class
}
.myDiv > div > div > h1 {
white-space: inherit;
position: absolute;
}
.outerContainer3 { // Cannot edit this class
margin-top: 0;
flex-direction: column;
flex: 1 0 auto;
display: flex;
}
.outerContainer2 { // Cannot edit this class
flex: 1 0 auto;
display: flex;
flex-direction: row;
}
.outerContainer1 { // Cannot edit this class
position: relative;
flex: 1 1 auto;
}
.headerContainer2 { // Cannot edit this class
align-items: center;
display: flex;
justify-content: space-between;
}
.headerContainer1 { // Cannot edit this class
min-width: 0%;
flex-shrink: 1;
width: 100%;
}
.header { // Cannot edit this class
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
<div class="outerContainer3">
<div class="outerContainer2">
<div class="outerContainer1">
<div>
<div>
<div class="myDiv">
<div class="headerContainer2">
<div class="headerContainer1">
<h1 class="header">asdfkasdjlfkasdjfla sjdlfkja sldkfj alskfj lskdjf laskdjf laskjf akjf lsakfjs lak jfkjflakj flkajds lakj f</h1>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

Add a max width to outerContainer1 and to the myDiv elements.
.myDiv {
max-width: 100%;
}
.outerContainer3 {
margin-top: 0;
flex-direction: column;
flex: 1 0 auto;
display: flex;
}
.outerContainer2 {
flex: 1 0 auto;
display: flex;
flex-direction: row;
}
.outerContainer1 {
position: relative;
flex: 1 1 auto;
max-width: 100%;
}
.headerContainer2 {
align-items: center;
display: flex;
justify-content: space-between;
}
.headerContainer1 {
min-width: 0%;
flex-shrink: 1;
width: 100%;
}
.header {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
<div class="outerContainer3">
<div class="outerContainer2">
<div class="outerContainer1">
<div>
<div>
<div class="myDiv">
<div class="headerContainer2">
<div class="headerContainer1">
<h1 class="header">asdfkasdjlfkasdjfla sjdlfkja sldkfj alskfj lskdjf laskdjf laskjf akjf lsakfjs lak jfkjflakj flkajds lakj f</h1>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

Related

CSS Flexbox - Floating variable height footer with scrollable content

I'm trying to make a fixed "floating" footer with variable height, that always appears at the bottom even when the content changes.
I have the following Create React App HTML:
<html>
<body>
<div id="root">
<div class="app">
<div class="header"></div>
<div class="content"></div>
<div class="footer"><div>
</div>
</div>
</body>
</html>
And the following CSS: (According to second answer on Fixed header, footer with scrollable content)
html, body, #root {
height: 100%
}
.app {
text-align: center;
display: flex;
flex-direction: column;
height: 100%;
flex-wrap: nowrap;
}
.header {
flex-shrink: 0;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
overflow: auto;
flex-grow: 1;
}
.footer {
flex-shrink: 0;
}
However, as the content dynamically changes the page gets distorted and elements overlap each other. I've found that setting #root with height: 275% makes the page display properly in the expanded state (and only then).
Setting #root with min-height: 100% makes the footer appear at the middle of the page when there isn't enough content, and it is not floating anymore when the content is scrollable.
I think this is what you are trying to achieve https://codepen.io/anon/pen/bmMrOg
<div id="root">
<div class="app">
<div class="header">
header
</div>
<div class="content">
<div>content</div>
</div>
<div class="footer">
footer
<div>
</div>
</div>
And the CSS
html, body, #root {
height: 100%;
margin: 0
}
.app {
text-align: center;
display: flex;
flex-direction: column;
height: 100%;
flex-wrap: nowrap;
flex-direction: column;
}
.header {
flex-shrink: 0;
background: blue;
}
.content {
overflow: auto;
flex-grow: 1;
background: red;
}
.footer {
flex-shrink: 0;
background:green;
}

Breaking a line with flexbox centering?

I'm trying to vertically/horizontally center my Title with the Subtitle directly beneath it. Here was my attempt:
html, body, h1 {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
#container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
<div id="container">
<h1>Main Title</h1>
<span>Subtitle</span>
</div>
As you can see, the subtitle is in the same line as the h1, I'm trying to get it to go beneath it. I've tried setting h1 to display: block; but that seems to not work when using display: flex on the container. Any help would be appreciated.
Set flex-direction: column on container
html, body, h1 {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
#container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
<div id="container">
<h1>Main Title</h1>
<span>Subtitle</span>
</div>
Setting flex-direction to column is one solution. It's already provided in another answer.
In some cases, if flex-direction: row is preferred (or a necessity), you can add flex-wrap: wrap to the container and give the first item a 100% width, which forces the second item to the next line.
body, h1 {
margin: 0;
padding: 0;
}
#container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
flex-wrap: wrap; /* NEW */
align-content: center; /* NEW */
text-align: center; /* NEW */
}
h1 { flex: 0 0 100%; } /* NEW */
<div id="container">
<h1>Main Title</h1>
<span>Subtitle</span>
</div>

horizontally scrolling flex child

I have been scowering the web, but can not seem to get a solution to work.
Here is an example codepen:
http://codepen.io/anon/pen/Wxjjqp
.container {
display: flex;
}
.horizontally-scrolled-items {
display: flex;
background: lightblue;
overflow-x: scroll;
}
.item {
width: 1000px;
border: 1px solid blue;
}
html:
<div class="container">
<div class="horizontally-scrolled-items">
<div class="item">item1</div>
<div class="item">item2</div>
<div class="item">item3</div>
</div>
<div class="aside">
<button>keep me on screen</button>
</div>
</div>
The idea is for horizntally-scrolled-items to be flex:1. If the items are greater than the width of the container, for them to scroll, leaving aside in the view.
You can achieve this with min-width. Give your .item class a min-width with a flex-grow: 1;. Then set your .horizontally-scrolled-items div to width: 100%;.
CSS
.horizontally-scrolled-items {
width: 100%;
}
.item {
min-width: 400px;
flex-grow: 1;
}
CodePen
With Flex box
.horizontally-scrolled-items {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
}
.item {
flex: 0 0 auto;
}
Without Flex box
.horizontally-scrolled-items {
overflow-x: scroll;
overflow-y: hidden;
white-space: nowrap;
}
.item {
display: inline-block;
}
Another way is to set the items with and flex: 0 0 auto which is short hand for flex-grow: 0; flex-shrink: 0, so flexbox does not try to resize the items.

Use justify-content: flex-end and to have vertical scrollbar

I have chat and I need to scroll all content to bottom.
I want to use justify-content: flex-end and to have vertical scrollbar.
.session-textchat {
height: 320px;
background: #fff;
display: -webkit-flex;
display: flex;
-webkit-align-items: flex-end;
align-items: flex-end;
-webkit-justify-content: space-between;
justify-content: space-between;
-webkit-flex-direction: column;
flex-direction: column;
}
.session-textchat .past-messages {
width: 100%;
max-width: 980px;
margin: 0 auto;
height: 83.92%;
overflow-y: auto;
padding: 30px 0 0;
display: -webkit-flex;
display: flex;
-webkit-align-items: flex-end;
align-items: flex-end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
-webkit-flex-direction: column;
flex-direction: column;
}
.session-textchat .past-messages .receiver,
.session-textchat .past-messages .sender {
width: 100%;
min-height: 47px;
margin: 0 0 20px;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
}
.session-textchat .past-messages .receiver .message,
.session-textchat .past-messages .sender .message {
position: relative;
padding: 17px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.session-textchat .past-messages .receiver {
text-align: left;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
.session-textchat .past-messages .receiver .message {
background: #f4f4f4;
color: #535353;
}
.session-textchat .past-messages .sender {
text-align: right;
-webkit-justify-content: flex-end;
justify-content: flex-end;
}
.session-textchat .past-messages .sender .message {
background: url('../img/rgbapng/0050ff26.png');
background: rgba(0, 80, 255, 0.15);
color: #0050ff;
}
<div class="session-textchat">
<div class="past-messages">
<div class="receiver">
<span class="message">
Good afternoon David. Welcome to your appointment! How are you today?
</span>
</div>
<div class="sender">
<span class="message">
Hello doctor. I feel terrible to be honest.
</span>
</div>
<div class="receiver">
<span class="message">
I can see from your notes that you've been having some ear ache - can you tell me a bit more about your symptoms?
</span>
</div>
<div class="sender">
<span class="message">
Hello doctor. I feel terrible to be honest.
</span>
</div>
<div class="receiver">
<span class="message">
I can see from your notes that you've been having some ear ache - can you tell me a bit more about your symptoms?
</span>
</div>
</div>
</div>
Example is here.
Is it possible?
Or please give me better solution.
Thanks in advance!
Srdjan
I just had to face this issue myself and, after concluding it is a bug, I came up with a workaround.
In summary, don't use justify-content: flex-end but rather put a margin-top: auto on the first child. Unlike flex-end this doesn't break the scrollbar functionality, and it bottom-aligns the contents when they're not overflowing the container.
Example based on #SrdjanDejanovic's fiddle is at https://jsfiddle.net/peter9477/4t5r0t5b/
In case the example isn't available, here's the relevant CSS:
#container {
overflow-y: auto;
display: flex;
flex-flow: column nowrap;
/* justify-content: flex-end; DO NOT USE: breaks scrolling */
}
#container > :first-child {
margin-top: auto !important;
/* use !important to prevent breakage from child margin settings */
}
An alternative workaround that I believe I've also used is to add an extra container for the scrollbar. Use the flex-end on the inner container and have the outer container handle the scrolling. I generally dislike workarounds that require adding dummy elements though, so I prefer my CSS-only solution above.
Probably you've already solved this, but I faced this problem too and found a solution by trial and error, so I'm going to share it.
Having parent container's display set to flex display: flex and child's items align to flex-end align-items: flex-end will prevent overflow-y: auto to work.
Instead, you can leave you can use next CSS properties for your parent container (in your case session-textchat):
display: flex;
flex-direction: column-reverse; /* 'column' for start, 'column-reverse' for end */
overflow-y: scroll; /* or overflow-y: auto ... */
This will make your child div appear on the bottom of parent container (it will act like flex-end) and enable vertical scroll if content height is bigger than parent container.
I made a little jsfiddle for you if this sounds confusing:
https://jsfiddle.net/lbartolic/9od4nruy/3/
In jsfiddle you can see header part, content part and footer. Container has fixed height and each part takes required height to fill the container. Content part _b__content will be scrollable if its content is taller than _b__content's height.
I hope this will help someone.
Cheers.
Also There is also another Solution
Remove the justify-content and add flex: 1 1 auto; property to the first element(create an empty div)
Old
HTML
<div class="content-reversed">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
CSS
.content-reversed {
display: flex;
flex-direction: column;
justify-content: flex-end;
}
New
HTML
<div class="content-reversed">
<div class="fix"></div> //add this dummy div
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
CSS
.content-reversed {
display: flex;
flex-direction: column;
}
.content-reversed .fix {
flex: 1 1 auto;
}
It seems to be a common bug among the browsers.
You should distribute your style onto 2 containers: the outer will be scrolled, and the inner will be a flex container. Also, you need some js to keep your message list scrolled to bottom while adding new messages.
Here is an example of code:
markup:
<div id='outer'>
<div id='inner-scroll'>
<div id='inner-flex'>
<div class='flex-item'>Item 1</div>
<div class='flex-item'>Item 2</div>
...
</div>
</div>
style:
#inner-scroll {
height: 100%;
overflow: auto;
}
#inner-flex {
display: flex;
flex-direction: column;
justify-content: flex-end;
min-height: 100%;
}
.flex-item { /*nothing*/ }
JS:
function messagePushCallback()
{
var scrollable=document.getElementById('inner-scroll');
scrollable.scrollTo(0, scrollable.scrollHeight-scrollable.clientHeight);
}
// for an example
chat.onMessagePush(messagePushCallback);
window.addEventListener('load', messagePushCallback);
In JS, scrollable.scrollHeight shows the whole height of the element, including the space beyond its visible part, while scrollable.clientHeight is for the height of the visible part.
You have to turn .session-textchat into a flex column then margin-top: auto on .past-messages to send it to the bottom. Then play with overflow-y: scroll and some jQuery:
function updateScroll() {
$("#chat").animate({ scrollTop: $('#chat').prop("scrollHeight")}, 1000);
}
updateScroll();
$("#send_button").on('click', updateScroll);
.session-textchat {
display: flex;
flex-direction: column;
height: 300px;
margin-bottom: 30px;
background: #fff;
overflow-y: scroll;
}
.session-textchat .past-messages {
margin-top: auto;
width: 100%;
max-width: 980px;
}
.session-textchat .past-messages .receiver,
.session-textchat .past-messages .sender {
width: 100%;
min-height: 47px;
margin: 0 0 20px 0;
}
.session-textchat .past-messages .receiver .message,
.session-textchat .past-messages .sender .message {
position: relative;
padding: 15px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.session-textchat .past-messages .receiver {
text-align: left;
}
.session-textchat .past-messages .receiver .message {
background: #f4f4f4;
color: #535353;
}
.session-textchat .past-messages .sender {
text-align: right;
}
.session-textchat .past-messages .sender .message {
background: url("../img/rgbapng/0050ff26.png");
background: rgba(0, 80, 255, 0.15);
color: #0050ff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div id="chat" class="session-textchat">
<div class="past-messages">
<div class="receiver">
<span class="message">
Good afternoon David. Welcome to your appointment! How are you today?
</span>
</div>
<div class="sender">
<span class="message">
Hello doctor. I feel terrible to be honest.
</span>
</div>
<div class="receiver">
<span class="message">
I can see from your notes that you've been having some ear ache - can you tell me a bit more about your symptoms?
</span>
</div>
<div class="sender">
<span class="message">
Hello doctor. I feel terrible to be honest.
</span>
</div>
<div class="receiver">
<span class="message">
I can see from your notes that you've been having some ear ache - can you tell me a bit more about your symptoms?
</span>
</div>
</div>
</div>
<div class="form-group">
<textarea class="form-control" rows="5" id="msg"></textarea>
</div>
<div class="form-group text-center">
<button href="#" id="send_button" class="btn btn-success">Send message</button>
</div>
</div>
Look at this full-screen jsFiddle.
This solution worked for me:
display: flex;
flex-direction: row-reverse;
justify-content: flex-start;

Stacked flexbox vertical centering not working in chrome

The following situation doesn't work in Google Chrome;
<div class="flex-container">
<div class="flex-item">
<div>
<div>
<h2>This is a test</h2>
</div>
</div>
</div>
<div class="flex-item">
<div>
<div>
<h2>This is a test</h2>
</div>
</div>
</div>
<div class="flex-item">
<div>
<div>
<h2>This is a test</h2>
</div>
</div>
</div>
</div>
SCSS
body,html {
height:100%;
background:#1D1F20;
font-family:sans-serif;
color:#fff;
}
.flex-container {
display: flex;
flex-direction: column;
align-items: center;
height:100%;
.flex-item {
flex: 1 1 auto;
align-self: center;
background:#87BEB7;
padding:0 10px;
&:nth-child(2) {
background:#ADBEBC;
}
&:nth-child(3) {
background:#BE8A74;
}
> div {
display: flex;
justify-content: center;
align-items: flex-start;
height:100%; // This seems to be the issue
div {
flex: 0 1 auto;
align-self: center;
background:#5C726F;
padding:10px
}
}
}
}
I would expect the second flexbox-container (.flex-item > div) to be the full height of the flex-child (.flex-item) but it doesn't seem to work. (chrome only)
The workaround I have involves using position absolute, but i'd rather not use it.
Codepen: http://codepen.io/anon/pen/QwpzLX
Open in Firefox to see the desired result and in Chrome to see the current situation.
Any help or suggestions would be appreciated.
Here is the working scss:
.flex-container {
display: flex;
flex-direction: column;
align-items: center;
height:100%;
.flex-item {
flex: 1 1 auto;
align-self: center;
background:#87BEB7;
padding:0 10px;
display: flex;
&:nth-child(2) {
background:#ADBEBC;
}
&:nth-child(3) {
background:#BE8A74;
}
> div {
display: flex;
justify-content: center;
align-items: flex-start;
div {
flex: 0 1 auto;
align-self: center;
background:#5C726F;
padding:10px
}
}
}
}
You have to set display:flex; to .flex-item and remove the height: 100%.
Here is the demo: http://jsfiddle.net/omgL91r8/1/

Resources