Negative margin not working with flexbox - html

I'm trying to create a grid layout with the help of the flexbox.
What I'm doing is that I'm giving parent negative margin on left and right and then giving its child the same amount of padding on left and right for the gutter space.
I'm trying to make 5 column grid and when I use flex: 1 1 20% all the columns are not coming in the same row. The last get wrapped in the next row. This should not be the case as flex-basis is set to 20% and parent should accommodate all five columns in one row.
But when I'm trying to do this, the 4th grid item is getting wrapped on the next line.
Here is the working codepen for this issue.
Updated the codepen:
https://codepen.io/vikrantnegi007/pen/BZwGJQ
Thanks.

If I add bootstrap to to your codepen it works, which means you have some other issue we can't see in your original code.
Note though, based on your image's settings, your elements still might wrap
Still, instead of doing negative margin tricks, create a gutter, use justify-content: space-around and flex-basis.
Updated codepen
//testing css
.buisness-blocks {min-height: 250px;}
//main css
.buisness-blocks {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.block {
flex-basis: calc(20% - 10px);
outline: 1px solid;
}
}

Is box-sizing the CSS property you are looking for?
Giving the block's a box-sizing of border-box, they all come next to each other:
.block {
flex: 0 1 20%;
padding-right: 10px;
padding-left: 10px;
outline: 1px solid;
box-sizing: border-box;
}
https://codepen.io/anon/pen/vZeQjO

Just Try This hope its work
.buisness-blocks {min-height: 250px;}
.buisness-blocks {
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
margin-right: 0px;
margin-left: 0px;
.block {
flex: 0 1 20%;
-webkit-flex: 10; /* Safari 6.1+ */
-ms-flex: 10; /* IE 10 */
flex: 2;
padding-right: 10px;
padding-left: 10px;
outline: 1px solid;
}
}
CLICK HERE for DEMO

If the negative margins isn't working with display flex, but you can try to use transform:
At the CSS style properties of the inner element add the translate that you wanna.
Example:
transform: translateY(15px);
P.S.: transform isn't portable to all browsers.

Related

Flexbox justify wrapped content with same sized elements

I was using CSS-Grid to make a list of elements that had a min-width of 35px and the size would adapt if you resized the window, so that always as many elements as possible could fit into one row, and the gap on the right of the row would always be the same as it was on the left using this CSS:
article{
display: grid;
grid-template-columns: repeat(auto-fill, minmax(35px, 1fr));
grid-gap: 5px;
}
div{
height: 35px;
background-color: lightblue;
}
You can try it here, by rescaling the window.
https://jsfiddle.net/k36jy0ou/39/
But due to compability problems I now want to make the same behaviour using flexbox. I don't know flexbox really well, but I got kind of close using this CSS:
article{
display: flex;
flex-wrap: wrap;
}
div {
flex-grow: 1;
min-width: 35px;
max-width: 40px;
background-color: lightblue;
height: 35px;
margin: 5px;
}
https://jsfiddle.net/k1tmfu7o/3/
Except, that not all elements have the same size, if you do it like this.
Here is an image to explain my problem
Is there any way to do it using flexbox?
Thank you for your help.
Already has an answer here
Working example from the answer above
SASS code
=flex-wrap-fix($flex-basis, $max-viewport-width: 2000px)
flex-grow: 1
flex-basis: $flex-basis
max-width: 100%
$multiplier: 1
$current-width: 0px
#while $current-width < $max-viewport-width
$current-width: $current-width + $flex-basis
$multiplier: $multiplier + 1
#media (min-width: $flex-basis * $multiplier)
max-width: percentage(1 / $multiplier)
ul
display: flex
flex-wrap: wrap
li
// I want the width to be between the following two sizes
min-width: 40px
//max-width: 100px
// this keeps all the elements the same size
// **as long as they are on the same row**
// but I want them to all the same width everywhere
//flex: 1 0 0
+flex-wrap-fix(100px)
// demo styles
ul, li
margin: 0
padding: 0
list-style: none
ul
background-color: tomato
li
.content
margin: .5em
background-color: darkgreen
// the image may have variable width, I want it to take the entire space calculated by flexbox
img
width: 100%
opacity: .5
figure, img
margin: 0
padding: 0
Remove
flex-grow:1;
and they will be the same size!
I don't know it is what you want or not, just add the attribute on the class article:
justify-content: space-around;
or
justify-content: space-between;
The gap will disappear.

Vertical list of elements, where each row shrinks its width to match the inner content

