I am trying to create a dynamic grid layout with two columns that is #red-container and #green-container. Each container or column should be resizable horizontally and the main container #container should be resizable vertically. Resizing the container should adjust the height of the child elements. The #red-container and #green-container have cells which are added dynamically to the container with the JavaScript function in a row-wise fashion. I have the following working implementation:
function addCell(color) {
let container = document.getElementById(color + "-container");
let cell = document.createElement("div");
cell.innerText = color;
container.appendChild(cell).className = "container-item";
}
#container {
border: 1px solid #ddd;
display: flex;
flex-grow: 1;
flex-direction: row;
height: 50vh;
resize: vertical;
overflow: auto;
}
#red-container {
flex-grow: 1;
display: grid;
grid-auto-flow: row;
margin: 10px;
resize: horizontal;
overflow: auto;
border: 1px solid red;
}
#green-container {
flex-grow: 1;
display: grid;
grid-auto-flow: row;
margin: 10px;
resize: horizontal;
overflow: auto;
border: 1px solid green;
}
.container-item {
padding: 10px;
border: 1px solid black;
}
<button onclick="addCell('red')">add red cell</button>
<button onclick="addCell('green')">add green cell</button>
<div id="container">
<div id="red-container"></div>
<div id="green-container"></div>
</div>
However, there are two problems with it:
The first time the user clicks add red cell it increases the width of #red-container.
adjusting the width of the red and green container is inconsistent and I am unable to adjust the width of the red container to less than 50% of the width.
Any ideas on how to fix these two problems? Additionally, any advice on writing the css in a more concise manner is welcome (#red-container and #green-container contain duplicate code).
Make only the red container resizable with an initial width equal to 50% and use flex-grow:1 on the green container
function addCell(color) {
let container = document.getElementById(color + "-container");
let cell = document.createElement("div");
cell.innerText = color;
container.appendChild(cell).className = "container-item";
}
#container {
border: 1px solid #ddd;
display: flex;
gap: 10px;
padding: 10px;
height: 50vh;
resize: vertical;
overflow: auto;
}
#green-container,
#red-container {
display: grid;
overflow: auto;
}
#red-container {
border: 1px solid red;
width: 50%;
resize: horizontal;
}
#green-container {
border: 1px solid green;
flex-grow: 1;
}
.container-item {
padding: 10px;
border: 1px solid black;
}
<button onclick="addCell('red')">add red cell</button>
<button onclick="addCell('green')">add green cell</button>
<div id="container">
<div id="red-container"></div>
<div id="green-container"></div>
</div>
do these two things to solve the problem:
make the #container with grid-template-columns: 1fr 1fr; so whatever it happens, the child will be always half-width.
because if you want to use flex, it only grows to 1, but does not always mean half precisely, so go for grid layout
for not making repetitive code just make the two selectors in one by using , (comma)
#red-container, #green-container
not important but can help:
adding box-sizing: border-box for solving extra problems if you add padding or something similar
also don't write grid-auto-flow: row because grid is by default row
also use gap instead of margin, gap makes the same value of px between element on a grid/flex layout.
if you are using margin, then if you write for example 10px as a value you will get 20px
here the correct code:
function addCell(color) {
let container = document.getElementById(color + "-container");
let cell = document.createElement("div");
cell.innerText = color;
container.appendChild(cell).className = "container-item";
}
* {
box-sizing: border-box;
}
#container {
border: 1px solid #ddd;
display: grid;
grid-template-columns: 1fr 1fr;
height: 50vh;
resize: vertical;
overflow: auto;
gap: 10px;
/* if you want like before, here in gap: write 20px */
padding: 10px;
}
#red-container,
#green-container {
display: grid;
resize: horizontal;
overflow: auto;
}
#red-container {
border: 1px solid red;
}
#green-container {
border: 1px solid green;
}
.container-item {
padding: 10px;
border: 1px solid black;
}
<button onclick="addCell('red')">add red cell</button>
<button onclick="addCell('green')">add green cell</button>
<div id="container">
<div id="red-container"></div>
<div id="green-container"></div>
</div>
if you didn't understand something, write me a comment here, I will answer to you
however here some documentations that can help you:
grid-template-columns: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
box-sizing: https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing
gap: https://developer.mozilla.org/en-US/docs/Web/CSS/gap
Related
I'm trying to do this :
The flex-item img must define the flex-container width and the other flex-item (the div with "a" and "aaaaaaa...") must into the flex-container but must not make the flex-container grow.
Also, i don't want to fix a width of text flex-item in px because the image width is dynamic. How can i do that without using javascript ?
I made this code snippet according to my image to help :
.flex-container {
display: flex;
flex-direction: column;
border: 3px blue solid;
}
.random-image {
width: 50px;
height: 50px;
border: 3px red solid;
}
.first-text, .second-text {
border: 3px orange solid;
}
.second-text {
word-break: break-all;
}
<div class="flex-container">
<div class="random-image"></div>
<div class="first-text">a</div>
<div class="second-text">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</div>
</div>
Remove the fixed width on the image div and use width: min-content; on the flex-container as well as the random-image div. This should work nicely for you.
.flex-container {
display: flex;
flex-direction: column;
border: 3px blue solid;
width: min-content;
height: fit-content;
padding: 10px;
}
.random-image {
border: 3px red solid;
width: fit-content;
}
.first-text, .second-text {
border: 3px orange solid;
}
.second-text {
word-break: break-all;
}
.first-text {
width: fit-content;
margin: 1em auto 1em auto;
}
<div class="flex-container">
<div class="random-image"><img src="https://dummyimage.com/600x400/000/fff"></div>
<div class="first-text">a</div>
<div class="second-text">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</div>
</div>
The image below is what I'm currently working with. I have a flex container taking up the whole width of the screen (a div with the red border), that contains two flex items: one being the white square, and the other being another flex container (with the blue border) containing the buttons.
What I'm trying to do is center the white square horizontally on screen, and have it so that when the window/screen is resized the button container div won't collide/come into the white square. I'm not sure how to go about this, so any help would be appreciated. My code is below the image.
<div class="middle-content-section">
<div class="drawing-pad-container"></div>
<div class="settings-container">
<button class="grid-toggle-button">Show grid</button>
<button class="grid-toggle-button">Hover to draw</button>
</div>
</div>
.middle-content-section {
margin-top: 50px;
display: flex;
gap: 50px;
width: 100%;
border: 1px solid red;
}
.settings-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 20px;
border: 1px solid blue;
}
.drawing-pad-container {
height: 500px;
width: 500px;
background: rgb(255, 255, 255);
filter: drop-shadow(2px 2px 3px rgb(180, 180, 180));
transition: 0.3s;
display: grid;
grid-template-rows: repeat(30, 1fr);
grid-template-columns: repeat(30, 1fr);
flex: 0 0 auto;
}
If you are simply trying to centre the white square in the div all you really need are some margins.
margin: 0 auto;
So I modified my answer to hopefully better fit your request. It is a little hacky but does seem to work.
What I did was create one more container called items which holds both interior items. I then set an auto margin on the container to centre both the white box and then settings bar. The bar was given a fixed width of 100px and therefore I did a transform: translateX(100px) which will then shift everything over by 100px correcting for the width and therefore offset cause by the settings bar.
Below is a code snippet of the result with the change spaced out.
.middle-content-section {
margin-top: 50px;
display: flex;
width: 100%;
border: 1px solid red;
}
.items {
margin: 0 auto;
transform: translateX(100px);
gap: 50px;
display: flex;
}
.settings-container {
width: 100px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 20px;
border: 1px solid blue;
}
.drawing-pad-container {
height: 500px;
width: 500px;
background: rgb(255, 255, 255);
filter: drop-shadow(2px 2px 3px rgb(180, 180, 180));
transition: 0.3s;
display: grid;
grid-template-rows: repeat(30, 1fr);
grid-template-columns: repeat(30, 1fr);
flex: 0 0 auto;
}
<div class="middle-content-section">
<div class="items">
<div class="drawing-pad-container"></div>
<div class="settings-container">
<button class="grid-toggle-button">Show grid</button>
<button class="grid-toggle-button">Hover to draw</button>
</div>
</div>
</div>
ref: coryrylan.com
section {
width: 200px;
border: 1px solid #2d2d2d;
display: flex;
justify-content: center;
align-items: center;
}
<section>
<div>1</div>
<div>2</div>
<div>3</div>
</section>
I want to display divs so that it can be horizontally scrolled. I have created a display flex container but I am not sure what else do I need to do so that the boxes are aligned to the left.
Here is the demo code
.container {
height: 95px;
border: 1px solid black;
display: flex;
flex-direction: column;
overflow-x: auto;
}
.box {
border: 1px solid black;
margin: 5px;
width: 100px;
}
The uncommented code works fine. The momement I comment the cols, I get extra spacing
The CSS align-content and justify-content properties allow you to choose where items in the flexbox appear. I suggest you look them up (for example on CSS tricks) to understand how they work. In this case setting align-content: flex-start; to the .container object will do the trick.
Is this what you wanted?: HERE
.container {
height: 95px;
border: 1px solid black;
display: flex;
/* flex-direction: column; */
overflow-x: auto;
}
.box {
border: 1px solid black;
margin: 5px;
flex: 0 0 33%;
}
I want to achieve a multi-line flexbox container where element width can reduce if it's min-width is not reach to not let big whitespace when break line happen.
Here is an example on which i'm working on : https://codepen.io/BaptisteG/pen/dyyQodR
.container {
border: 5px solid rgb(111,41,97);
border-radius: .5em;
padding: 10px;
display: flex;
flex-wrap: wrap;
row-gap: 1em;
column-gap: 20px;
width: 500px;
}
.item {
padding: 10px;
background-color: rgba(111,41,97,.3);
border: 2px solid rgba(111,41,97,.5);
flex: 1 1 content;
min-width: 100px;
max-width: min-content;
white-space:nowrap;
overflow:hidden;
}
A sketch of what i want to achieve :
sketch
I don't want element size to be increase to complete whitespace
This question already has answers here:
Stretch columns in two columns layout with shared header using flexbox
(2 answers)
Closed 4 years ago.
I have this layout, where a row wrap flex container has a first child with 100% width and 2 more children on the second row. The container has a fixed height and the first child (Filters block below) is collapsible (i.e. has 2 possibles values for height).
I would like the blocks on the last line to take all available height in all cases (filters block collapsed or expanded), but I can't find a solution.
I've tried various combinations of height, align-items/align-self: stretch, to no avail. Setting the pdt/list blocks height to 100% makes them effectively 100% of parent container, so they overflow due to the filters.
I know I could achieve it by making the first container flex column and throw in a second one with flex row,but I'd like to keep the current markup if possible. Any idea?
JSfiddle: https://jsfiddle.net/Lp4j6cfw/34/
HTML
<div id="lp-tag">
<div id="header">HEADER</div>
<div id="lp-ctnr">
<div id="filters" onclick="toggle()">FILTERS</div>
<div id="pdt">PDT</div>
<div id="list">LIST</div>
</div>
CSS
#lp-tag{
display: flex;
flex-flow: column nowrap;
width: 350px;
margin: auto;
border: 1px solid red;
height: 250px;
}
#header{
background: lightblue;
height: 80px;
}
#lp-ctnr{
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-content: flex-start;
align-items: stretch;
border: 1px solid green;
flex: 1;
}
#filters{
width: 100%;
background: lightgreen;
height: 45px;
}
.close{
height: 20px !important;
}
#pdt, #list {
flex: 1;
border: 1px solid blue;
text-align: center;
align-self: stretch;
}
#pdt{
background: yellow;
}
#list{
background: pink;
}
If you are open to alternative layout methods, I'd recommend CSS-Grid
.lp-tag {
width: 250px;
margin: 1em auto;
border: 1px solid red;
height: 250px;
display: inline-grid;
grid-template-rows: auto 1fr;
}
.header {
background: lightblue;
height: 80px;
}
.header.small {
height: 40px;
}
.lp-ctnr {
display: grid;
grid-template-rows: auto 1fr;
grid-template-columns: repeat(2, 1fr);
border: 1px solid green;
flex: 1;
}
.filters {
grid-column: 1 / span 2;
background: lightgreen;
height: 45px;
}
.filters.large {
height: 80px;
}
.pdt,
.list {
border: 1px solid blue;
text-align: center;
}
.pdt {
background: yellow;
}
.list {
background: pink;
}
<div class="lp-tag">
<div class="header">HEADER</div>
<div class="lp-ctnr">
<div class="filters" onclick="toggle()">FILTERS</div>
<div class="pdt">PDT</div>
<div class="list">LIST</div>
</div>
</div>
<div class="lp-tag">
<div class="header small">HEADER</div>
<div class="lp-ctnr">
<div class="filters large" onclick="toggle()">FILTERS</div>
<div class="pdt">PDT</div>
<div class="list">LIST</div>
</div>
</div>
This is the only solution I can see without an intermediary container. https://jsfiddle.net/5j38ouvs/
However, I would probably do like Nandita and add a surrounding container like here: https://jsfiddle.net/8md4oyLx/
CSS
#lp-ctnr{
display: flex;
flex-direction: column;
border: 1px solid green;
height: 550px;
width: 350px;
margin: auto;
}
#filters{
width: 100%;
background: lightgreen;
}
.close{
height: 20px !important;
}
#pdt{
flex-grow: 1;
background: yellow;
}
#list{
flex-grow: 1;
background: pink;
}
.list-container {
flex-grow: 1;
border: 1px solid blue;
text-align: center;
display: flex;
flex-direction: row;
}
HTML
<div id="lp-ctnr">
<div id="filters" onclick="toggle()">FILTERS</div>
<div class="list-container">
<div id="pdt">PDT</div>
<div id="list">LIST</div>
</div>
</div>