I am working on react web app which has less styling, so under
wrapper I have 3 columns, such that leftWrap is col-3, rightWrap is
col-4, and rest width is centerWrap. How can i apply flex while i just
know its col-* classnames
<div className={styles.Home__wrapper}>
<div className={styles.Home__leftWrap}> .... </div>
<div className={styles.Home__centerWrap}> .... </div>
<div className={styles.Home__rightWrap}> .... </div>
</div>
.Home {
&__wrapper {
display : flex;
flex-wrap: nowrap;
width : 100%;
box-sizing: border-box;
}
&__leftWrap {
display : flex;
}
&__rightWrap {
display : flex;
}
&__centerWrap {
display : flex;
}
}
How to set width to each column className as per above mentioned, is
it through cal() method
Set the display CSS attribute on the container div to flex, and play with the flex attribute on the children elements. Flex will sum up the flex number assigned to each children element to calculate the "total" steps to be filled, then calculate the value of each step based on the available space remaining and calculate the display width of each child by multiplying the calculated step width value by the child element flex value. In your case, it looks like your left and right children have fixed widths, and you want the center element to take the remaining space, so just set flex to 1 on the center element.
._wrapper {
display : flex;
flex-wrap: nowrap;
box-sizing: border-box;
}
._leftWrap {
width: 50px;
background-color: red;
}
._rightWrap {
width: 100px;
background-color: blue;
}
._centerWrap {
flex: 1;
background-color: yellow;
}
<div class="_wrapper">
<div class="_leftWrap"> .... </div>
<div class="_centerWrap"> .... </div>
<div class="_rightWrap"> .... </div>
</div>
Related
Hello I'm not too good with css/floats/blocks etc.
I have this sort of setup
<div class="blue">1</div>
<div class="red">2</div>
<div class="blue">3</div>
<div class="red">4</div>
<div class="blue">5</div>
<div class="red">6</div>
I want to style it so 1 and 2 are on the same line (floated left and right), then 3 and 4 are on the same line (floated left and right) and so on and so forth.
Currently these elements are created in a loop. I have tried all sorts of methods to get the elements to line up how I want to no avail.
I think you want to make them two per row correct?
You can add a flex property to the parent container. Set the flex-wrap to wrap, then add a 50% width on your child elements (taking into account any inherited margin or padding effecting the layouts width to not overflow the flex-wrap), then justify-content to space-between, this will force the elements to their respective sides or a better way to put it is; place the "left over" space the children on that row are not taking up, in the middle of the two elements.
* { /* set box-sizing on all elements to border-box */
box-sizing: border-box;
}
body { /* remove any margin or padding from the body */
margin: 0;
padding: 0;
}
#cont { /* add display flex, flex-wrap and justify-content to space between */
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
#cont>div { /* Set your child divs to a percentage that will only give you two per row
the flex-wrap will push elements down */
width: 50%;
}
.blue {
background-color: lightblue;
border: 1px solid darkblue;
}
.red {
background-color: pink;
border: 1px solid darkred;
text-align: right; /* remove if you want standard left side text-alignment on red elements */
}
<div id="cont">
<div class="blue">1</div>
<div class="red">2</div>
<div class="blue">3</div>
<div class="red">4</div>
<div class="blue">5</div>
<div class="red">6</div>
</div>
If this is not what you were looking for let me know and I can edit or remove this answer.
My problem is that I want the flexbox with variable range width, and all works well, but not on the last row. I want the same dimension for all children even where the row is not full of children (the last row).
#products-list {
position:relative;
display: flex;
flex-flow: row wrap;
width:100%;
}
#products-list .product {
min-width:150px;
max-width:250px;
margin:10px 10px 20px 10px;
flex:1;
}
I created a dynamic situation in jsFiddle
My flex divs can shrink until 150px and grow up to 250px, but all must be with the same size (and obviously I want a CSS solution, with JS I know the way).
Unfortunately, in the current iteration of flexbox (Level 1), there is no clean way to solve the last-row alignment problem. It's a common problem.
It would be useful to have a flex property along the lines of:
last-row
last-column
only-child-in-a-row
alone-in-a-column
This problem does appear to be a high priority for Flexbox Level 2:
CSS Working Group Wiki - Specification Issues and Planning
https://lists.w3.org/Archives/Public/www-style/2015Jan/0150.html
Although this behavior is difficult to achieve in flexbox, it's simple and easy in CSS Grid Layout:
Equal width flex items even after they wrap
In case Grid is not an option, here's a list of similar questions containing various flexbox hacks:
Properly sizing and aligning the flex item(s) on the last row
Flex-box: Align last row to grid
Flexbox wrap - different alignment for last row
How can a flex item keep the same dimensions when it is forced to a new row?
Selector for an element alone in a row?
Aligning elements in last flexbox row
How can I allow flex-items to grow while keeping the same size?
Left-align last row of flexbox using space-between and margins
Inconsistent margin between flex items on last row
How to keep wrapped flex-items the same width as the elements on the previous row?
How to align left last row/line in multiple line flexbox
Last children of grid get giant gutter cause of flexbox space-between
Managing justify-content: space-between on last row
Flexbox space between behavior combined with wrap
Possible to use CSS Flexbox to stretch elements on every row while maintaining consistent widths?
As a quick and dirty solution one can use:
.my-flex-child:last-child/*.product:last-child*/ {
flex-grow: 100;/*Or any number big enough*/
}
You could try using grid instead of flexbox here:
#products-list {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(auto-fit, minmax(100px, 250px)); //grid automagic
justify-content: start; //start left
}
Fiddle link
There is a great solution that works always.
add a div with class product (The same class for other items that are under flex) and add a style for this div:height:0px;
you need to add as many dives that are possible to be in one row.
<div class="product" style="height:0px">
as many that can be in one row.
That's all. Works always.
If all your rows have the same number of items, you can use :nth-last-child. For example, if all the rows have 3 items, you can do something like this to remove the margin of the last 3 items:
.container{
display: flex;
flex-wrap: wrap;
background: yellow;
}
.item{
width: calc((100% - 2*10px)/3);
height: 50px;
background: blue;
color: white;
margin-right: 10px;
margin-bottom: 10px;
padding: 5px;
box-sizing: border-box;
}
/* last item of each row */
.item:nth-child(3n){
margin-right: 0;
font-size: 150%;
}
/* last 3 items */
.item:nth-last-child(-n+3){
margin-bottom: 0;
background: green;
}
<div class="container">
<div class="item" >1</div>
<div class="item" >2</div>
<div class="item" >3</div>
<div class="item" >4</div>
<div class="item" >5</div>
<div class="item" >6</div>
<div class="item" >7</div>
</div>
A simple trick adds a flexible space to fill the rest of the last row:
#products-list{
display:flex;
flex-flow: row wrap;
justify-content:space-between;
}
#products-list::after {
content: "";
flex: auto;
flex-basis: 200px;/*your item width*/
flex-grow: 0;
}
But you shouldn't use margins on items then. Rather wrap them into containers with padding.
I used this workaround, even if it's not very elegant and it doesn't use the power of Flexbox.
It can be carried out on the following conditions:
All the items have the same width
The items have a fixed width
You use SCSS/SASS (can be avoided though)
If this is the case, you can use the following snippet:
$itemWidth: 400px;
$itemMargin: 10px;
html, body {
margin: 0;
padding: 0;
}
.flex-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0 auto;
border: solid 1px blue;
}
#for $i from 1 through 10 {
#media only screen and (min-width: $i * $itemWidth + 2 * $i * $itemMargin) {
.flex-container {
width: $i * $itemWidth + 2 * $i * $itemMargin;
}
}
}
.item {
flex: 0 0 $itemWidth;
height: 100px;
margin: $itemMargin;
background: red;
}
<div class="flex-container">
<div class="item"></div>
<div class="item" style="flex: 500 0 200px"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Here I have created an example on codepen which also implements margin.
The second and the third conditions can be avoided respectively using css variables (if you decided to provide support for it) and compiling the above scss snippet.
Well, it's true, we could do it also before flexbox, but display: flex can be still essential for a responsive design.
I was facing this same issue where I wanted to have a variable number of items in a resizable container.
I wanted to use all of the horizontal space, but have all of the flex items at the same size.
I ultimately came up with a javascript approach that dynamically added padding spacers as the container was resized.
function padLastFormRow() {
let topList = [];
let nSpacersToAdd = 0;
$('#flexContainer').find('.formSpacer').remove();
$('#flexContainer').find('.formItem').each(function(i, formItem) {
topList.push($(formItem).position().top);
});
let allRowLengths = getFlexLineLengths(topList);
let firstRowLength = allRowLengths[0];
let lastRowLength = allRowLengths[((allRowLengths.length) - 1)];
if (lastRowLength < firstRowLength) {
nSpacersToAdd = firstRowLength - lastRowLength ;
}
for (var i = 1; i <= nSpacersToAdd; i ++) {
$('#flexContainer').append(formSpacerItem);
}
}
Please see my Fiddle:
http://jsfiddle.net/Harold_Buchman/z5r3ogye/11/
I was having a similar challenge with menu rows. I wanted more spacing on the top of the second row of menu items.
The use of flex-box's row-gap worked well.
https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap
.menu {
display: flex;
flex-wrap: wrap;
row-gap: 10px;
}
This added a margin-top type effect to menu items were wrapped to the second line.
If all your rows have the same number of items, you can use :nth-last-child. For example, if all the rows have 3 items, you can do something like this:
.container{
display: flex;
flex-wrap: wrap;
background: yellow;
}
.item{
width: calc((100% - 2*10px)/3);
height: 50px;
background: blue;
color: white;
margin-right: 10px;
margin-bottom: 10px;
padding: 5px;
box-sizing: border-box;
}
// last item of each row
.item:nth-child(3n){
margin-right: 0;
background: green;
}
// last 3 items
.item:nth-last-child(-n+3){
margin-bottom: 0;
font-size: 150%;
}
<div class="container">
<div class="item" >1</div>
<div class="item" >2</div>
<div class="item" >3</div>
<div class="item" >4</div>
<div class="item" >5</div>
<div class="item" >6</div>
<div class="item" >7</div>
</div>
I have a need to create a grid of data. Ideally, I would like to use CSS Grid. The grid will be potentially large and need to scroll horizontally and vertically. However, the first row and the first column must always be visible. The effect I'm going for is similar to "freezing panes" in Excel (sometimes called "locking" rows and/or columns).
Additionally, after scrolling, I'll need to be able to click on items in the grid as well as implement some drag/drop behavior.
I have this working using a technique that utilizes HTML tables and the sticky and z-index CSS properties. You can see that working in the following fiddle: https://jsfiddle.net/dmboucher/txcLkq60/26/
Notice how you can scroll horizontally and vertically, but you can always see the first row and the first column.
There are reasons why using html tables for this is less than ideal. I would rather use CSS Grid or FlexBox... no html tables. My experiments with CSS Grid and FlexBox have failed so far.
I investigated the concept of using CSS masking and/or clipping. The idea here would be to have a massive div (the grid) in the background, but only be able to view it "through" a mask "window", then use scrollbars and javascript to move the large div behind the mask such that you can see the desired portion of the grid. Something to that effect. I have not been able to get that to work either.
The only method that has been successful has been with html tables.
Can this be done without using html tables? Other suggestions?
Thank you for your help!
I eventually figured out a way to do this. I laid out a FlexBox grid of div's with the appropriate stylings. Conceptually, I laid out a 9 "cell" matrix like so:
.
.
.
Upper left
Times
Spacer
Employees
Schedule
Vertical Scrollbar
Spacer
Horizontal Scrollbar
Spacer
In this way, Times will scroll horizontally, Employees will scroll vertically, and Schedule will scroll both horizontally and vertically.
The key was that Employees, Schedule, and Vertical Scrollbar all had to have the same computed height. Similarly, Times, Schedule, and Horizontal Scrollbar all had to have the same computed width. If not, then the scrolling would get janky.
Once all the styles were added such that everything rendered properly (i.e. overflow, flex-shrink, etc.), then, I added onscroll functions to the Horizontal and Vertical Scrollbar elements. Whenever horizontal scroll events fire, I synchronize the schedule and times scrollLeft values. Whenever vertical scroll events fire, I synchronize the schedule and times scrollTop values.
The relevant sync functions are like so:
function bodyOnLoad() {
let id = "timeline";
let tag = `<div class="timeline_grid_row timeline_grid_header_row">
<div class="timeline_grid_controls">Upper Left</div>
<div id="${id}_timeline_calendar_container_grid_times" class="timeline_grid_times">
${[...Array(24).keys()].map((i) => {
return `<div class="timeline_grid_cell">hour ${i}</div>`;
}).join("\n")}
</div>
<div class="timeline_grid_spacer_cell ur"> </div>
</div>
<div class="timeline_grid_row timeline_grid_body_row">
<div id="${id}_timeline_calendar_container_grid_employees" class="timeline_grid_employees">
${[...Array(35).keys()].map((i) => {
return `<div class="timeline_grid_employee_cell">worker ${i}</div>`;
}).join("\n")}
</div>
<div id="${id}_timeline_calendar_container_grid_schedule" class="timeline_grid_schedule">
${[...Array(35).keys()].map((i) => {
return `<div class="timeline_grid_schedule_row">
${[...Array(24).keys()].map((j) => {
return `<div class="timeline_grid_cell">content ${i}-${j}</div>`;
}).join("\n")}
</div>`;
}).join("\n")}
</div>
<div class="timeline_grid_scroll_vertical" onscroll="TimelineSynchronizeVerticalScroll('${id}', this)">
${[...Array(35).keys()].map((i) => {
return '<div class="timeline_grid_spacer_cell cr"> </div>';;
}).join("\n")}
</div>
</div>
<div class="timeline_grid_row timeline_grid_footer_row">
<div class="timeline_grid_spacer_cell ll"> </div>
<div class="timeline_grid_scroll_horizontal" onscroll="TimelineSynchronizeHorizontalScroll('${id}', this)">
${[...Array(24).keys()].map((i) => {
return '<div class="timeline_grid_horizontal_filler_cell"> </div>';
}).join("\n")}
</div>
<div class="timeline_grid_spacer_cell lr"> </div>
</div>`;
document.getElementById(`${id}_calendar_container_grid`).innerHTML = tag; // write to DOM
}
function TimelineSynchronizeHorizontalScroll(id, scrollControl) {
document.getElementById(`${id}_timeline_calendar_container_grid_schedule`).scrollLeft = scrollControl.scrollLeft;
document.getElementById(`${id}_timeline_calendar_container_grid_times`).scrollLeft = scrollControl.scrollLeft;
}
function TimelineSynchronizeVerticalScroll(id, scrollControl) {
document.getElementById(`${id}_timeline_calendar_container_grid_schedule`).scrollTop = scrollControl.scrollTop;
document.getElementById(`${id}_timeline_calendar_container_grid_employees`).scrollTop = scrollControl.scrollTop;
}
.timeline_control .timeline_calendar {
display: flex;
width: 500px;
height: 150px;
flex-shrink: 0;
}
.timeline_control .timeline_calendar .timeline_calendar_container_grid * {
display: flex;
}
.timeline_control .timeline_calendar .timeline_calendar_container_grid {
display: flex;
flex-direction: column;
overflow: hidden;
}
.timeline_control .timeline_calendar .timeline_grid_row {
overflow: hidden;
}
.timeline_control .timeline_calendar .timeline_grid_row.timeline_grid_header_row,
.timeline_control .timeline_calendar .timeline_grid_row.timeline_grid_footer_row {
flex-shrink: 0;
}
.timeline_control .timeline_calendar .timeline_grid_controls {
flex-shrink: 0;
width: 150px;
}
.timeline_control .timeline_calendar .timeline_grid_times {
overflow: hidden;
}
.timeline_control .timeline_calendar .timeline_grid_employees {
flex-direction: column;
flex-shrink: 0;
overflow: hidden;
width: 150px;
}
.timeline_control .timeline_calendar .timeline_grid_schedule {
flex-direction: column;
overflow: hidden;
}
.timeline_control .timeline_calendar .timeline_grid_cell {
flex-shrink: 0;
margin: 0 10px;
width: 100px;
}
.timeline_control .timeline_calendar .timeline_grid_scroll_horizontal {
height: 18px;
overflow-x: auto;
overflow-y: hidden;
}
.timeline_control .timeline_calendar .timeline_grid_scroll_vertical {
flex-direction: column;
flex-shrink: 0;
overflow-x: hidden;
overflow-y: auto;
width: 18px;
}
.timeline_control .timeline_calendar .timeline_grid_horizontal_filler_cell {
flex-shrink: 0;
margin: 0 10px;
width: 100px;
}
.timeline_control .timeline_calendar .timeline_grid_spacer_cell {
flex-shrink: 0;
}
.timeline_control .timeline_calendar .timeline_grid_spacer_cell.ur {
width: 8px;
}
.timeline_control .timeline_calendar .timeline_grid_spacer_cell.cr,
.timeline_control .timeline_calendar .timeline_grid_spacer_cell.lr {
width: 18px;
}
.timeline_control .timeline_calendar .timeline_grid_spacer_cell.ll {
width: 150px;
}
<body onload="bodyOnLoad()">
<div class="timeline_control">
<div class="timeline_calendar">
<div id="timeline_calendar_container_grid" class="timeline_calendar_container_grid"></div>
</div>
</div>
</body>
Now I have the UI I'm going for... with no html tables. Mission Accomplished!
I just thought I'd share this solution in case it helps others in the future.
Here is a working fiddle of this solution: https://jsfiddle.net/dmboucher/Lwqdcpv8/
I am tring to display two div inside a nav on the rigth, the problem is that if I set this div <div _ngcontent-c9="" class=" ng-clock docs-homepage-row menuSup"> as float: right in the css, it will not goes on the right part of the screen.
<nav _ngcontent-c1="" class=" ng-clock docs-navbar-header menuDate">
<div _ngcontent-c9="" class=" ng-clock docs-homepage-row menuSup">
<div _ngcontent-c9="" class=" ng-clock docs-homepage-promo-img">
...
</div>
<div _ngcontent-c9="" class=" ng-clock docs-homepage-promo-img" >
...
</div>
</div>
</nav>
CSS
.docs-navbar-header[_ngcontent-c1] {
display : flex;
flex-wrap : wrap;
align-items : center;
padding : 12px 16px;
}
.menuDate{
width: 100%;
background: var(--defaultColorDark);
}
.docs-homepage-row[_ngcontent-c9] {
display : flex;
max-width : 920px;
margin : 60px 0;
float: right;
}
.menuSup[_ngcontent-c9] {
display : flex;
width: 100%;
margin : 10px 10px;
float: right;
}
.docs-homepage-row[_ngcontent-c9] .docs-svg-image[_ngcontent-c9] {
max-width : 90%;
}
.docs-homepage-promo-desc[_ngcontent-c9], .docs-homepage-promo-img[_ngcontent-c9] {
width : 50%;
}
.docs-homepage-promo-img[_ngcontent-c9] {
text-align : center;
margin-top: 20px;
}
There is many options to achieve what you need, but using float property is not the best one. Each following options will be interesting depending of the context.
[OPTION #1] (recommended)
If .docs-homepage-row.menuSup is the only one child of .docs-navbar-header.menuDate, you can simply apply justify-content: flex-end; to .docs-navbar-header.menuDate.
Learn more about Flexbox there : https://css-tricks.com/snippets/css/a-guide-to-flexbox/
[OPTION #2] (usefull)
Apply margin-left: auto; to .docs-homepage-row.menuSup will push the flex-item to the right.
[OPTION #3] (not recommended)
If, for some reason, you really need to use float, be aware that you need to "clear" the next element. The best way to achieve it, it's to use the clearfix hack on the parent.
You can learn more about the clearfix hack on the following link : https://css-tricks.com/snippets/css/clear-fix/
I'm trying to create a grid layout that sizes all child divs to match the tallest div in the group. For example, I have a 2x2 grid, with each div in the grid containing some text. The div that contains the most text is tallest, and should push the height on the other 3 divs to match.
I can get the div heights to match on each row using display: flex; and flex-wrap: wrap;, but I need all rows to match in height.
Is this possible to accomplish with CSS, or will I need to resort to jQuery?
<section class="grid two">
<div>
<div>
<p>The top left div</p>
</div>
</div>
<div>
<div>
<p>The top right div</p>
</div>
</div>
<div>
<div>
<p>The bottom left div</p>
</div>
</div>
<div>
<div>
<p>The bottom right div</p>
<p>this has more text, and should casue the rest to strecth to match its height.</p>
</div>
</div>
</section>
And my current CSS is:
.grid {
display: flex;
flex-wrap: wrap;
}
.grid > div {
box-sizing: border-box;
display: flex;
flex-directon: column;
padding: 10px;
width: 50%;
}
.grid > div > div {
background: #EEE;
flex: 1 1 auto;
width: 100%;
}
Here's a fiddle: http://jsfiddle.net/g41xas6w/
Update 1: I can't used a fixed height for two reasons:
The client will be able to edit this text, so I can't always know what the height will be.
This is a responsive site, so I'd have to do a whole bunch of breaks to ensure that things are always displaying at the correct height.
http://brm.io/jquery-match-height/
Please see the link above. These guys have created a jQuery plugin to achieve the effect you are after.
Your solution would work only for the 4 DIVs in a single horizontal line. Change the width and look! If you require the 2X2, the dynamically getting the height of all 4 to be same is not possible with only CSS. You need to either use script to control it or have a height set which would stop being dynamic!
If you put a height tag in the .grid > div with for example 200px it will all be 200px
.grid > div {
box-sizing: border-box;
display: flex;
flex-directon: column;
padding: 10px;
width: 50%;
height: 200px;
}