How to prevent child's content from stretching parent's width [duplicate] - css

This question already has answers here:
How to match width of text to width of dynamically sized image/title?
(2 answers)
Closed 2 years ago.
I have a component (Container) that contains an icon (marked with an X below), a title and a child component (Message) that contains a long message. I would like Container's width to wrap around the icon and the title so both are on one line as much as window's width allows for it.
Message component has a button that toggles display of a long text. This text should not stretch the parent Container and it should be aligned with title's width. The message content can be broken and wrapped at any point:
I used a flex-grow: 1; width: 0; style on a dummy div in Message as suggested
here to prevent it from growing. This works well on all browsers except for MS Edge, where the message content stretches the parent:
How can I fix this issue on MS Edge?
Is there alternative way using only CSS that I can prevent the message content from stretching its parent?
Style.css:
.box {
display: table;
margin: auto;
border: 1px solid black;
}
.container {
display: flex;
justify-content: center;
}
.icon {
margin-right: 10px;
}
.message {
display: flex;
}
.message > div {
flex-grow: 1;
width: 0;
word-break: break-all;
}
Container.jsx:
export const Container = () => {
return (
<div className='box'>
<div className='container'>
<div className='icon'>
X
</div>
<div className='content'>
<div className='title'>
Some title
</div>
<Message>
Long message that should not make parent wider
</Message>
</div>
</div>
</div>
);
}
Message.jsx:
export const Message = ({children}) => {
const [isExpanded, setExpanded] = React.useState(false);
const handleClick = () => setExpanded(!isExpanded);
return (
<div>
<div>
<button onClick={handleClick}>Click</button>
</div>
{isExpanded &&
<div className='message'>
<div>{children}</div>
</div>
}
</div>
);
}

Try width:0;min-width:100%; on the message container:
.box {
display: table;
margin: auto;
border: 1px solid black;
}
.container {
display: flex;
justify-content: center;
}
.icon {
margin-right: 10px;
}
message {
display:block;
width:0;
min-width:100%;
}
<div class='box'>
<div class='container'>
<div class='icon'>
X
</div>
<div class='content'>
<div class='title'>
Some title
</div>
<message>
<div>Long message that should not make parent wider</div>
</message>
</div>
</div>
</div>
Or to the div inside the message:
.box {
display: table;
margin: auto;
border: 1px solid black;
}
.container {
display: flex;
justify-content: center;
}
.icon {
margin-right: 10px;
}
message {
display:block;
}
message > div {
width:0;
min-width:100%;
}
<div class='box'>
<div class='container'>
<div class='icon'>
X
</div>
<div class='content'>
<div class='title'>
Some title
</div>
<message>
<div>Long message that should not make parent wider</div>
</message>
</div>
</div>
</div>

Related

How to place an item conditionally to right or left of a container?

I am implementing a chat for my web app and I find difficulty in placing the messages correctly and I am not skilled in CSS. I want to place the owner's messages to right and the other user's on the left.
Here some sample code:
// this is the container
<div className="container">
{messages.map(({ text='', isOwnMessage=false })=> <Message text={text} isOwnMessage={isOwnMessage}/>)}
</div>
// This is the message component
//...
<div classname="message">{text}</div>
I need to place <Message /> component to left if isOwnMessage is false, on the right otherwise. I know It can be done by giving position absolute and right:0 but that's not good for me. I tried as well: marginLeft: '50%' but then there's a problem with the dimension of the message itself, which is max 80% of the container, otherwise is like its content.
So how would you do that?
I hope this help to solve your problem:
.message{
clear:both;
padding: 10px;
color: #eee;
}
.message.right{
background: green;
float:right;
}
.message.left{
background: cadetblue;
float:left;
}
<div class="container" >
<div class="message right">Owner message...</div>
<div class="message left">Response message...</div>
</div>
You can implement Message component like this:
<div classname=`message ${isOwnMessage ? 'right' : 'left'}`>{text}</div>
By using the align-self property for flex children.
body {
font-family: sans-serif;
}
.conversation {
border: 1px solid black;
display: flex;
flex-direction: column;
gap: 0.2rem;
max-width: 300px;
padding: 0.5rem;
}
.message {
border-radius: 100vh;
padding: 0.5em 0.8em;
}
.self {
align-self: end;
background-color: #006aff;
color: white;
}
.other {
align-self: start;
background-color: gainsboro;
color: black;
}
<div class="conversation">
<div class="message other">hi</div>
<div class="message self">hello</div>
<div class="message other">what's up</div>
<div class="message self">i'm weekending</div>
<div class="message self">hbu</div>
</div>
Made these changes using flex.
.flex{
display:flex;
}
.flex-col{
flex-direction:column;
}
.ml-auto{
margin-left:auto;
}
// Component
<div className="container flex flex-col">
{messages.map(({ text='', isOwnMessage=false })=> <Message text={text} isOwnMessage={isOwnMessage}
className={isOwnMessage?"ml-auto":""}
/>)}
</div>
// This is the message component
<div classname={["message", props.className].join(" ")}>{text}</div>

