How to make a div adapt to its content's width? - css

this is my first question here, but I've read many Java answers which helped me a lot. I did some research before, but don't hesitate to tell me if I duplicated a question or am doing anything wrong.
I'm trying to create a thumbnails gallery and I made a jsfiddle here.
HTML
<body>
<div id="main">
<div id="wrapper">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
</body>
CSS
#main {
background-color: rgba(255, 105, 180, 0.5);
height: 100vh;
padding: 10px;
}
#wrapper {
background-color: blue;
display: inline-block;
padding: 5px;
}
.box {
display: inline-block;
background-color: red;
width: 200px;
height: 200px;
margin: 5px;
}
I would like to center the red boxes in the main div, but not like text-align: center;, align the boxes left-to-right between them, and center the whole block. So I thought, why not make a wrapper div and center it ?
This is where my problem is, I would like the blue wrapper to be no larger than its content, but it fills the main div.
An answer here says inline-block should solve the issue but I can't figure out how.
The whole thing surely can be made quite easily, so what am I missing ?
If TLDR, I made some snapshots here : http://imgur.com/a/a2Fjg
Thanks a lot !

You can solve it via CSS, but in this way you should write a lot of mediaqueries with hardcoded values. I recommend you do this magic with javascript:
1) Get available width
2) Calculate, how many blocks in one row can appear
3) Get required width and set it for wrapper-container

So the reason why your content is expanding to fit 100% of the space available is that as the boxes are 'inline-block' they are situated within a line (think line of text) that will take up 100% of the width if it wraps. The browser doesn't know your intention and treats this exactly like text which, normally, we would want to behave like this.
In order to change this we will need to either :
Specify the maximum width of the container.
Specify the number of elements that can be contained on one line before wrapping.
Either way we do have to hardcode some assumptions/limitations (without involving any script or complex media queries etc).
Specifying the maximum width of the wrapper is probably the most straightforward way - like this:
body{
width:100%;
}
#main {
background-color: rgba(255, 105, 180, 0.5);
height: 100%;
padding: 10px;
width:100%;
}
#wrapper {
background-color: blue;
display: block;
padding: 5px;
max-width:640px;
margin: 0 auto;
}
.box {
display: inline-block;
background-color: red;
width: 200px;
/* If you want it to shrink rather than wrap you could say
width: calc((100% / 3) - 15px);*/
height: 200px;
margin: 5px;
}
JS Fiddle: https://jsfiddle.net/Chipmo/z30fLv0v/
Specifying the number of elements before wrap is a bit more tricky. The solution I have found is to add <br> tags after each box and then selectively activate them using the nth-child selector. I'm sure there'll be a way of doing this which doesn't involve extraneous tags - perhaps with display: table shenanigans or flexbox, but this works and shows the basic concept.
JS Fiddle: https://jsfiddle.net/Chipmo/xsf6c7e5/
SO snippets below:
Max-width
body{
width:100%;
}
#main {
background-color: rgba(255, 105, 180, 0.5);
height: 100%;
padding: 10px;
width:100%;
}
#wrapper {
background-color: blue;
display: block;
padding: 5px;
max-width:640px;
margin: 0 auto;
}
.box {
display: inline-block;
background-color: red;
width: 200px;
/* If you want it to shrink rather than wrap you could say
width: calc((100% / 3) - 15px);*/
height: 200px;
margin: 5px;
}
<body>
<div id="main">
<div id="wrapper">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
</body>
Number of elements
#main {
background-color: rgba(255, 105, 180, 0.5);
height: 100%;
padding: 10px;
text-align: center;
}
/*needs 2 ID's to gain higher precedence than the text-align center from above */
#main #wrapper {
background-color: blue;
display: inline-block;
padding: 5px;
text-align: left;
}
.box {
display: inline-block;
background-color: red;
width: 200px;
height: 200px;
margin: 5px;
}
#wrapper br {
display: none;
}
/*change to 8n for every fourth, 4n for every 2nd etc etc
You will probably want to use media queries with this */
#wrapper br:nth-child(4n) {
display: block;
}
<body>
<div id="main">
<div id="wrapper">
<div class="box"></div><br>
<div class="box"></div><br>
<div class="box"></div><br>
<div class="box"></div><br>
<div class="box"></div><br>
<div class="box"></div><br>
<div class="box"></div><br>
</div>
</div>
</body>

