Make items to stretch inside the container with same gap - html

I have four items with same width. I need them to be stretched inside the fluid container. Whenever I resize the window, the gap between each item should adjust in such a way that the items are still stretching inside the container. Here is the image of what I want.
Here is the code, I have tried:
.parent {
margin-top: 40px;
background-color: beige;
}
.parent::after {
content:"";
clear: both;
display: block;
}
.child {
width: 20px;
height: 20px;
background-color: tomato;
margin-left: 20%;
float: left;
}
Fiddle

For limited known items:
Suppose, we know the number of items present in a container. Lets say the items to be 4. Lets wrap those items in separate sections each and give those sections float: left and width: 25%. Here I am giving width: 25% because there are four sections which need to cover the container completely i.e 100/4 = 25%. This will result in something similar view as shown below in the image:
As you can see in the above image, the items are still not aligned to each other. We can see gap between the last item and the container. But if you ignore the gap, you can see that the items are equally aligned to each other.
So now we should just be able to remove the width of the section holding the last item. This can be done using :last-child selection. Since, the last item holder is now hidden, we need to stretch other child holders. Hence, we need to divide 100% by 3 instead of 4.
.child-holder{
width: 33.3%; /* Instead of 25% */
}
.child-holder:last-child {
width: 0px;
}
It stretches the items but this hides the last item. As you can see in the below image:
We can solve this by giving negative margin-left to each item with value equal to the items. Applying so, will now hides the first item. So, give margin-left to the container equal to the item's width (positive value).
.parent {
margin-left: 20px; /* This value is equal to the item's width */
}
.child {
width: 20px;
height: 20px;
background-color: black;
margin-left: -20px; /* negative margin equal to its width */
}
Hence, this will give the solution we want:
Working Fiddle
For unknown number of items:
For unknown number of items, we will replace float: left to the item holding sections with display: table-cell and to stretch those sections, we will apply display: table; width: 100%; to the parent container. and since we must apply margin-left value equal to the item's width, we will have a parent wrapper, to which we apply margin-left instead. (Because, if we apply margin-left and width: 100% to same element, then the element will overflow)
Though we are giving width: 0px to the last item holder section, it is still occupying the space.
This can be solved by applying table-layout: fixed to the parent container. This will give us the solution:
Working Fiddle
This solution will work for any number of items, added dynamically or static. It will get automatically adjusted.
For Unknown number of items with unequal widths:
For unequal/unknown width of items, we should definitely go with javascript. Here is the small code which I wrote to use in one of the projects:
function setAlign(parentClass, childCommonClass) {
var childDivs = document.getElementsByClassName(childCommonClass);
var childDivsTotalWidth = 0;
var childDivsLength = childDivs.length;
var parentElement = document.getElementsByClassName(parentClass)[0];
var parentElementWidth = parentElement.offsetWidth;
for (var i = 0; i < childDivsLength; i++) {
childDivsTotalWidth += childDivs[i].offsetWidth;
}
var remainingWidth = parentElementWidth - childDivsTotalWidth;
var gap = remainingWidth / (childDivsLength - 1);
var leftWidth = 0;
for (var j = 0; j < childDivsLength; j++) {
if (j > 0) {
leftWidth += gap + childDivs[j - 1].offsetWidth;
}
childDivs[j].style.left = leftWidth + "px";
}
}
window.onload = setAlign('row', 'box');
window.onresize = function () {
setAlign('row', 'box');
}
Working Fiddle

