DIV within flex container pushing down entire row - css

I'm working on an angular/js app using directives and this particular flex-container uses divs(directives) which may contain one or more items. When a directive includes 3 items for the flexbox, if it isn't a perfect fit for all items in that directive, it pushes the entire row down instead of say leaving one on the top line and putting the rest on the 2nd line. It will instead leave an empty space on top and push all 3 to the 2nd line. The reason for directives in this case is for reuse and grouping common functionality together.
To simplify, this demonstrates the issue I'm seeing just with using divs. Looking at the example if you resize the window you'll see that as soon as there is not enough room to fit the 6th bubble, all 3 in that div get pushed to the second row.
example on codepen
dl,
dt,
dd {
/* resetting definition list styling */
margin: 0;
padding: 0;
}
.bubble {
display: block;
border-radius: 1rem;
background: rgb(52, 58, 64);
color: rgb(255, 255, 255);
text-align: center;
font-weight: 600;
padding: 1rem;
width: 10rem;
height: 10rem;
}
.flex-container {
display: inline-flex;
flex-wrap: wrap;
}
.flex-container div {
display: inline-flex;
}
<div class="flex-container">
<div>
<dl class="bubble">1</dl>
</div>
<div>
<dl class="bubble">2</dl>
</div>
<div>
<dl class="bubble">3</dl>
</div>
<div>
<dl class="bubble">4</dl>
<dl class="bubble">5</dl>
<dl class="bubble">6</dl>
</div>
</div>
Is it possible for me to get that div with 3 items to start after the 3rd bubble and wrap only those that don't fit to the second line?

update:
Use
.flex-container div {
display: contents;
}
Instead of
.flex-container div {
display: inline-flex;
}
display: contents basically ignores the element and makes the element's parent, or flex-container in this case, the parent of the children or the dl tags here. This only affects the layout. The children still keep any of the styling inherited from their wrapper element.

Showing Roya's suggestion here which does the trick...
dl, dt, dd {
/* resetting definition list styling */
margin: 0;
padding: 0;
}
.bubble {
display: block;
border-radius: 1rem;
background: rgb(52, 58, 64);
color: rgb(255, 255, 255);
text-align: center;
font-weight: 600;
padding: 1rem;
width: 10rem;
height: 10rem;
margin-right: 2rem;
margin-top: 1rem;
}
.flex-container {
display: inline-flex;
flex-wrap: wrap;
}
.flex-container div {
display: contents;
}
<div class="flex-container">
<div><dl class="bubble">1</dl></div>
<div><dl class="bubble">2</dl></div>
<div><dl class="bubble">3</dl></div>
<div><dl class="bubble">4</dl></div>
<div>
<dl class="bubble">5</dl>
<dl class="bubble">6</dl>
<dl class="bubble">7</dl>
</div>
</div>

Related

Flex Items Spilling, not Resizing

https://codepen.io/fluark/pen/VwxGawr
.header {
display: flex;
font-family: monospace;
background: papayawhip;
align-items: center;
justify-content: space-between;
margin-left: auto;
}
ul {
display: flex;
background: papayawhip;
gap: 10em;
list-style-type: none;
flex-direction: row;
margin: 0;
padding: 0;
}
Desired Outcome
Visually my header looks fairly close to the desired outcome, however when I shrink down the page, the right links/ul (child items) spill out of the header (parent).
I am pretty sure this is a matter of not having the proper flex settings. Is the error maybe in the flex-basis? Or potentially the relationship between flex-shrink and flex-basis?
I have looked up flex settings and tried separately adding “flex: 1;” on both the parent .header as well as the div.right-links and ul.
I have also tried creating a separate div... div.header and then adding flex: 1 to that with the intention of making it so the parent is able to grow when the window is resized. That didn't seem to do anything.
I am a little confused because with “display: flex” on both the .header element and the ul, that means the flex-shrink is 1 (flex = 0, 1, auto), so shouldn’t the links be shrinking when the parent element is resized, not spilling out?
I’m looking for some guidance/talk throughs because I am at the point where I am just adding to the code to “see what happens”, and that’s when I know I need help.
Thanks in advance!
The ul element has a default padding of 26px and when you narrow the viewport it's that padding that's pushing the div to the right. If you set padding-left: to 0 then it removes it. I've also set the li display type to inline-block so that the padding on the a element does not overflow the logo on small screen sizes. At really small screen sizes (below 612px or so), the logo, a tags, gaps and padding will all be the lowest they can be so if you want to restyle it any further then I'd use a media query. See below
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
font-family: monospace;
background: papayawhip;
padding: 5px;
}
.logo {
font-size: 48px;
font-weight: 900;
color: tomato;
background: white;
padding: 4px 32px;
}
ul {
padding-left: 0;
display: flex;
gap: 1em;
flex-direction: row;
/* this removes the dots on the list items*/
list-style-type: none;
}
li {
display: inline-block;
}
a {
font-size: 22px;
background: white;
/* this removes the line under the links */
padding: 8px;
text-decoration: none;
}
<div class="header">
<div class="left-links">
<ul>
<li>ONE</li>
<li>TWO</li>
<li>THREE</li>
</ul>
</div>
<div class="logo">LOGO</div>
<div class="right-links">
<ul>
<li>FOUR</li>
<li>FIVE</li>
<li>SIX</li>
</ul>
</div>
</div>