I want to create a vertical list, where each row shrinks its width to perfectly contain its inner content (versus the default div behavior of expanding its width to fill the container).
I'd like to do this with only one HTML element for each row (no extra wrapping divs).
The following code does exactly what I want, but it doesn't work in Safari (bug?).
.container {
margin: 10px;
border: 2px solid #999;
padding: 5px;
display: flex;
flex-direction: column;
width: 300px
}
.row-item {
padding: 5px;
margin: 5px;
border: 1px solid green;
/* this will shrink the width to the inner content
in Chrome and Firefox, but not in Safari */
margin-right: auto;
}
<div class='container'>
<div class='row-item'>Item #1</div>
<div class='row-item'>Another Item...</div>
<div class='row-item'>Item No. 3</div>
</div>
Here is a codepen with the above code: http://codepen.io/anon/pen/woKYqx
I know that it is trivial to solve this problem by adding a wrapping div and then using display: inline-block on the inner element (or several other similar solutions).
However, it seems like it should be possible to solve this without adding extra HTML elements. It is a fairly simple layout.
Is there a cross-browser way to do this with a single HTML element for each row?
You're using margin-right: auto to push the element all the way to the left, which also forces the item to take the width of its content.
This is a good method but, as you've noted, it fails in Safari.
A simple alternative is to use align-self: flex-start on the flex items:
.row-item {
padding: 5px;
margin: 5px;
border: 1px solid green;
align-self: flex-start; /* NEW */
/* margin-right: auto; (can be kept or removed) */
}
OR, just use align-items: flex-start on the flex container.
.container {
margin: 10px;
border: 2px solid #999;
padding: 5px;
display: flex;
flex-direction: column;
align-items: flex-start; /* NEW */
width: 300px
}
You can erase all flex stuff and use float:left and clear:left on the children, and overflow-x: hidden on the parent:
http://codepen.io/anon/pen/pNjQJJ
When you are using display: flex you should also use the vendor prefixes for it.
too support older versions of browsers
when in doubt check up on caniuse.com
.container {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -webkit-flex; /* NEW - Chrome */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: flex;
/* ETC */
}
NOTE: caniuse.com have written about bugs being reported about flexbox childrens height in safari.

get the height of the previous element

Can i get the height of the previous element using only CSS?
I am using calc() function to set dynamically height of the div B.
#b{
height:calc(100vh - heightOfPreviousElement);
}
I need to know the height of the previous element.
what i know is that, 100vh is equal to 100% of the screen height.
I used the code in the answer below.Using flex,
I have one problem. The height of the color orange become smaller.
You can easily achieve the effect you're looking for using flexbox. The trick is to allow the blue container (the one with the flexible height) to grow in size whenever the need arises, using flex: 1 1 auto, which is simply a shorthand for:
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
See proof-of-concept code snippet below:
body {
padding: 0;
margin: 0;
}
.wrapper {
display: flex;
flex-direction: column;
flex-wrap: no-wrap;
align-items: center;
justify-content: center;
height: 100vh;
}
.wrapper > div {
width: 100%;
}
#c1 {
background-color: #880015;
color: #fff;
height: 60px;
margin-bottom: 10px;
}
#c2 {
background-color: #ff7f27;
}
#c3 {
background-color: #00a2e8;
flex: 1 1 auto;
margin-bottom: 10px;
}
<div class="wrapper">
<div id="c1">height: 60px</div>
<div id="c2">height: auto (determined by content?)</div>
<div id="c3">flexible height</div>
</div>
No you can't select a previous element in CSS.
You might be interested in JQuery Prev OR Parents method for selecting previous element and apply height using .css() method?

Make two flex items each 50% height of parent

I am using css flex layout to build a dashboard and would like to put two widgets (one on top of the other) inside of a flex item and make them 50% height of their parent at all times (regardless of content). So if my html is:
<div class="flex-container">
<div class="flex-item">
<div class="widget" id="w1">
widget 1 content
</div>
<div class="widget" id="w2">
widget 2 content
</div>
</div>
</div>
and my css looks like:
.flex-container {
display: flex;
flex-direction: column;
}
.flex-item {
flex: 1;
}
How can I get the two .widgets to always occupy 50% height of .flex-item?
I've tried:
.flex-item {
flex: 1;
display: flex;
}
.widget {
flex: 1;
}
But this only works when the content in both widgets are the same.
I've worked up a more elaborate jsfiddle to better illustrate my issue.
Thanks in advance!
When you say that flex: 1 only works when the content in both widgets are the same, that is not correct. That would defeat the purpose of flex: 1.
flex: 1 tells flex items to distribute container space evenly among themselves. If there are four flex items with flex: 1, each will take 25%. Three would take 33.33%. And two flex items will take 50%. This is regardless of content quantity.
See this illustration: DEMO
The problem you're having is not clear in the code you posted in the question. However, it's apparent in your fiddle demo.
You have a main container with a height: 400px. You also have a rule adding 10px padding all-around to your divs. This adds 20px height to each div. You also have a header with height: 2em.
When you account for the extra heights the layout works.
Try these adjustments:
HTML (no changes)
CSS
div {
box-shadow: inset 0 0 0 1px rgba(30, 100, 200, 0.5);
padding: 10px; /* sneaky villain */
font-family: arial;
}
h1, p { margin: 0; }
#main-wrapper {
height: 400px; /* primary height */
display: flex;
flex-direction: column;
}
#header {
flex-shrink: 0;
height: 2em; /* header height */
}
#main-column-wrapper {
flex: 1;
display: flex;
flex-direction: row;
height: calc(100% - 2em - 20px); /* primary height - header height - padding */
}
#side-column {
width: 20%;
flex-shrink: 0;
}
#main-column {
flex: 1;
display: flex;
flex-direction: column;
height: calc(100% - 40px); /* main-column-wrapper height - padding (2 divs) */
}
#widget1,
#widget2 {
flex: 1;
flex-shrink: 0;
overflow: auto;
}
Revised Fiddle
Another option would be to use box-sizing: border-box to adjust for the padding. Learn more here: https://css-tricks.com/box-sizing/