Use flexbox. This is the heart of the design:
#wrapper {
background-color: blue;
height: auto;
padding: 10px;
display: flex;
flex-direction: row;
justify-content: space-around;
align-content: space-between;
flex-wrap: wrap;
}
Added 2 invisible boxes at the bottom to push the last red box to the left.
FIDDLE
SNIPPET
html,
body {
width: 100%;
height: 100%;
}
#main {
width: 100vw;
max-width: 640px;
height: auto;
background-color: rgba(255, 105, 180, 0.5);
padding: 10px;
}
#wrapper {
background-color: blue;
height: auto;
padding: 10px;
display: flex;
flex-direction: row;
justify-content: space-around;
align-content: space-between;
flex-wrap: wrap;
}
.box {
display: block;
background-color: red;
margin: 2.5px auto 10px;
width: 200px;
height: 200px;
}
.space {
background: none;
}
<body>
<div id="main">
<div id="wrapper">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="space box"></div>
<div class="space box"></div>
</div>
</div>
</body>

Related

Parent DIV to inherit width (%) from child div

I am currently trying to figure out a way to be able to have a layout that has a bottom-up, content-oriented resizing behavior.
I have the following situation: https://codepen.io/Flash1232/pen/JJYPVQ
What is wrong here is obviously that the wrapper divs do not wrap around the table divs. Now is there any solution for this involving just plain CSS and HTML or do I have to write something in JS like "set wrapper width to the width of its inner div"?
Thanks in advance for any clues!
Man i solved my problem with display:flex on parent element :)
You may want to consider using a flexbox. Please see below. If there is anything that needs to be different, just let me know.
.outer-div {
position: absolute;
background: black;
width: 800px;
left: 0;
top: 0;
bottom: 0;
overflow: auto;
padding: 10px;
}
.area {
overflow: auto;
display: flex;
border: 5px solid red;
background: white;
margin: 10px 40px 10px 10px;
}
.column {
background: green;
border: 5px solid blue;
}
.wrapper {
display: flex;
border: 5px solid yellow;
justify-content: center;
align-items: center;
}
.table {
white-space: nowrap;
}
.violet {
background: violet;
width: 120%;
height: 80px;
}
.red {
background: red;
width: 150%;
height: 80px;
margin-bottom: 20px;
}
.icons {
Background: yellow;
float: right;
height: auto;
width: auto;
}
<div class="outer-div">
<div class="area">
<div class="column">
<div class="wrapper">
<div class="table red">
<span>***Table Content***</span>
</div>
</div>
<div class="wrapper">
<div class="table violet">
<span>***Table Content***</span>
</div>
</div>
</div>
<div class="column">
<div class="wrapper">
<div class="table violet">
<span>***Table Content***</span>
</div>
</div>
</div>
</div>
<div class="icons">
<p>Icon</p>
<p>Icon</p>
<p>Icon</p>
<p>Icon</p>
<p>Icon</p>
<p>Icon</p>
</div>
</div>
You should read the definition of the width attribute.
https://developer.mozilla.org/en/docs/Web/CSS/width
Percentages: refer to the width of the containing block
If you set width to 150%, you explicitly say, that the child should be bigger than the parent. You can not expect, that the parent has the same width like the child, if you force the child to be wider.

CSS Flex dynamic grid with multiple sizes