cardboxes on 1 row vs 1 column

I am trying to place my card boxes on 1 row rather than on 1 column. Can someone explain to me what is wrong with this CSS?
import "./Card.css"
class Card extends PureComponent {
render() {
return (
<div className="cardcontainer">
<div className="cardbox">
<div>{this.props.title}</div>
<div>{this.props.category}</div>
<div>{this.props.likes / this.props.dislikes}</div>
</div>
</div>
)
}
}
export default Card
.cardcontainer{
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.cardbox{
border: 1px solid red;
width: 200px;
height: 200px;
}
Your cardlist style needs to be applied with the parent component of the Card component.
EG you may have another component called cardList and within the render method for that you apply the cardcontainer style EG.
<div className = cardcontainer>
<Card/>
</div>
This is because in your current code you have initiated the cardcontainer style for every row. I have recoded your work in CSS and HTML so you can see what I mean. I hope this helps.
.cardcontainer{
display: flex;
flex-direction: row;
flex-wrap: nowrap;
width:1000px;
}
.cardbox{
border: 1px solid red;
width: 200px;
height: 200px;
}
<div class="cardcontainer">
<div class="cardbox">
<div>A title</div>
<div>A CAtegory</div>
</div>
<div class="cardbox">
<div>A title</div>
<div>A CAtegory</div>
</div>
</div>

Flex box requires width for proper sizing [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
What are the differences between flex-basis and width?
(6 answers)
Closed 3 years ago.
Using flex for the main menu that has three boxes. The first and third do not flex, and the second grows to fill. The second box is a nested flex that has two boxes, the first does not flex and the second grows to fill. The nested flex, second box is configured to use ellipsis for overflow, but that did not work. The box expands and pushes the nested flex, but not the parent flex, beyond the parent max width. Then discovered if the second boxe has a defined width, any value, even 1px, it works as expected. Concerned and courious why that is, and if i'm doing something wrong.
Codepin to see in action: https://codepen.io/nws-jholmberg/pen/mdyEyWq
<div class="menu-container">
<div class="menu">
<div class="menu-item-1 menu-item">X</div>
<div class="menu-item-2 menu-item">
<div class="menu-search">
<div class="menu-item-search-1">X</div>
<div class="menu-item-search-2">The search result goes here and does not fit</div>
</div>
</div>
<div class="menu-item-3 menu-item">X</div>
</div>
</div>
<br>
<div class="menu-container">
<div class="menu">
<div class="menu-item-1 menu-item">X</div>
<div class="menu-item-2 menu-item">
<div class="menu-search">
<div class="menu-item-search-1">X</div>
<div class="menu-item-search-2 add-width">The search result goes here and does not fit</div>
</div>
</div>
<div class="menu-item-3 menu-item">X</div>
</div>
</div>
.menu-container {
background-color: #f00;
max-width: 200px;
}
.menu {
display: flex;
}
.menu-item {
margin: 4px;
}
.menu-item-1 {
flex: none;
}
.menu-item-2 {
flex: 1;
background-color: #0ff;
}
.menu-item-3 {
flex: none;
}
.menu-search {
display: flex;
}
.menu-item-search-1 {
flex: none;
background-color: #3A3;
color: #fff;
}
.menu-item-search-2 {
flex: 1;
background-color: #3F3;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.add-width {
width: 1px;
}
there is 2 other hurtless ways you can use :
.menu-item-2 {
flex: 1;
background-color: #0ff;
overflow:hidden;
}
or
.menu-item-2 {
flex: 1;
background-color: #0ff;
min-width:0;
}
https://codepen.io/gc-nomade/pen/yLyJypm

Flexbox children overflow parent with max-height specified on IE

I have a parent element that contains two children elements that are displayed on top of each other using flexbox. This parent element has max-height property set to a certain value. So, as long as the content is short, the parent element is supposed to stay small, and as the content grows, the parent element grows with it until it meets its max-height. At this point we should see scrollbars on the content element.
#container {
display: flex;
max-width: 80vw;
max-height: 100px;
flex-direction: column;
}
#content {
overflow-y: auto;
}
/* styling - ignore */
#container {
border: 2px solid black;
margin-bottom: 1em;
}
#header {
background-color: rgb(245, 245, 245);
padding: 10px;
}
#content {
background-color: rgb(255, 255, 255);
padding: 0 10px;
}
<div id="container">
<div id="header">Header</div>
<div id="content">
<p>Everything works as supposed to, move along</p>
</div>
</div>
<div id="container">
<div id="header">Header</div>
<div id="content">
<p>Very long content</p>
<p>Very long content</p>
<p>Very long content</p>
<p>Very long content</p>
</div>
</div>
This works perfectly on Firefox and Chrome. On Internet Explorer though the scrollbars in the content element are not displayed; instead, the content element overflows from the parent element.
I've tried to play around with flex-basis and other flexbox attributes, googled a lot, but without any luck.
I tried to solve this many times, but none of the css solution seems to work in IE 11.
Especialy if you want to keep variable height until max height is reached and then display scrollbar.
(you simply have to set fixed height(not in %) to make scrollbar work in IE)
So I used javascript function that I launched only for IE
You can find out how detect browser here.
Vanilla:
const cont = document.getElementById('container');
if (cont && cont.cildren){
const child = cont.children;
const maxH = cont.offsetHeight - child[0].offsetHeight;
if (maxH < child[1].offsetHeight){
child[1].style.height = maxH + 'px';
}
}
or jQuery (if you are still using it):
const cont = $('#container');
const header = cont.find('.header');
const scrollCont = cont.find('.scrollContainer');
const maxH = cont.outerHeight() - header.outerHeight();
if (maxH < scrollCont.outerHeight()){
scrollCont.height(maxH);
}
In most cases I do what I can to avoid javascript in similar cases ... but, damn you IE !
try height: 100px instead of max-height: 100px; on #container, ie:
#container {
display: flex;
max-width: 80vw;
height: 100px;
flex-direction: column;
}
#container {
display: flex;
max-width: 80vw;
height: 100px;
flex-direction: column;
}
#content {
overflow-y: auto;
}
/* styling - ignore */
#container {
border: 2px solid black;
margin-bottom: 1em;
}
#header {
background-color: rgb(245, 245, 245);
padding: 10px;
}
#content {
background-color: rgb(255, 255, 255);
padding: 0 10px;
}
<div id="container">
<div id="header">Header</div>
<div id="content">
<p>Everything works as supposed to, move along</p>
</div>
</div>
<div id="container">
<div id="header">Header</div>
<div id="content">
<p>Very long content</p>
<p>Very long content</p>
<p>Very long content</p>
<p>Very long content</p>
</div>
</div>