How can I put one box next to another with flexbox?

I'm trying to put two flex containers next to each other using flexbox, taking this layout as reference (I want it to be like the first row here, with part of the image on the left inside a box and the other one on the right)
This is my code so far for the two containers:
.chaco-container {
border: $borde-textos;
background-color: #bda89c;
margin: 0;
padding: 1em;
width: 50%;
display: inline-flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.plan-container {
background-color: white;
border: $borde-textos;
width: 50%;
display: inline-flex;
}
display: flex; needs to be applied on the parent container. Check out the below example snippet.
.flex-container {
display: flex;
}
.chaco-container {
width: 50%;
background-color: yellow;
}
.plan-container {
width: 50%;
background-color: skyblue;
}
<div class="flex-container">
<div class="chaco-container">...content</div>
<div class="plan-container">...content</div>
</div>
I think you might be facing gap between the two inline flex elements which is resulting to the second element going to the next line.
To fix this:
Use this as a reset:
*{
margin: 0;
padding: 0;
box-sizing:border-box;
}
2)Give negative margin to the plan(second) container:
margin-left:-4px;
(increase the number of negative pixels until both flexboxes are on the same row)

How to CSS grid block has background color?

i was using grid property to build web site. but i got a problem that i can't use background property as i expect.
#wrap {
height: 100%;
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 35px 125px;
}
.line1 {
width: 1px;
height: 16px;
background: #ccc;
}
header {
background-color: #221816;
grid-column: 2/12;
}
header .topNav {
color: #fff;
}
header .topNav ul {
height: 35px;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
header .topNav ul li {
align-self: center;
padding-right: 16px;
}
*,
:before,
:after {
margin: 0;
padding: 0;
border: 0;
color: #fff;
list-style: none;
}
<div id="wrap">
<header>
<nav class="topNav">
<ul>
<li>login</li><span class="line1"></span>
<li>signin</li>
<li>bags</li>
<li>mypages<span></span></li>
<li>customer</li>
</ul>
</nav>
</header>
</div>
i expected the header's width 100%. so i put 'grid-column:1/-1;' and i got problem that contents have to be narrow. so i fix property like 'grid-column:2/12' then now i got a problem the background can't be wide. do i have solution?
change your header to read: header{background-color:#221816; grid-column: 1/13;}
This is why: You have 12 divisions along the width of your page, but you don't count the area by divisions, you count by the line.Take a piece of scratch paper, draw three lines from side to side, then 13 lines top to bottom to represent your 12 columns and 2 rows of your header/navigation area. Now, the three lines across are numbered 1, 2, and 3 (one at the top, two in the middle, three at the bottom). The 13 verticle lines start with line number one, and if you count all the way across end with line number 13. So, to get your header to go from one side of the page to the other, it needs to start on line 1 and end on line 13 (1/13). Does that make sense?
If I understand correctly what you're trying to do, you can get what you want with a lot less effort, as I've shown below. Just do this row with flex. You don't need to use grid.
After I wrote up this answer, your subsequent comments say that you want to do something that you haven't shown us with some more rows that are different from this one. You can do things the way I've shown you for this row, and then add another div with the grid in it and do what you want with it.
If that doesn't work for you, then you'll need to further clarify what you're trying to do.
.line1 {
width: 1px;
height: 100%;
background: #ccc;
}
header {
background-color: #221816;
}
header .topNav {
color: #fff;
}
header .topNav ul {
height: 35px;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
header .topNav ul li {
padding: 0 2%;
align-self: center;
}
*,
:before,
:after {
margin: 0;
padding: 0;
color: #fff;
list-style: none;
}
<div id="wrap">
<header>
<nav class="topNav">
<ul>
<li>login</li><span class="line1"></span>
<li>signin</li>
<li>bags</li>
<li>mypages<span></span></li>
<li>customer</li>
</ul>
</nav>
</header>
</div>

Make flex items stretch full height and vertically center their content

I have a horizontal flex box (i.e. flex-direction: row, i.e. side-by-side) with a few items. Each item can be a single line of text, or can have multiple lines. I want to vertically-align the contents of each flex item.
If each item had a transparent background, I could easily use align-items: center. However, I want each item to be stretched vertically, because I want to set a background (or maybe borders, or maybe it is a clickable region) to the entire available height.
So far, I know:
Stretching: align-items: stretch
Aligning: align-items: center
Stretching and aligning: ???
Demo available at http://codepen.io/denilsonsa/pen/bVBQNa
ul {
display: flex;
flex-direction: row;
}
ul.first {
align-items: stretch;
}
ul.second {
align-items: center;
}
ul > li {
flex-grow: 1;
flex-shrink: 0;
flex-basis: 5em;
text-align: center;
}
ul > li:nth-child(2) {
background: #CFC;
}
/* Visual styles, just ignore. */
html, body { font-family: sans-serif; font-size: 25px; }
ul, li { list-style: none; margin: 0; padding: 0; }
ul { background: #CCF; width: 25em; }
<ul class="first">
<li>Sample</li>
<li><span>span</span></li>
<li><span>multiple</span> <span>span</span></li>
<li>text <span>span</span></li>
<li>multi<br>line</li>
</ul>
<hr>
<ul class="second">
<li>Sample</li>
<li><span>span</span></li>
<li><span>multiple</span> <span>span</span></li>
<li>text <span>span</span></li>
<li>multi<br>line</li>
</ul>
Similar questions:
Question 14012030 and question 23442692 and question 27729619 and question 25311541 ask essentially the same thing, but they either have a single element or plain text as child of each flex item. As soon as we have mixed content, possibly with multiple elements, those solutions do not work.
Question 19026884 is unrelated, the issue there was the wrong markup.
Unfortunately, it is impossible to achieve the desired effect while using the exact markup posted in the question.
The solution involves:
Setting display: flex; on <li>.
Wrapping the <li> contents into another element.
This is required because <li> is now a flex container, so we need another element to prevent the actual contents from becoming flex items.
In this solution, I introduced a <div> element, but it could have been other element.
Now that <li> is a flex container and it contains only a single child, we can use align-items and/or justify-content to align this new and only child.
The DOM tree looks like this:
<ul> flex-parent, direction=row
├ <li> flex-item && flex-parent && background && JavaScript clickable area
│ └ <div> flex-item as a single transparent element
│ ├ Actual contents
│ └ Actual contents
├ …
Note: The solution in this answer uses 2 nested flex boxes. The solution by Michael_B uses 3 nested flex boxes, because it has the added challenge of expanding the <a> element to fill the entire <li>. Which one is preferred depends on each case. If I could, I would accept both answers.
/* New code: this is the solution. */
ul > li {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
/* Old code below. */
ul {
display: flex;
flex-direction: row;
align-items: stretch;
}
ul > li {
flex-grow: 1;
flex-shrink: 0;
flex-basis: 5em;
text-align: center;
}
ul > li:nth-child(2) {
background: #CFC;
}
/* Visual styles, just ignore. */
html, body { font-family: sans-serif; font-size: 25px; }
ul, li { list-style: none; margin: 0; padding: 0; }
ul { background: #CCF; width: 25em; }
button:focus + ul {
font-size: 14px;
width: auto;
}
<button>Click here to set <code>width: auto</code> and reduce the font size.</button>
<!-- New code: there is a single <div> between each <li> and their contents. -->
<ul>
<li><div>Sample</div></li>
<li><div><span>span</span></div></li>
<li><div><span>multiple</span> <span>span</span></div></li>
<li><div>text <span>span</span></div></li>
<li><div>multi<br>line</div></li>
</ul>
I want each item to be stretched vertically, because I want to set a
background (or maybe borders, or maybe it is a clickable region) to
the entire available height.
You can achieve this layout without any changes to your HTML structure. There's no need for additional containers.
You already have a primary flex container and a group of flex items. Simply make those flex items into nested flex containers. That will enable you to align the content with flex properties.
(Since you mentioned that you may need clickable regions, I switched from li to a elements.)
nav {
display: flex;
background: #CCF;
width: 25em;
}
nav > a {
flex: auto; /* flex-grow: 1, flex-shrink: 1, flex-basis: auto */
text-align: center;
text-decoration: none;
display: flex;
align-items: center;
justify-content: center;
}
nav > a:nth-child(2) {
background: #CFC;
}
html, body {
font-family: sans-serif;
font-size: 25px;
}
<nav>
Sample
<span>span</span>
<span>multiple</span> <span>span</span>
text <span>span</span>
multi<br>line
</nav>
revised codepen
Note that content placed directly inside a flex container is wrapped in an anonymous flex item:
From the spec:
4. Flex Items
Each in-flow child of a flex container becomes a flex item, and each contiguous run of text that is directly contained inside a flex
container is wrapped in an anonymous flex item.
So, because the text is automatically wrapped in flex items, you can keep the full height of each item (align-items: stretch from the primary container) and vertically center the content (align-items: center from the nested containers).
Make the li flex-containers with flex-direction:column. I think that's what you are after.
html,
body {
font-family: sans-serif;
font-size: 25px;
}
ul,
li {
list-style: none;
margin: 0;
padding: 0;
}
ul {
background: #CCF;
width: 25em;
display: flex;
flex-direction: row;
}
ul.first {
align-items: stretch;
}
ul > li {
flex-grow: 1;
flex-shrink: 0;
flex-basis: 5em;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
/*outline: 1px dotted #444;*/
}
ul > li:nth-child(2) {
background: #CFC;
}
<ul class="first">
<li>Sample</li>
<li><span>span</span>
</li>
<li><span>multiple</span> <span>span</span>
</li>
<li>text <span>span</span>
</li>
<li>multi
<br>line</li>
</ul>
Flex-child items can also be flex-parent items.
*,
*:before,
*:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
font-family: sans-serif;
font-size: 25px;
}
body {
display: flex;
flex-flow: column nowrap;
background-color: #333;
overflow: hidden;
}
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.List {
padding: 0;
margin: 0;
background: #CCF;
width: 25em;
list-style: none;
display: flex;
flex-flow: row nowrap;
justify-content: center;
}
.ListItem {
flex-basis: 5em;
display: flex;
flex-flow: row wrap;
text-align: center;
align-items: center;
}
.ListItem:nth-child(2) {
background: #CFC;
}
.ListItem__content {
width: 100%;
}
<ul class="List">
<li class="ListItem">
<span class="ListItem__content">Sample</span>
</li>
<li class="ListItem">
<span class="ListItem__content">span</span>
</li>
<li class="ListItem">
<span class="ListItem__content">multiple <br> span</span>
</li>
<li class="ListItem">
<span class="ListItem__content">span</span>
</li>
<li class="ListItem">
<span class="ListItem__content">multi<br>line</span></li>
</ul>

Keep an element centred between, or above, two other elements

I've managed to get CSS3 to almost do what I want:
The grey .top-middle container is of arbitrary width, and must always remain flush with the top edge of the parent container (the <main>).
The purple left and right containers are also of arbitrary width, and must always remain flush with their respective edges of the parent container.
When the parent container is sufficiently wide, the three top containers should sit side-by-side; otherwise, the left and right containers should sit just beneath the .top-middle container. (It would be nice if the two purple containers dropped at the same time, but I'll live with one of them remaining next to the middle container, when there's space.)
The minimum width of the <main> container should essentially be the width of the .top-middle container
The .top-middle container should be centred, ideally relative to the parent container (<main>), but at least relative to the horizontal space available to it (between the left and right containers)
It's that last requirement, #5, that I haven't managed.
I'd prefer not to resort to JavaScript, and of course, it needs to be a cross-browser solution. (I don't really care about IE < 11, though—people using that cruft have bigger worries than whether my CSS looks pretty!)
N.B. This issue cannot (AFAIK) be tested in jsfiddle, StackOverflow's code snippet feature, or any other fixed-width environment. Please copy my code and paste it into a file, and watch what happens when you widen or narrow the browser window.
Here's my complete code, for your copying and pasting pleasure:
main div {
white-space: nowrap;
color: white;
}
.top-container {
background: olive;
}
.top-middle {
background: grey;
}
.top-left,
.top-right {
background: purple;
}
.bottom-container {
background: blue;
text-align: center;
}
/* The crux of the layout starts here */
main {
height: 300px;
display: flex;
flex-direction: column;
}
.top-container>* {
display: inline-block;
padding: 1em;
}
.top-left {
float: left;
}
.top-right {
float: right;
}
.spacer {
background: silver;
flex-grow: 1;
}
<main>
<div class="top-container">
<div class="top-middle">
This should be centred, and always stay on top.
<em>Left</em> and <em>right</em> should drop when the window contracts.
</div>
<div class="top-left">left</div>
<div class="top-right">right</div>
</div>
<div class="spacer"></div>
<div class="bottom-container">This is the bottom.</div>
</main>
Your fifth requirement can be achieved by making the following change:
Add text-align: center; to .top-container
This works because text-align effects the alignment of inline elements:
The text-align CSS property describes how inline content like text is aligned in its parent block element. text-align does not control the alignment of block elements itself, only their inline content.
text-align (https://developer.mozilla.org/en-US/docs/Web/CSS/text-align)
.top-middle is set to be inline-block due to .top-container>* { display: inline-block; padding: 1em; } so will be centered within .top-container.
main div {
white-space: nowrap;
color: white;
}
.top-container {
background: olive;
text-align: center;
}
.top-middle {
background: grey;
}
.top-left,
.top-right {
background: purple;
}
.bottom-container {
background: blue;
text-align: center;
}
/* The crux of the layout starts here */
main {
height: 300px;
display: flex;
flex-direction: column;
}
.top-container>* {
display: inline-block;
padding: 1em;
}
.top-left {
float: left;
}
.top-right {
float: right;
}
.spacer {
background: silver;
flex-grow: 1;
}
<main>
<div class="top-container">
<div class="top-middle">
This should be centred, and always stay on top.
<em>Left</em> and <em>right</em> should drop when the window contracts.
</div>
<div class="top-left">left</div>
<div class="top-right">right</div>
</div>
<div class="spacer"></div>
<div class="bottom-container">This is the bottom.</div>
</main>
Unfortunately, there is a drawback with this method as a bug in Firefox will always force .top-left and .top-right onto a new line:
Also affecting Bugzilla itself, as glob pointed out on IRC. https://bugzilla.mozilla.org/show_bug.cgi?id=677757#c4 has the
"comment 4" text hidden
The cause is this code in nsLineLayout::ReflowFrame:
if (psd->mNoWrap) {
// If we place floats after inline content where there's
// no break opportunity, we don't know how much additional
// width is required for the non-breaking content after the float,
// so we can't know whether the float plus that content will fit
// on the line. So for now, don't place floats after inline
// content where there's no break opportunity. This is incorrect
// but hopefully rare. Fixing it will require significant
// restructuring of line layout.
// We might as well allow zero-width floats to be placed, though.
availableWidth = 0;
}
I wonder whether the right thing to do is:* not manipulate the
available width at all, or* make the available width infinite, since
the nowrap content is never going to wrap around the float anyway
(In theory, the correct solution is not to try placing the float until
the following break opportunity. I wonder if other browsers do that.)
Bug 488725 - float pushed down one line with white-space: nowrap; (https://bugzilla.mozilla.org/show_bug.cgi?id=488725)
You could also use flex to center .top-middle although this wont push both .top-left and .top-right down to a new line when the space is taken up. To achieve this make the following changes:
Add display: flex; to .top-container to make its children use the flexbox model
Add flex-wrap: wrap; to .top-container to make its children wrap onto new lines when they run out of space
Add justify-content: space-between; to .top-container to add space around the child elements which will center .top-middle
main div {
white-space: nowrap;
color: white;
}
.top-container {
background: olive;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.top-middle {
background: grey;
}
.top-left,
.top-right {
background: purple;
}
.bottom-container {
background: blue;
text-align: center;
}
/* The crux of the layout starts here */
main {
height: 300px;
display: flex;
flex-direction: column;
}
.top-container>* {
display: inline-block;
padding: 1em;
}
.top-left {
float: left;
}
.top-right {
float: right;
}
.spacer {
background: silver;
flex-grow: 1;
}
<main>
<div class="top-container">
<div class="top-left">left</div>
<div class="top-middle">
This should be centred, and always stay on top.
<em>Left</em> and <em>right</em> should drop when the window contracts.
</div>
<div class="top-right">right</div>
</div>
<div class="spacer"></div>
<div class="bottom-container">This is the bottom.</div>
</main>
To get both .top-left and .top-right moving onto a new line when they run out of space you will need to use JavaScript. The following is using vanilla JavaScript but should provide a good starting point. In principle:
We check to see if the combined width of .top-left, .top-middle and .top-right is equal to or bigger than .top-container
If it is then we change the order of .top-left and .top-right to place them after .top-middle. We add margin to .top-left to force it onto a new line and margin to .top-middle to center it (as there are no elements in the same line for justify-content: space-between; to work)
If it isn't we set the styles back to the defaults
var topContainer = document.getElementsByClassName('top-container')[0];
var topLeft = document.getElementsByClassName('top-left')[0];
var topMiddle = document.getElementsByClassName('top-middle')[0];
var topRight = document.getElementsByClassName('top-right')[0];
var topContainerWidth;
var topLeftWidth = topLeft.offsetWidth;
var topMiddleWidth = topMiddle.offsetWidth;
var topRightWidth = topRight.offsetWidth;
var moveDivs;
(moveDivs = function(){
topContainerWidth = topContainer.offsetWidth;
if ((topLeftWidth + topMiddleWidth + topRightWidth) >= topContainerWidth) {
topLeft.style.order = 1;
topLeft.style.marginRight = topRightWidth + 'px';
topMiddle.style.margin = '0 auto';
topRight.style.order = 2;
} else {
topLeft.style.order = 0;
topLeft.style.marginRight = 0;
topMiddle.style.margin = 0;
topRight.style.order = 2;
}
})();
window.addEventListener('resize', function(event){
moveDivs();
});
main div {
white-space: nowrap;
color: white;
}
.top-container {
background: olive;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.top-middle {
background: grey;
}
.top-left,
.top-right {
background: purple;
}
.bottom-container {
background: blue;
text-align: center;
}
/* The crux of the layout starts here */
main {
height: 300px;
display: flex;
flex-direction: column;
}
.top-container>* {
display: inline-block;
padding: 1em;
}
.top-left {
float: left;
}
.top-right {
float: right;
}
.spacer {
background: silver;
flex-grow: 1;
}
<main>
<div class="top-container">
<div class="top-left">left</div>
<div class="top-middle">
This should be centred, and always stay on top.
<em>Left</em> and <em>right</em> should drop when the window contracts.
</div>
<div class="top-right">right</div>
</div>
<div class="spacer"></div>
<div class="bottom-container">This is the bottom.</div>
</main>
I rearranged your markup and used display: table-cell. Here's the fiddle example http://jsfiddle.net/k108vt58/. Hope this helps and is what you're looking for.

Resources