I have a problem with flex.
I have a wrapper where a minimum of 1 and maximum of 9 squares can be shown. Squares can have multiple sizes, based on the number of squares in grid.
I've got all required cases working except for one, as seen in this picture:
My styles are:
.grid {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-content: space-between;
width: 300px;
height: 300px;
position: relative;
}
Plus. the images have sized based on the overall number of them and their position in a list.
So the problem is in situation when I have 1 big square (takes position of 4 small squares) and 5 small squares around him from right and bottom.
The big one is first as he should be.
Next to him (top right corner) is second one, that's also correct.
The third one is in bottom left corner, and it should be in the second line and on the far right. Because of this one, all the others are in wrong position, so the last one is overflowing.
I've tried a lot of value combinations for justify-content, align-content, align-items and align-self but nothing have worked.
I'll go back to ton of classes and position absolute solution, if there is no flex solution for this. But I don't like it. It's too much styles and it doesn't look good.
Any advice would be greatly appreciated.
I think float is a better option for you, check out this snippet:
.grid {
width: 300px;
}
.box {
background: orange;
width: 90px;
height: 90px;
margin: 5px;
float: left;
}
.wide {
width: 190px;
}
.tall {
height: 190px;
}
.empty {
background: transparent
}
/* you can ignore everything after this comment - it's all for illustration */
body {
background: #334;
color: white;
font-family: sans-serif;
}
.example {
display: inline-block;
margin: 5px;
border: 1px solid #445;
padding: 10px;
width: 300px;
}
h3 {
margin: 0 0 5px 0;
}
<div class="example">
<h3>Example 1</h3>
<div class="grid">
<div class="box wide tall"></div>
<div class="box tall empty"></div>
<div class="box wide empty"></div>
<div class="box"></div>
</div>
</div>
<div class="example">
<h3>Example 2</h3>
<div class="grid">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
<div class="example">
<h3>Example 4</h3>
<div class="grid">
<div class="box wide tall"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
Flex is still trying to make complete rows of elements, so your big square and your little square are part of one row; there's no support for stacking beyond that.
Float on the other hand tries to stuff elements wherever it can fit them.
EDIT
I've updated this answer with examples on how to reproduce most of the images above (I've purposefully left out the 2 by 2 example - didn't want to cloud the answer with classes for boxes of 1.5 height/width).
Use of an empty class to remove color from blocks, as well as classes tall and wide to fill in spots of all sizes should help you customize your layout however you see fit. One note - here empty sets the background color to transparent. Your empty class may do more or less than this. You may not even need an empty class if all it is is a div without content.
There is no way to handle this layout with flex in a single container.
You need to do a little trick to achieve it.
The easier one would be to take the third item out of the flex layout, positioning it absolute:
.grid {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-content: space-between;
width: 300px;
height: 300px;
position: relative;
}
.item {
background-color: lightblue;
width: 100px;
height: 100px;
margin: 0px;
border: transparent solid 5px;
box-sizing: border-box;
background-clip: content-box;
}
.item:first-child {
width: 200px;
height: 200px;
}
.item:nth-child(2) {
background-color: blue;
position: absolute;
top: 100px;
right: 0px;
}
<div class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Another posibility, may be more in the flex idea, but also tricky
Set the big element with a margin-bottom negative, that makes it occupy only 1 row (being the height of a row the size of the small boxes).
Now be have a layout with 3 rows. The problem will be that the 3rd box will be under the first, big box. To solve this, we are setting a pseudo element (I have styled the snippet to make it visible, in production just set it to height 0 and it will disappear) with the same properties of width and margin of the first element.
.grid {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-content: space-between;
width: 300px;
height: 300px;
position: relative;
}
.grid:after {
content: "";
order: 3;
background-color: red;
width: 190px;
height: 10px;
margin: 5px;
}
.item {
background-color: lightblue;
width: 90px;
height: 90px;
margin: 5px;
}
.item:first-child {
width: 190px;
height: 190px;
margin-bottom: -100px;
order: 1;
opacity: 0.5;
}
.item:nth-child(2) {
order: 2;
}
.item:nth-child(n+3) {
order: 4;
}
<div class="grid">
<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>

Vertically align divs with equal space between them

