How to make resizable grids based on number of items? - css

I am working on a questionnaire design, which can have one or more answers, something like this:
This looks alright for 3 or more answers as in the above screenshot. However, when there's a single or couple of answers, they are taking too much space, resulting in this:
How can I make the boxes smaller if there are fewer answers, still making them look good, i.e. centered and with proper spacing, etc.?
Here's a working code sandbox where you can see what I have so far.

Maybe you may need a different approach with only flexbox
/* custom class */
.box {
display: inline-flex;
align-items: center;
justify-content: center;
width: 150px;
height: 150px;
border: 2px solid black;
margin: 2px;
}
/* responsivity class */
.responsive {
width: 100%;
display: flex;
margin: 0 auto;
}
.center-placer {
width: max-content;
margin: 0 auto;
}
<div class="responsive">
<div class="center-placer">
<div class="box">
A
</div>
<div class="box">
B
</div>
<div class="box">
C
</div>
<div class="box">
D
</div>
<div class="box">
E
</div>
</div>
</div>
<div class="responsive">
<div class="center-placer">
<div class="box">
A
</div>
<div class="box">
B
</div>
</div>
</div>
<div class="responsive">
<div class="center-placer">
<div class="box">
C
</div>
</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>

Adding a class "collapse" to flex grid creates uneven spacing

So, I am creating a grid system based on flexbox and everything is going quite swimmingly. The basics of my grid are:
<div class="row">
<div class="column"><p>Column</p></div>
<div class="column"><p>Column</p></div>
<div class="column"><p>Column</p></div>
</div>
And in my css:
.row {
margin: 10px 0;
display: flex;
flex-wrap: wrap;
}
.column {
padding: 10px;
flex: 1 1 0%;
}
Essentially, this makes the columns quite fluid, and they shrink/grow to fill all available space. This is great for me as I need to use this throughout various projects where I can't quite customize the grid for every single one. However, I have run into a small "issue". I was going to create a class called ".collapse" so I could collapse the left/right padding to have some columns fit right next together (for example: If I wanted a div with a background color (by adding a color class to the column=> .column .green) flush to an image in the next column). However, the spacing is all out of wack compared to row/columns above it.
<div class="row">
<div class="column purple collapse"><p>Column</p></div>
<div class="column red collapse"><p>Column</p></div>
<div class="column purple collapse"><p>Column</p></div>
<div class="column red collapse"><p>Column</p></div>
</div>
example screenshot here
As you can see in my little example mockup, they do kinda line up, but the right and left margins have "decreased". Is there any smart way around this? I tried adding "left/right margins" to the first-of-type and last-of-type, but this just gets a bit hacky as then anything added in between start having odd alignment issues.
For this kind of grid system, you usually would discourage using structural styling on the grid cells directly, and it lets you do something like this:
.row {
display: flex;
flex-flow: row wrap;
list-style: none;
padding: 0;
margin-left: -10px;
}
.column {
flex: 1 0 0;
padding-left: 10px;
}
.collapse { margin-left: 0; }
.collapse > .column { padding-left: 0; }
.red,
.purple {
padding: 10px;
margin-bottom: 10px;
}
.red { background-color: red; }
.purple { background-color: purple; }
<div class="row">
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
</div>
<div class="row collapse">
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
</div>
This approach uses no margins on the outer ends, which I find way more convenient.
It's worth noting that this kind os system is not all that useful anymore, with the advent of CSS Grid Layout, but there you have it.
On a side note, 0 is always 0, and it never needs a unit.

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>