Flex
This can be done with display: flex; or flexbox
Property your after is justify-content: space-between; this will display all the item evenly distributed along the container with the fist and last element at the start and end of the container.
.container {
margin-top: 50px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
background-color: whitesmoke;
}
.item {
width: 50px;
height: 50px;
background-color: tomato;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
THERE is so much more
Different sizes
Lets say the content size is not known:
.container {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
background-color: whitesmoke;
align-items: center;
}
.item {
width: 50px;
height: 50px;
background-color: tomato;
}
.one {
width: 100px;
height: 20px;
}
.two {
width: 20px;
height: 100px;
}
.three {
width: 50px;
height: 70px;
}
.four {
width: 70px;
height: 70px;
}
.headline {
font-size: 20px;
}
<h2>Different sizes</h2>
<div class="container">
<div class="item one"></div>
<div class="item two"></div>
<div class="item three"></div>
<div class="item four"></div>
</div>
Column
More of a vertical person then a horizontal one?
No problem.
.container {
display: inline-flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: space-around;
background-color: whitesmoke;
align-items: center;
height: 500px;
}
.item {
width: 50px;
height: 50px;
background-color: lime;
}
.item2 {
width: 150px;
height: 50px;
background-color: tomato;
}
<div class="container">
<div class="item"></div>
<div class="item2"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Can i use it?
The support is really good, its just that IE is a tiny bit behind the rest...
So only IE10 (semi) IE 11 full
Links:
MDN Good thorough documentation
CSS-tricks My person favorite

Related

Empty space when I set height of a child element

I want to create a simple page with flex looks like this:
So this is what I try:
.container {
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.header {
height: 40px;
background-color: red;
width: 100%;
}
.sidenav {
background-color: blue;
align-items: flex-start;
}
.main {
background-color: green;
flex-grow: 1;
}
<div class="container">
<header class="header">Header</header>
<nav class="inner sidenav">Sidenav</nav>
<div class="inner main">Main</div>
</div>
My question is, when I set the height of the .header, there's a blank space between .header and the others. Anybody knows why? How can I fix it?
I know I can add more div to make it works, but I want a solution without adding any extra wrapper.
It seems that your content wrapped into two flex rows, and when height is distributed among those rows there are some extra space remained. All of that extra space is not given to last row automatically. So a gap remains unless you shrink the height of window to your contents' exact height.
If you want your second row to take remaining space using css, maybe you can assign remaining height to it with CSS like this:
.container {
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.header {
height: 40px;
background-color: red;
width: 100%;
}
.sidenav {
background-color: blue;
align-items: flex-start;
height: calc(100vh - 40px);
}
.main {
background-color: green;
flex-grow: 1;
}
body
{
margin: 0
}
<div class="container">
<header class="header">Header</header>
<nav class="inner sidenav">Sidenav</nav>
<div class="inner main">Main</div>
</div>

Horizontal scroll not working as expected

Hello I am trying to implement horizontal scrolling (using scroll bars)but I can't get it to work properly
I have 2 divs 1 for scroll and 1 main div I want to display the items on the main div but when I do that the whole div scrolls, instead of only the items. How can I get this to work?
scroll div
<div class="scrolling-wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
main div
<div class="main">
</div>
CSS
.scrolling-wrapper {
overflow-x: scroll;
overflow-y: hidden;
white-space: nowrap;
}
.item {
display: inline-block;
align-self: flex-start;
background-color: var(--pampas);
border-radius: 10px;
flex-shrink: 0;
height: 269px;
margin-left: 210px;
margin-top: 13px;
width: 200px;
}
.main {
align-items: center;
background-color: white;
display: flex;
flex-direction: column;
height: auto;
justify-content: flex-start;
min-height: 1080px;
padding: 26px 0;
width: 1920px;
}
Here is how it looks right now.
Thank you <3
If I understand your question correctly, you want all the items to scroll together (i.e. not each one individually) but only inside div.scrolling-wrapper which is a child of div.main.
This only works if you restrict the width of div.scrolling-wrapper.
You most likely need
.scrolling-wrapper {
width: 100%;
/* you can also use max-width instead */
}
The 100% refer to the parent's width, in this case that of div.main. This is necessary because you have display:flex set on div.main which has the effect that its child div.scrolling-wrapper gets the sum of its children' (the .items) widths as its default width.
As a sidenote: Please mind that the following rules related to flexbox that you set on .item:
align-self: flex-start;
flex-shrink: 0;
don't have any effect unless there is some rule that you didn't mention in your original post that sets .scrolling-wrapper to display:flex.

flex space between elements

I have two flex elements and I need space between them,
I added a margin-right between them and it looks great, but the problem is when the screen is get smallest the second element go down to the new line and I have aredudant margin-right:30px and it not looks good.
How can I solve it:
I dont want to use a window resize event because if you open this ui in mobile so in the begining you have these two items in seperate lines.
.item-target-scale {
flex: 3;
min-width: 186px;
display: inline-block;
text-align: left;
margin-right: 30px;
}
.item-target-bar {
flex:1;
min-width: 100px;
display: inline-block;
}
Use media query for this purpose. Inspect your page and find out when does the line break occur(use devtools it gives precise viewport width in pixels).
#media screen and (min-width:'calculated'px)
{
.item-target-scale {
margin-right: 0px;
}
}
Hopefully this is what you need.
EDIT:
Use this if the element size is not fixed:
function myFunction(){
var i=document.getElementById("target1").offsetWidth+document.getElementById("target2").offsetWidth+50;
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
if(i>=w)
{
document.getElementById("target1").style.marginRight="0px";
}
else
{
document.getElementById("target1").style.marginRight="30px";
}
}
.item-target-scale {
flex: 3;
min-width: 186px;
display: inline-block;
text-align: left;
margin-right: 30px;
background:green;
}
.item-target-bar {
flex:1;
min-width: 100px;
display: inline-block;
background:red;
}
<body onresize="myFunction()" onload="myFunction()">
<div class="item-target-scale" id="target1">
dwdwdwdwd
</div>
<div class="item-target-bar" id="target2">
eegerg
</div>
</body>
I will need the HTML code to get the rest of the item's size but that can be done by inspecting. So, just add the remaining element's width in 'i'.
I would suggest wrapping these two elements in parent element and using justify-content: space-between property.
.parent {
display: flex;
justify-content: space-between;
width: 50%;
}
.child {
height: 20px;
width: 50px;
background: red;
}
<div class="parent">
<div class="child child1">
</div>
<div class="child child2">
</div>
</div>

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?

Height is not correct in flexbox items in Chrome [duplicate]

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I've got a delicate problem for any CSS guru out there.
My green div has a flexible height, taking up the remaining.
And now I want to put a div inside that div which should be the half of the green div. But it seems like if Chrome treats it like half of the whole page rather than the flex item.
http://jsfiddle.net/unh5rw9t/1/
HTML
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>
CSS
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
}
#half_of_content {
height: 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
#Michael_B explained why Chrome behaves like this:
You gave the body a height: 100%. Then gave its child (.wrapper)
a height: 100%. Then gave its child (.content) a height: 100%.
So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be a 50% height
of body.
However, Firefox disagrees because, in fact, that height: 100% of .content is ignored and its height is calculated according to flex: 1.
That is, Chrome resolves the percentage with respect to the value of parent's height property. Firefox does it with respect to the resolved flexible height of the parent.
The right behavior is the Firefox's one. According to Definite and Indefinite Sizes,
If a percentage is going to be resolved against a flex item’s
main size, and the flex item has a definite flex
basis, and the flex container has a definite main
size, the flex item’s main size must be treated as
definite for the purpose of resolving the percentage, and the
percentage must resolve against the flexed main size of the
flex item (that is, after the layout algorithm below has been
completed for the flex item’s flex container, and the flex
item has acquired its final size).
Here is a workaround for Chrome:
#content {
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
height: auto;
}
This way the available space in #content will be distributed equally among #half_of_content and the ::after pseudo-element.
Assuming #content doesn't have other content, #half_of_content will be 50%. In your example you have a 2 in there, so it will be a bit less that 50%.
html,
body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
You could absolutely position div id="half_of_content".
#content {
flex: 1;
height: 100%;
background-color: green;
position: relative; /* new */
}
#half_of_content {
height: 50%;
background-color: yellow;
position: absolute; /* new */
width: 100%; /* new */
}
DEMO
With regard to your statement:
But it seems like if Chrome treats it like half of the whole page
rather than the flex item.
You gave the body a height: 100%. Then gave its child (.wrapper) a height: 100%. Then gave its child (.content) a height: 100%. So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be 50% height of body.
With absolute positioning, however, you don't need to specify parent heights.
Nesting flexboxes is a little buggy. I reworked your markup a little by adding an inner wrapper with display: flex; which seems to do the job. Here is the fiddle (also using class names instead of ids).
<div class="content">
<div class="wrapper-inner">
2
<div class="half">
2.1
</div>
</div>
</div>
.wrapper-inner {
position: absolute;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
Fix:
on #content set
display: flex;
flex-flow: column nowrap;
justify-content: flex-end
on #half_of_content set flex: 0 0 50%;
Caveat: you need to add an extra div as a child of #content.
Here's the full example:
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
display:flex;
flex-flow: column nowrap;
justify-content: flex-end;
background-color: green;
}
#half_of_content {
flex: 0 0 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>