So I'm struggling to achieve this simple concept with CSS and i've also searched the entire internet but couldn't find anything. I think I'm just not wording it correctly so a visual image of what i'm trying to do is this:
The top box should be positioned on top and the bottom one should be positioned at the bottom. Then the boxes in between them should have equal spacing on top and bottom. This is more like the vertical version of this answer: https://stackoverflow.com/a/6880421/7150896
You can use Flexbox for this. You just need to set flex-direction: column and justify-content: space-between.
body,
html {
margin: 0;
padding: 0;
}
.content {
display: flex;
height: 250px;
border: 1px solid black;
justify-content: space-between;
flex-direction: column;
width: 200px;
}
.box {
background: #0479D9;
height: 50px;
}
<div class="content">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
You can also achieve this using grid css layout:
.content {
display: grid;
align-content: space-between;
height: 275px;
border: 1px solid black;
width: 200px;
}
.box {
background: #0479D9;
height: 75px;
}
<div class="content">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>

Flexbox, min-height, margin auto and Internet Explorer

I use to play with both display: flex and margin: auto to have this kind of layouts:
This works well on every browser supporting Flexbox, even IE.
However, it would have been too easy if there hadn't had a little exception: min-height.
You can find a simple working example here. When using min-height on my wrapper, the last element is not pushed to the bottom of this wrapper (IE only).
I can't get this to works, do you girls/guys have any idea? Thanks.
Testing on IE11
.wrapper {
display: flex;
flex-direction: column;
min-height: 300px;
border: 1px solid grey;
padding: 5px;
}
.element {
height: 35px;
border: 1px solid grey;
margin: 5px;
}
.element:last-child {
margin-top: auto;
}
<div class="wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
This is a bug in IE's flexbox implementation:
In all other browsers that support flexbox, a flex-direction:column based flex container will honor the containers min-height to calculate flex-grow lengths. In IE10 & 11-preview it only seems to work with an explicit height value.
Bug report - (https://connect.microsoft.com/IE/feedback/details/802625/min-height-and-flexbox-flex-direction-column-dont-work-together-in-ie-10-11-preview#tabs)
It appears that this is on Microsoft's radar and will be fixed some point in the future:
Unfortunately, we are not able to address this feedback in our upcoming release. We will consider your feedback for a future release. We will keep this connect feedback bug active to track this request.
Reply from Microsoft - (https://connect.microsoft.com/IE/feedback/details/802625/min-height-and-flexbox-flex-direction-column-dont-work-together-in-ie-10-11-preview#tabs)
For now the simple solution is to use height:
.wrapper {
border: 1px solid grey;
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 300px;
padding: 5px;
}
.element {
border: 1px solid grey;
height: 35px;
margin: 5px;
}
.element:last-child {
margin-top: auto;
}
<div class="wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
But this has the limitation that the box wont grow if more .elements are added so probably isn't what you are after.
There does appear to be a somewhat hacky way of achieving this although it does require an extra containing element:
.container {
display: table;
min-height: 300px;
width: 100%;
}
.wrapper {
border: 1px solid grey;
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 100%;
min-height: 300px;
padding: 5px;
}
.element {
border: 1px solid grey;
height: 35px;
margin: 5px;
}
.element:last-child {
margin-top: auto;
}
<div class="container">
<div class="wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
</div>
This adds a container (.container), sets it to display: table; and gives it max-height: 300px;. height: 100%; is then added to .wrapper to get it to fit the full height of .container (effectively 300px) thus making IE behave the same as other browsers.
Compliant browsers ignore this and will continue to follow the min-height: 300px; rule set on .wrapper.
Here's another solution:
Adding an additional container with 2 elements:
an element with an height of "300px"
your ".wrapper"
.container {
display: flex;
}
.min-height-fix {
flex: 0 0 auto;
height: 300px; /* the "min-height" */
width: 1px; /* DEBUG */
background: red; /* DEBUG */
}
.wrapper {
flex: 1 1 auto;
display: flex;
flex-direction: column;
/*min-height: 300px;*/
border: 1px solid grey;
padding: 5px;
flex-wrap: wrap;
}
.element {
height: 35px;
border: 1px solid grey;
margin: 5px;
}
.element:last-child {
margin-top: auto;
}
<div class="container">
<div class="min-height-fix">
</div>
<div class="wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
</div>

Packing fixed width div's into fluid container

I have simple structure with container and inside boxes:
<div id="container">
<div class="block"></div>
// more blocks
<div class="block"></div>
</div>
What I would like to achieve is to center boxes inside this container but to pack them as much as possible in a one line. The same I can do using JS: http://jsfiddle.net/JhxSd/ but I would like to avoid that, and use only CSS. Is that possible?
#media queries
Use a set of #media queries to define different layouts for the grid based on the current screen size. The only part of the layout that needs to vary is the width of the grid wrapper.
For all practical purposes, this is the only CSS solution available at present. For an explanation of why #media queries are appropriate, and why other available CSS options won't work, see this answer.
JSFiddle Demo
The above demo has #media queries for screen sizes up to 1200px wide (more can be added as needed), and does not use JavaScript. The rendered width of #container is always 75% (not counting the border), and the grid is centered within #container.
Note: This solution requires adding a wrapper div around the blocks. In each #media query, the width of the wrapper is just enough to fit the number of columns appropriate for the current screen size. The fixed wrapper width is what allows the grid as a whole to be centered within #container. If editing the static HTML isn't an option, the wrapper div can be added when the page loads using jQuery.
HTML
<div id="container">
<div class="grid-wrapper">
<div class="block"></div>
...
</div>
</div>
CSS
#container {
width: 75%;
...
}
.grid-wrapper {
margin: 0 auto;
width: 70px; /* Default: 1 column */
}
#media (min-width: 200px) {
.grid-wrapper {width: 140px;} /* 2 columns */
}
#media (min-width: 290px) {
.grid-wrapper {width: 210px;} /* 3 columns */
}
...
I hope this will do the trick:
http://jsfiddle.net/CnjZR/1/
<div id="container">
<div id="wrap">
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
</div>
CSS:
#container {
width: 100%;
overflow: hidden;
background: red;
text-align: center;
}
.block {
width: 20px;
height: 20px;
background: blue;
float: left;
margin: 5px;
}
#wrap {
background: green;
overflow: hidden;
display: inline-block;
}
Not too sure if you where looking for something like 'flex-justify' , I added in the demo a turn around based on inline-boxes behavior and text-align values.
edit : point cleared: text-align:center ; is it.
http://jsfiddle.net/JhxSd/10/
The point is you should not use float, but display.
Float is not friendly with centering , nor vertical nor horizontal, since it is not standing in the natural flow of the document.
#container {
width: 75%;
border: 1px solid;
text-align:center;
overflow:hidden;
padding:1em 1em 0;
box-sizing:border-box;
float:left;
}
#container .block {
width: 50px;
height: 50px;
background-color: blue;
display:inline-block;
margin: 10px;
}
I think, everything you have almost done already.
#container {
width: 75%;
border: 1px solid;
float: left;
}
#container .block {
width: 50px;
height: 50px;
background-color: blue;
float: left;
margin: 10px;
overflow: hidden;
}
http://jsfiddle.net/JhxSd/3/
Try this:
#container {
width: 75%;
border: 1px solid;
float: left;
overflow: hidden;
text-align: center;
}
#container .block {
display: inline-block;
width: 50px;
height: 50px;
background-color: blue;
margin: 10px;
}
If you truly need everything left-aligned then I think you're out of luck with just CSS.
You can use the text-align:justify for the container and use the display:inline-block for the div.block. but you need add some placeholder tag at the last.Like this:
HTML
<div class="wrapper">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
<div class="block">4</div>
<div class="block">5</div>
<div class="block">6</div>
<div class="block">7</div>
<div class="block">8</div>
<div class="block">9</div>
<div class="block">10</div>
<div class="block">11</div>
<div class="block">12</div>
<div class="block">13</div>
<div class="block">14</div>
<div class="block">15</div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
</div>
CSS
.wrapper {
width: 75%;
border: 1px solid;
font-size: 0.1px;
text-align: justify;
}
.wrapper:after {
content:"";
display:inline-block;
width: 100%;
}
.wrapper div{
font-size: 16px;
display:inline-block;
*display: inline;
zoom:1;
color: #fff;
background-color:blue;
width: 50px;
height: 50px;
margin: 10px;
}
.wrapper .placeholder {
width: 50px;
height: 0px;
background:none;
}
Please view the demo. A detailed tutorial, please click here.

Resources