CSS fill remaining width

I have this header bar.
<div id="header">
<div class="container">
<img src="img/logo.png"/>
<div id="searchBar">
<input type="text" />
</div>
<div class="buttonsHolder">
<div class="button orange inline" id="myAccount">
My Account
</div>
<div class="button red inline" id="basket">
Basket (2)
</div>
</div>
</div>
</div>
I need the searchBar to fill whatever the remaining gap is in the div. How would I do this?
Here's my CSS
#header {
background-color: #323C3E;
width:100%;
}
.button {
padding:22px;
}
.orange {
background-color: #FF5A0B;
}
.red {
background-color: #FF0000;
}
.inline {
display:inline;
}
#searchBar {
background-color: #FFF2BC;
}
Use calc!
https://jsbin.com/wehixalome/edit?html,css,output
HTML:
<div class="left">
100 px wide!
</div><!-- Notice there isn't a space between the divs! *see edit for alternative* --><div class="right">
Fills width!
</div>
CSS:
.left {
display: inline-block;
width: 100px;
background: red;
color: white;
}
.right {
display: inline-block;
width: calc(100% - 100px);
background: blue;
color: white;
}
Update: As an alternative to not having a space between the divs you can set font-size: 0 on the outer element.
You can realize this layout using CSS table-cells.
Modify your HTML slightly as follows:
<div id="header">
<div class="container">
<div class="logoBar">
<img src="http://placehold.it/50x40" />
</div>
<div id="searchBar">
<input type="text" />
</div>
<div class="button orange" id="myAccount">My Account</div>
<div class="button red" id="basket">Basket (2)</div>
</div>
</div>
Just remove the wrapper element around the two .button elements.
Apply the following CSS:
#header {
background-color: #323C3E;
width:100%;
}
.container {
display: table;
width: 100%;
}
.logoBar, #searchBar, .button {
display: table-cell;
vertical-align: middle;
width: auto;
}
.logoBar img {
display: block;
}
#searchBar {
background-color: #FFF2BC;
width: 90%;
padding: 0 50px 0 10px;
}
#searchBar input {
width: 100%;
}
.button {
white-space: nowrap;
padding:22px;
}
Apply display: table to .container and give it 100% width.
For .logoBar, #searchBar, .button, apply display: table-cell.
For the #searchBar, set the width to 90%, which force all the other elements to compute a shrink-to-fit width and the search bar will expand to fill in the rest of the space.
Use text-align and vertical-align in the table cells as needed.
See demo at: http://jsfiddle.net/audetwebdesign/zWXQt/
I know its quite late to answer this, but I guess it will help anyone ahead.
Well using CSS3 FlexBox. It can be acheived.
Make you header as display:flex and divide its entire width into 3 parts. In the first part I have placed the logo, the searchbar in second part and buttons container in last part.
apply justify-content: space-between to the header container and flex-grow:1 to the searchbar.
That's it. The sample code is below.
#header {
background-color: #323C3E;
justify-content: space-between;
display: flex;
}
#searchBar, img{
align-self: center;
}
#searchBar{
flex-grow:1;
background-color: orange;
padding: 10px;
}
#searchBar input {
width: 100%;
}
.button {
padding: 22px;
}
.buttonsHolder{
display:flex;
}
<div id="header" class="d-flex justify-content-between">
<img src="img/logo.png" />
<div id="searchBar">
<input type="text" />
</div>
<div class="buttonsHolder">
<div class="button orange inline" id="myAccount">
My Account
</div>
<div class="button red inline" id="basket">
Basket (2)
</div>
</div>
</div>
This can be achieved by wrapping the image and search bar in their own container and floating the image to the left with a specific width.
This takes the image out of the "flow" which means that any items rendered in normal flow will not adjust their positioning to take account of this.
To make the "in flow" searchBar appear correctly positioned to the right of the image you give it a left padding equal to the width of the image plus a gutter.
The effect is to make the image a fixed width while the rest of the container block is fluidly filled up by the search bar.
<div class="container">
<img src="img/logo.png"/>
<div id="searchBar">
<input type="text" />
</div>
</div>
and the css
.container {
width: 100%;
}
.container img {
width: 50px;
float: left;
}
.searchBar {
padding-left: 60px;
}
in css:
width: -webkit-fill-available
I would probably do something along the lines of
<div id='search-logo-bar'><input type='text'/></div>
with css
div#search-logo-bar {
padding-left:10%;
background:#333 url(logo.png) no-repeat left center;
background-size:10%;
}
input[type='text'] {
display:block;
width:100%;
}
DEMO
http://jsfiddle.net/5MHnt/
Include your image in the searchBar div, it will do the task for you
<div id="searchBar">
<img src="img/logo.png" />
<input type="text" />
</div>
I did a quick experiment after looking at a number of potential solutions all over the place. This is what I ended up with:
http://jsbin.com/hapelawake

Resources