How to make flex box with limit 2 elements per row? - javascript

I need to make a table which will contain up to 4 divs.
But the divs in that table always should use maximum of avaliable space.
And one one row should contain not more then 2 divs
For instance if table contains 2 divs it should look like this
If table has 3 divs then like this:
And if contains 4 then it should look like that
To achieve it i wrote this code:
<div
style={{
height: '58vh', border: '1px solid #d9d9d9',
borderRadius: '0px 0px 2px 2px',
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
}}
>
<div style={{background:'red', flex: 'auto', margin: '5px'}}
<div style={{background:'green', flex: 'auto', margin: '5px'}}
<div style={{background:'blue', flex: 'auto', margin: '5px'}}
<div style={{background:'pink', flex: 'auto', margin: '5px'}}
</div>
But i missing something here.
For 1 div and for 2 divs it works as planned.
But for more..
This is my result for 3 divs
And for 4 divs
Can anyone advice me please what should i change in this code?
PS. Please don't judge my unevenly drawn squeres :)

.container {
display: flex;
flex-wrap: wrap;
}
.inner {
flex-basis: 50%;
flex-grow: 1;
}
.inner:nth-of-type(1) {
background: red;
}
.inner:nth-of-type(2) {
background: gold;
}
.inner:nth-of-type(3) {
background: green;
}
.inner:nth-of-type(4) {
background: blue;
}
<div class="container">
<div class="inner">one</div>
<div class="inner">two</div>
<div class="inner">three</div>
<div class="inner">four</div>
</div>
I used the following steps to achieve your result.
Make the container which contains the inner boxes as flex.
Give the container flex-wrap: wrap so that the inner boxes which do not have place on the same line, shift to the next line.
Give flex-basis: 50% to the inner boxes so that they take up 50% of the available space.
Give the inner boxes flex-grow: 1 so that if the last box has any space left, it will take up all of it.
References:
Flexbox
flex-wrap
flex-basis
flex-grow
(Extra) flex-shrink
PS: Try commenting the fourth inner box so that the third box will take up the whole horizontal space.

What you mean about use Grid for this?
example:
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
here it's guide for Grid: https://css-tricks.com/snippets/css/complete-guide-grid/

Related

I want to overlay a rectangle on top of another rectangle

I want to form something like this using CSS and typescript/JavaScript:
Can someone please help me understand how to do this?
I tried using a flex container and this is what I have got this:
I am new to front end development. Can someone please tell me what I am missing here?
.green-area {
display: flex;
flex-grow: 1;
margin-right: #space-sm;
position: relative;
}
.black-area {
display: flex;
flex-grow: 1;
position: absolute;
background: #000000;
height: 20px;
width: 5%;
}
.height {
height: #space-sm;
}
<div styleName="green-area">
<div style={{ flexGrow: 10, }}>
<div styleName={`height`}>
<div styleName="black-area">
<div style={{ flexGrow: 10, }}>
<div styleName={`height`} />
</div>
</div>
</div>
</div>
</div>
Just like isherwood mentioned, this is an HTML/CSS issue.
You've added the class using styleName which is incorrect. It should be className
You've missed the positioning for the black-area
I created this CodeSandbox with the answer. You can change the inline style to control the positioning of the black-area

How to make two columns same height dynamically