How can I set a minimum amount of space between flexbox items?

Given this CSS:
div.container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
border: 1px solid blue;
}
div.container div {
width: 200px;
border: 1px solid gray;
display: inline-block;
text-align: center;
}
This layout has the first item in each row aligned to the left, and the last item aligned to the right, as required.
As the browser window is made narrower, the distributed div elements will move closer together until they touch, at which point they are re-arranged over an additional row. Again, the first div on each row is aligned left, and the last aligned right with space between.
Is there any way of setting a minimum spacing so that the inner div elements always have a gap between them.
padding and margin will probably not work, as the alignment
<-- 1st left in row and last right in row --> will not hold.
Bit late the the party but I ran into the same issue. The way I solved it probably wont work for everyone but here it is for those who can use it.
The basic idea is that you have a min gap of x. You set the left and right margins of each item to x/2 so that the distance between the items will be x (margin + margin). Then you wrap all of the items in a container with a left and right margin of -x/2. This will hide the margin on the items at the edges of each row.
Here is a working example:
.box {
border: 1px solid black;
overflow-x: hidden;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin: 0 -1em;
}
.item {
display: flex;
border: 1px solid grey;
padding: 1em;
width: 20%;
margin: 0 1em;
}
<div class="box">
<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>
</div>
The overflow-x: hidden; on .box is to prevent the horizontal scrollbar that shows up in some browsers because of the margin overflowing.
If you want the gap to always be consistent and for rows with only one item to have that item span the whole row then you can add flex-grow: 1 to .item.
You can add another div with flex style for holding the needed gap between inner divs. and for the minimum width for that gap use this property (as mentioned in W3Schools.com):
flex: flex-grow flex-shrink flex-basis|auto|initial|inherit;
which flex-shrink is :
flex-shrink: A number specifying how much the item will shrink relative to the rest of the flexible items
so, for example you set this css code for the gap div :
flex: 1 0 10px;
that tells gap div will have 10px width, and will grow relative to the rest of the flexible items, but WON'T SHRINK. so the minimum width will be 10px at the narrowest width of the screen.
In 2022 you can just use gap CSS property:
div.container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
border: 1px solid blue;
gap: 20px;
}
To support older browsers you may use margin hack.
div.container > * {
margin: 12px 0 0 12px;
}
div.container {
display: inline-flex;
flex-wrap: wrap;
margin: -12px 0 0 -12px;
width: calc(100% + 12px);
}
Since April 2021 support for flexbox-gap has arrived in all major browsers (IE considered dead). Combining it w/ space-between solves your problem.
div.container {
display: flex;
gap: 10px; /* minimum gap between flex-items */
justify-content: space-between;
}
It's a couple of days passed since this question was asked, but I thought I should add my solution if anybody comes past and has the same issue.
I suggest using calc, width, and media to solve this issue. Yes, it's a little work but it's a visual clean solution in my opinion.
.main{
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.main > div{
width: 100%;
height: 125px;
border: 1px solid red;
}
#media (min-width: 576px) {
.main > div{
width: calc(100% / 2 - 5px);
margin-bottom: 5px;
}
}
#media (min-width: 992px) {
.main > div{
width: calc(100% / 3 - 5px);
}
}
#media (min-width: 1140px) {
.main > div{
width: calc(100% / 6 - 5px);
margin-bottom: 0;
}
}
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
For the needed breakpoints I calculate the width I want the divs to use and subtract the space I want them to have.
I hope this helps someone and that I explained it understandable.
Regards.
Setting a flex-basis with percentage also will do the trick. Then the min space between will be also in percentage.
For instance, with 3 elements, flex: 0 0 30% will allow a fixed 10% space reparted between elements.
with 6 elements, flex: 0 0 15% and so on.