Prevent contenteditable (in flexed div) from expanding [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 5 years ago.
I'm starting with css flex and I have a hard time with using a contenteditable that I can't prevent from expanding horizontally when the text is too long.
I tried on:
- Chrome
- Firefox
- Opera
- Safari
They all make the divs expand but Safari, who does what I expect.
Here is the HTML:
<div class="container">
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
</div>
Here is the CSS:
.container
{
width: calc(100% - 34px);
height:185px;
margin-left:17px;
margin-top:17px;
display:flex;
}
.column{
flex:1;
height:186px;
margin-right:1.75%;
}
.column:nth-child(5){
margin-right:0px;
}
.field{
margin-bottom:5px;
display:flex;
width:100%;
}
.field_left{
width:6px;
height:24px;
background:green;
}
.field_middle{
height:24px;
background:red;
width:calc(100% - 13px);
}
.field_right{
width:7px;
height:24px;
background:blue;
}
[contenteditable]
{
display:inline;
white-space: nowrap;
overflow:hidden;
text-overflow: inherit;
-webkit-user-select: auto;
user-select: auto;
-moz-user-select: -moz-text;
}
Of course, the HTML could be less complicated for such a result (divs into divs into divs) but keep in mind that I cleaned the code as much as possible in order to present it to you as the design asks for this.
However, I decided to show the relevant part of structure as it might be important to fix the problem.
Here is a JSFiddle of the result:
https://jsfiddle.net/b4er9tLg/2/
If you type a text into one of these boxes, when the text is long enough, it will expand its containing div and change the overall layout of the page.
(if it doesn't do that on your browser, then your browser is one of the happy few).
Basically, what I need is to get something like a hidden overflow on all browsers of text written so that the overall design won't break.
I just can't get it to work.
Thanks for your help.
You have given .column the property flex: 1. From the spec
w3
flex: <positive-number>
Equivalent to flex: <positive-number> 1 0. Makes the flex item flexible and sets the flex basis to zero, resulting in an item that
receives the specified proportion of the free space in the flex
container. If all items in the flex container use this pattern, their
sizes will be proportional to the specified flex factor.
To prevent column and it's contents from expanding you need to give it a max-width value.
I would also suggesting removing margin-right from .column. Instead, set the column width and use the justify-content property on the container.
fiddle
.container {
width: calc(100% - 34px);
height: 185px;
margin-left: 17px;
margin-top: 17px;
display: flex;
justify-content: space-between;
}
.column {
flex: 1;
height: 186px;
max-width: 19%;
}
.field {
margin-bottom: 5px;
display: flex;
width: 100%;
}
.field_left {
width: 6px;
height: 24px;
background: green;
}
.field_middle {
height: 24px;
background: red;
width: calc(100% - 13px);
}
.field_right {
width: 7px;
height: 24px;
background: blue;
}
[contenteditable] {
display: inline;
white-space: nowrap;
overflow: hidden;
text-overflow: inherit;
-webkit-user-select: auto;
user-select: auto;
-moz-user-select: -moz-text;
}
<div class="container">
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
<div class="column">
<div class="field">
<div class="field_left"></div>
<div class="field_middle" contenteditable="true"></div>
<div class="field_right"></div>
</div>
</div>
</div>

Child element shifting parent div

I've searched quite a bit looking for an explanation as to why this behavior is occurring.
Essentially I've setup 2 columns, each with a nav bar and content area.
CSS
#mainContainer {
background-color: lightblue;
width: 100%;
height: 300px;
}
#leftContainer, #rightContainer {
border: 1px solid black;
display: inline-block;
background-color: red;
width: 40%;
height: 100%;
}
#leftBar, #rightBar {
background-color: purple;
height: 10%;
}
#leftMain, #rightMain {
background-color: grey;
height: 90%;
}
HTML
<div id="mainContainer">
<div id="leftContainer">
<div id="leftBar"></div>
<div id="leftMain"></div>
</div>
<div id="rightContainer">
<div id="rightBar"></div>
<div id="rightMain"></div>
</div>
</div>
Whenever I add an element to the nav bar in only one column it shifts the entire column down.
http://jsfiddle.net/qn6rs0q2/3/
<div id="mainContainer">
<div id="leftContainer">
<div id="leftBar">
<button>Test</button>
</div>
<div id="leftMain"></div>
</div>
<div id="rightContainer">
<div id="rightBar"></div>
<div id="rightMain"></div>
</div>
</div>
But if I add another element to the other column they line up again.
http://jsfiddle.net/qn6rs0q2/5/
<div id="mainContainer">
<div id="leftContainer">
<div id="leftBar">
<button>Test</button>
</div>
<div id="leftMain"></div>
</div>
<div id="rightContainer">
<div id="rightBar">
<button>Test 2</button>
</div>
<div id="rightMain"></div>
</div>
</div>
To clarify, I'm not looking for a solution to fix this behavior. Rather I'm hoping someone can explain the underlying reason behind why it's behaving as it is. Thanks in advance.
It happens because the default vertical alignment of inline elements is the baseline. If you set the vertical alignment to top (or middle) for both sides, they line up as you want:
#leftContainer, #rightContainer {
border: 1px solid black;
display: inline-block;
background-color: red;
width: 40%;
height: 100%;
vertical-align:top;
}
jsFiddle example

Resources