I hava a page with two columns. I would like to textarea height mimic left column height. Left column is short when webpage loads, but when user starts expanding various properties (checkboxes + dropdownmenus) it grows based on hidden divs. But my textarea is still small in right column and making it staticly bigger does not look good.
I want it to grow per left column height. Not sure how to achieve that.
EDIT:
Once height: 100%; was added to textarea it solved the issue with columns growth.
But I ran into another two issues.
Textarea in right column overlaps that column on page load. When I try to resize, it suddenly jumps to the column properly. Weird behavior.
here is the pic - textarea overlaps column
Left column context is not aligned properly with right. How I am going to align or justify context of both columns so they end up like this:
here is the pic - final look
My CSS:
body {
height: 100%;
position: relative;
background: #000000;
color: #66adff;
font-size: 105%;
font-family: serif, Arial, Helvetica
}
.column {
border: 5px solid #333;
}
.container{
display: flex;
}
.columnleft {
width: 45%;
padding: 10px;
display: table-cell;
}
.columnright {
width: 45%;
padding: 10px;
display: table-cell;
}
textarea.out {width: 100%; height: 100%; box-sizing: border-box;}
EDIT 2:
Issue 1 - I had text inside the column which pushed area down
Issue 2 - all was fixed with proper padding
Thanks all for replies.
I think you could do this without js, but use CSS Grid instead.
Example:
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr; // the width of each column
grid-template-rows: auto; // row height will auto-adjust to contents
}
<div class="grid-container">
<div class="column-left">
...some dynamic content
gets bigger and bigger and bigger and bigger and bigger
</div>
<div class="column-right">
might be empty or small or large
</div>
</div>
The grid row height will always adjust to the height of the largest content which will make both columns the same height.
Since you're using flex, the right column should be automatically adjusting to match the left column. It sounds like your issue is that the textarea is not expanding automatically to match its container (right column.)
If that's the case, try this simple fix - in your CSS, set textarea height to 100% to automatically fill its parent:
textarea {
height: 100%;
};
Here's an example answer:
Textarea to fill a parent container exactly, with padding
The reason your code wasn't working was because you didn't set the height to your textarea settting the height to 100% will always make it fit the maximum size of it's container (<div>) also i have added box-sizing: border-box; so that you can add padding to your columnright.
A better explanation about box-sizing can be found here (just won't explain here because i couldn't do better then this): https://css-tricks.com/box-sizing/
function f_anyEvent(){
var leftcolumnHeight = document.getElementById('columnleft').style.height.value;
if (document.getElementById('columnleft').style.height != document.getElementById('columnright').style.height)
document.getElementById('columnright').style.height = leftcolumnHeight.value;
}
document.getElementById('add').addEventListener('click', function() {
let columnleft = document.getElementById('columnleft');
columnleft.innerHTML += '<h1>a</h1>';
});
.row{
display: flex;
}
.column {
border: 1px solid #333;
}
.columnleft {
float: left;
width: 45%;
padding: 10px;
display: table-cell;
}
.columnright {
float: left;
width: 45%;
padding: 10px;
display: table-cell;
}
textarea {
width: 100%;
height: 100%;
box-sizing: border-box;
}
<div class="row">
<div id="columnleft" class="column columnleft">
</div>
<div id="columnright" class="column columnright">
<textarea></textarea>
</div>
</div>
<button id="add">
add
</button>
Every time you click add it will add an <h1> to your left column and your textarea will get the same height as columnleft.
Here's a basic demo of an interface similar to yours that uses display: grid on the parent container to automagically keep the two inner divs the same height. (Click on the blue details element to trigger a height change.)
It's wonderfully simple. (Thanks for inspiring me to finally learn how grid works.)
// The JavaScript isn't needed for the dynamic styling. (It just copies the text.)
const
left = document.getElementById("left"),
right = document.getElementById("right");
left.addEventListener("change", showOutput);
function showOutput(event){
right.innerHTML = this.querySelector("#reasons").value
}
div { max-width: 400px; border: 1px solid grey; }
details{ margin: 10px 5px; color: #0000DD; text-decoration: underline; }
/* This is where the magic happens */
#container { display: grid; grid-template-columns: 1fr 1fr; }
#left{ padding: 10px; }
#right { white-space: pre-wrap; }
<div id="container">
<div id="left">
<label> <input type="checkbox"/> I like pie </label>
<details>
<summary>Type your reasons here</summary> <textarea id="reasons"></textarea>
</details>
</div>
<div id="right"></div>
</div>

CSS - How do I create a grid that takes up the remaining width of screen (without counting sidebar)

I am trying to create a grid in CSS, but I am not sure how to specify the width of the entire grid, such that it takes up only the remaining width of the screen (minus the sidebar) such that there should not be any scrolling horizontally allowed. Below is the screenshot of the issue I am facing.
As you can see, there is horizontal scrolling enabled, because the grid is too wide.
Here is my code for reference: (I am using ReactJS)
.analytics-grid {
display: grid;
grid-template-rows: auto;
grid-template-columns: 1fr 1fr;
row-gap: 10px;
column-gap: 10px;
grid-template-areas: "conversion conversion-daily"
}
.daily-conversion-box {
grid-area: conversion-daily;
padding: 20px;
}
.conversion-box {
grid-area: conversion;
padding: 20px;
}
jsx (where CustomerConversion and CustomerConversionDaily are child components I call to render the charts)
<div className='analytics-grid'>
<div className='conversion-box'>
<CustomerConversion />
</div>
<div className='daily-conversion-box'>
<CustomerConversionDaily />
</div>
sidebar.js (where Sider is a component from a UI package AntD)
<div>
<Sider trigger={null} collapsible collapsed={collapsed}>
{menu()}
</Sider>
<div id='crm-header-layout'>
... *header goes here* ...
<div id="crm-content">
{props.children} //this is where the analytics grid from above end up
</div>
</div>
</div>
Is there a way for me to be able to specify the width of my grid such that it just nice takes up the remaining width of the screen minus the sidebar such that there is no horizontal scrolling to be done? Thanks all for the help, I am new to CSS, so do guide me along if there are any better solutions to accomplish what I want to accomplish! Thank you
when you set display: grid; it means the children of this node are arranged using grid. It doesn't set the div's height or width for you. You need to set it if you want to contain it.
There are multiple ways to set the width.
You can use the grid the same way you've used for container. Like this,
.container {
display: grid;
grid-template: 1fr / 80px 1fr;
}
.content-1 {
background-color: red;
}
.content-2 {
background-color: blue;
}
<div class="container">
<div class="content-1">Content 1</div>
<div class="content-2">Content 2</div>
</div>
You can contain both the appbar and the content in a flex, and set the flex-grow of container to 1.
.app{
display: flex;
}
.appbar{
flex-grow: 0;
}
.main-container{
flex-grow: 1;
}
or,
use CSS calc for container like this.
.analytics-grid {
display: grid;
grid-template-rows: auto;
grid-template-columns: 1fr 1fr;
row-gap: 10px;
column-gap: 10px;
grid-template-areas: "conversion conversion-daily";
width: calc(100vw - <appbar width>);
}
PS: grid-template is short hand to set both row and columns at a time. Refer https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template

css grid to fill 100vh without affecting row height

I have a grid with 3 columns and a variable/dynamic number of rows. The grid has a colored background and when there are NOT enough rows as to vertically fill the window, the remaining, empty vertical space is un-colored:
.grid {
align-self: flex-start;
display: grid;
grid-template-columns: min-content 2fr 1fr;
grid-gap: 0px;
}
.index, .title {
background: red;
padding: 0 2vw 0 1vw;
}
.ticker {
background: yellow;
}
<div class="grid">
<div class="index">1</div>
<div class="title">Pigs are cute</div>
<div class="ticker">blah blah</div>
<div class="index">2</div>
<div class="title">Horses rise at night</div>
<div class="ticker">bleh bleh</div>
<div class="index">3</div>
<div class="title">Cats run in packs</div>
<div class="ticker">blih blih</div>
</div>
I would like this vertical space to be colored as the grid is. The apparently obvious solution is to give the grid a height of 100vh. But this expectedly stretches each row's height accordingly, which is not the result I am looking for, as I need row height to adapt to content.
.grid {
align-self: flex-start;
display: grid;
grid-template-columns: min-content 2fr 1fr;
grid-gap: 0px;
height: 100vh;
}
.index, .title {
background: red;
padding: 0 2vw 0 1vw;
}
.ticker {
background: yellow;
}
<div class="grid">
<div class="index">1</div>
<div class="title">Pigs are cute</div>
<div class="ticker">blah blah</div>
<div class="index">2</div>
<div class="title">Horses rise at night</div>
<div class="ticker">bleh bleh</div>
<div class="index">3</div>
<div class="title">Cats run in packs</div>
<div class="ticker">blih blih</div>
</div>
Is there any CSS grid way of expanding the grid vertically while still allowing row height to adapt to content?
An alternative javascript solution, such as adding blank rows to the grid until grid's height is >= the height of the window would also be acceptable.
A flex solution is, I believe, not acceptable, as I need a grid-like behaviour where columns and rows remain aligned.
Thank you
Since different columns have different colors, extending the grid would not work, because the grid itself can't have two different colors. This means only expanding the rows or adding new rows would work.
Since one of the question's requeriments is to leave row height untouched, and as per this question, adding an extra row and expanding only that row to take the remaining space is not possible with CSS grid (but flexbox), the only solution seems to add rows via JS until the grid height is >= window height :
var rowHeight = window.getComputedStyle(document.querySelector('.grid').firstElementChild).height;
var row = "<div class='index' style='height:"+ rowHeight +"'></div><div class='title' style='height:"+ rowHeight +"'></div><div class='ticker' style='height:"+ rowHeight +"'></div>";
while (parseFloat(window.getComputedStyle(document.querySelector('.grid')).height) < window.innerHeight) {
document.querySelector('.grid').innerHTML += row;
}
html, body {
margin: 0;
padding: 0;
}
.grid {
align-self: flex-start;
display: grid;
grid-template-columns: min-content 2fr 1fr;
grid-gap: 0px;
}
.index, .title {
background: red;
padding: 0 2vw 0 1vw;
}
.ticker {
background: yellow;
}
<div class="grid">
<div class="index">1</div>
<div class="title">Pigs are cute</div>
<div class="ticker">blah blah</div>
<div class="index">2</div>
<div class="title">Horses rise at night</div>
<div class="ticker">bleh bleh</div>
<div class="index">3</div>
<div class="title">Cats run in packs</div>
<div class="ticker">blih blih</div>
</div>

CSS: Set divs horizontally in 2 rows

Lets say I have
<div class="cont">
<div class="single">1</div>
<div class="single">2</div>
<div class="single">3</div>
<div class="single">4</div>
<div class="single">5</div>
<div class="single">6</div>
<div class="single">7</div>
</div>
What I want to have is to plase the .single divs in 2 rows like bricks horizontaly from left to right this simple way: 1st div will be in left top corner, 2nd will be placed below 1st, 3rd will be placed next to 1st, 4th will be placed below 3rd and so on like:
1 3 5 7 9
2 4 6 8
All the divs has the same size.
I've tried with masonry.js and its working like a charm, but its way to complex solution for so simple task (simply solution is important).
fiddle playground
There is a CSS property that does exactly that
http://tinker.io/8ff59
.cont {
-webkit-columns: 5em;
-moz-columns: 5em;
columns: 5em; /* desired width of column */
}
http://caniuse.com/#feat=multicolumn
I had the very same problem and solved using the grid.
Here's the CSS you should add to your container:
.cont {
height: 220px;
background: red;
display: grid;
grid-template-rows: repeat(2, 100px);
gap: 10px;
grid-auto-flow: column;
grid-auto-columns: 100px;
}
I don't think you can do that with css with structure as you have.
This structure should help you to get your required layout:
<div class="a">
<div class="b">
<div class="c">1</div>
<div class="c">2</div>
</div>
<div class="b">
<div class="c">3</div>
<div class="c">4</div>
</div>
</div>
<style>
div.a div.b {float: left; width: 100px;}
</style>
For the sake of argument, let's say you can't change your document structure - you need to do this through layout definitions alone.
If you know how many items you will have, the easiest way to manage this would be CSS3 columns with inline-block elements. Your .singles are the inline-blocks, and .cont uses the 'columns' property to set 5 columns each wide enough to hold your singlets, whilst using max-height to force the inline-blocks onto new columns every two items. The singlets have a min-size large enough to stop multiple inline-blocks displaying on the same line.
You can see this effect as a jsfiddle here: http://jsfiddle.net/mwjJG/25/ :
.container {
height: 240px;
columns: 100px 5;
-webkit-columns: 100px 5;
-moz-columns: 100px 5;
}
.single {
display: inline-block;
height: 100px;
width: 100px;
}
Do be aware this won't work on IE<10 unless you can use some kind of JS-based shiv to add support for the columns property (CSS Pie may be able to do this).
I accomplished this with CSS here using this code: It's kind of hackish though.
I set three of the divs (the last three) to the class 'double'
.cont .single {
background: blue;
color: white;
width: 100px;
height: 100px;
margin: 10px;
float:left;
display: inline-block;
}
.cont .double {
background: blue;
color: white;
width: 100px;
height: 100px;
margin: 10px;
display:inline-block;
float:left;
}
div:nth-child(5) {
clear:left;
}
.cont {
height: 220px;
background: red;
}

Categories