How to make flex-grow act not greedy? - css

Markup:
<div class="playground">
<div class="red">
<div class="child">I don't need all this space, but my parents are greddy. : (</div>
</div>
<div class="blue">I want to grow big!</div>
</div>
Stylesheet:
.playground {
width: 500px; height: 500px; background: #ccc; display: flex; flex-direction: column;
}
.red,
.blue {
width: 100%;
}
.red {
flex: 1; background: rgba(255,0,0,.5);
.child {
background: rgba(255,255,255,.5); padding: 10px; margin: 10px;
}
}
.blue {
background: rgba(0,0,255,.5); min-height: 100px; max-height: 300px;
}
http://jsbin.com/waset/1/
In the above example,
Red container is set to use all available space (flex-grow).
Red container is sharing space with blue.
Blue has max-height: 300px.
Red content is not taking all of the height. If red wasn't greedy, it would give away extra 200px to blue.
How to make red not greedy?

Try adding flex:1; to .blue
By the way, you misspelled width in .red,.blue

If I'm understanding you correctly, you can use flex-grow on both .red and .blue and give blue a very large value. Using flex-grow instead of the flex shorthand will default flex-basis to auto. As a result, the flex-basis will be based on the content and then only after the initial content is taken into consideration will leftover space be distributed.
The very large value on .blue will cause it to consume nearly all remaining space up until it reaches its max-width.
.red {
flex-grow: 1;
background: rgba(255, 0, 0, .5);
.child {
background: rgba(255, 255, 255, .5);
padding: 10px 10px;
margin: 10px;
}
}
.blue {
flex-grow: 999;
background: rgba(0, 0, 255, .5);
min-height: 100px;
max-height: 300px;
}

Is this what you are looking for? I can't remember where I learned this technique, but I will post credits when I come across the Website again. I created two flexboxes, a blue and red, and each one expands in size when you hover over them. Hope this helps.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.flx
{
width: 400px;
height: 200px;
font: 12px auto;
display: -webkit-flex;
-webkit-flex-direction: column;
display: flex;
flex-direction: column;
}
.flx > div
{
-webkit-flex: 1 1 auto;
flex: 1 1 auto;
width: 50px;
-webkit-transition: width 0.2s ease-out; /*adjust speed of size change*/
transition: width 0.2s ease-out;
}
.flx > div:nth-child(1){ background : red; }
.flx > div:nth-child(2){ background : blue; }
.flx > div:hover /*adjust size when you hover*/
{
width: 200px;
}
</style>
</head>
<body>
<div class="flx">
<div>red box</div>
<div>blue box</div>
</div>
</body>
</html>

I think you can set flex: 1; instead of flex-grow to .red and .blue. This works in Facebook's Yoga Layout.

Related

Div With Negative Margin and Background Color Not Showing In Flexbox From Outside

I would like to have a div with negative margin impinge upon a flexbox from outside and below the flexbox including its background color. In the attached snippet, the title "Up Up and ..." has a white background that is not showing. The position of the title itself is fine. If you comment out flex-row, you'll see it appear in the lower div. Is this possible to do with flex-box?
I've checked other flex-box negative margin posts. They deal with margins within the flexbox. I wouldn't be doing this if it wasn't a hard requirement of converting a fixed page layout into a responsive one. In addition, the real world project uses an image in the left child.
.parent {
background-color: cyan;
}
.left-child {
height: 16em;
background-color: aquamarine;
}
.right-child {
height: 16em;
background-color: orange;
}
.negative {
margin-top: -4em;
margin-left: 3em;
background-color: white;
}
.flex-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.mf6 {flex: 0 0 50%;}
<div class="flex-row parent">
<div class = "mf6 left-child">
<h1>Left Header Content</h1>
</div>
<div class = "mf6 right-child">
<h1>Right Header Content</h1>
</div>
</div>
<div class="negative">
<h1>Up Up and Away, this is really long in order to make it into the second section. It should have a white background</h1>
</div>
you need to add position:relative; to .negative
here it is:
.parent {
background-color: cyan;
}
.left-child {
height: 16em;
background-color: aquamarine;
}
.right-child {
height: 16em;
background-color: orange;
}
.negative {
margin-top: -4em;
margin-left: 3em;
position:relative; // this line
background-color: white;
}
.flex-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.mf6 {flex: 0 0 50%;}

is it possible to inject background property in the margin of a block element?

demo:https://codepen.io/joondoe/pen/BaBJjqe
I have seen that the css box model include margin as the most outter component of the box model. I am wondering if it is possible to add a background color in the margin of a box element.
div{
display:flex;
text-align:center;
justify-content:center;
align-items:center;
background:orange;
height: 30px;
border: 15px solid green;
margin:50px;
/* to illustrate what I would accomplish */
margin-background:pink;
}
<div> I am a div </div>
I guess you are simply looking for box-shadow:
div{
display:flex;
text-align:center;
justify-content:center;
align-items:center;
background:orange;
height: 30px;
border: 15px solid green;
margin:50px;
box-shadow:0 0 0 50px pink;
}
<div> I am a div </div>
No, you can't do this with a margin, and I see that you've already used border which would be the obvious one to use for what you're asking for.
Other options to achieve the kind of effect you're looking for include:
box-shadow
outline
::before and ::after
Each of these works quite differently, but they could all pull off the effect you've asked for, namely an additional coloured shell around a box, outside of the border.
If you want other background effects such as background images, however, your options are probably limited to using ::before and ::after.
It's not possible (as other answers pointed out), but you could keep what you're doing with use of the ::before (or ::after) pseudo
div {
display: flex;
text-align: center;
justify-content: center;
align-items: center;
background: orange;
height: 30px;
border: 15px solid green;
margin: 50px;
position: relative;
}
div::before {
content: '';
display: block;
position: absolute;
width: calc(100% + 100px);
height: calc(100% + 100px);
left: -50px;
top: -50px;
background: pink;
z-index: -1;
}
<div>
test
</div>
It's not possible to change background color of margin property. I'd prefer to go down the root of wrapping the element in a container that respects your margin instead abusing other properties and pseudo styles. This supports all browsers.
.container {
background-color: red;
display: flex;
}
.container div {
flex: 1 1;
display: flex;
text-align: center;
justify-content: center;
align-items: center;
background: orange;
height: 30px;
border: 15px solid green;
margin: 50px;
}
<div class="container">
<div>I am a div </div>
</div>

CSS: flex-grow maintain vertical aspect ratio

I am creating a website with a circular menu. The website content should fit all onto the homepage without the need to scroll. The menu needs to fill the remaining space on the homepage. However, I am unsure how to maintain the shape of the circle while filling the remaining space on the homepage using flex-grow: 1. Is there a way I can do this with pure CSS? Setting the menu to a set viewport size is not acceptable, it needs to fill the remaining space. I am not having luck using the traditional padding-top: 100% to maintain aspect ratio. The circle is not quite circular and it takes up twice the remaining space.
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle {
background: black;
border-radius: 50%;
flex-grow: 1;
padding-top: 100%;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle"></div>
<div id="footer">Footer</div>
</body>
Edit
I have figured out a way to maintain the aspect ratio of the circle filling the remaining space with flex grow. However, it is what I would consider a hack so I am leaving this question open.
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle {
background: black;
border-radius: 50%;
flex-grow: 1;
/*width: max-content;*/
padding: 0%;
align-self: center;
}
#circle img {
height: 100%;
width: auto;
justify-content: center;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle"><img src="https://luxury.zappos.com/search/imgs/blank.20190219170746.png"></div>
<div id="footer">Footer</div>
</body>
Edit 2
It seems I was mislead by caniuse.com. This solution does not seem to work in most browsers besides chrome. Is there another solution?
Put the circle div inside a wrapper div in your HTML:
<div id="circle-wrap">
<div id="circle"></div>
</div>
Then move the flex rule to the wrapper:
#circle-wrap {
flex-grow: 1;
}
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle-wrap {
flex-grow: 1;
}
#circle {
background: black;
border-radius: 50%;
padding-top: 100%;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle-wrap">
<div id="circle"></div>
</div>
<div id="footer">Footer</div>
</body>

3 expandable column landscape page in pure CSS

If this can be achieved in CSS:
When not hovered: 3 columns split in average width
When hovered on one of the column: that column expands and squeezes other 2 columns
Here's what I've been trying:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* vertical 1:2:1 */
html,
body {
height: 100%;
}
.vertical-divider {
display: flex;
flex-flow: column nowrap;
height: 100%;
}
/* container in page center */
.container {
display: flex;
flex-flow: row nowrap;
background-color: #eee;
flex: 2;
}
.container>.item {
display: flex;
flex-flow: column;
justify-content: left;
align-content: left;
align-items: left;
transition: .3s;
max-width: 50%;
padding-top: 24px;
padding-left: 12px;
background-color: #ccc;
min-width: 10%;
flex: 1;
text-align: left;
}
.container>.item:hover {
transition: .3s;
max-width: 80% !important;
background: #333;
flex: 4;
cursor: pointer;
color: #fff;
}
<!doctype html>
<html>
<head>
</head>
<body>
<div class="vertical-divider">
<div class="container">
<div class="item">
Column 1
</div>
<div class="item">
Column 2
</div>
<div class="item">
Column 3
</div>
</div>
</div>
</body>
</html>
But responsive design (e.g. If I want to just put them vertically if the screen is narrow) seems hard to achieve. So I'm asking if there is a better solution.
Flexbox offers a clean, modern solution. We can transition on the flex property. If you want to make the hovered div take up more room, simply adjust the value to a higher number.
.container {
display: flex;
}
.container > div {
flex: 1;
border-right: 2px solid black;
height: 300px;
padding: 10px;
transition: 0.5s flex;
}
.container > div:hover {
flex: 3;
}
.container > div:last-child {
border-right: 0;
}
<div class="container">
<div>col 1</div>
<div>col 2</div>
<div>col 3</div>
</div>
Edit A new requirement has emerged: make it responsive. Flexbox makes this an easy addition by changing the flex-direction property inside a simple media query.
#media screen and (max-width: 700px) {
.container {
flex-direction: column;
height: 100vh;
}
.container > div {
border-right: none;
border-bottom: 2px solid;
}
}
With the media query in place, our example is now complete.
Have a look.

Flex css layout with fixed and variable elements

I am hoping to create the following layout in pure CSS. I know that I can achieve this with a JavaScript solution, but a CSS solution would be much cleaner, if it is possible.
I have created a jsFiddle which I know is incorrect, to provide a starting point. The HTML and CSS I use in the jsFiddle are shown below.
Notes:
I would like this to fill the full height of the window, so that there is no scroll bar for the page (but see my last point)
There are two sections that can contain a variable number of elements.
The red elements are images which the user can add on the fly, and which will be given a frame with a fixed aspect ratio (shown here as a square)
The green section will contain a list which will have at least one item, so it will have a fixed minimum height. It may have up to four items, so its height may change. I would prefer not to have this section scroll. If the user makes the window too short for both the green and the blue elements to show full height, then the page as a whole will have to scroll.
My question is: can this be done in pure CSS? If you know that there is a solution, and if you can provide some pointers as to how I can achieve it, then I can continue to work towards that solution. If you know that there is no solution, then I will simply adopt a JavaScript approach.
If there is a solution, and you would be happy to share it, then I will be delighted that you have saved me a lot of time.
<!DOCTYPE html>
<html>
<head>
<title>Flex</title>
<style>
body, html {
height: 100%;
margin: 0;
background: #000;
}
main {
width: 30em;
height: 100%;
margin: 0 auto;
background: #333;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.head{
width:100%;
-webkit-flex: 3em;
flex: 3em;
background: #fcc;
}
.expand{
width:100%;
overflow:auto;
}
.filler {
width:100%;
height:20em;
background: #003;
border-bottom: 1px solid #fff;
}
.space {
width:100%;
height:10em;
border-bottom: 1px solid #fff;
}
.foot{
width:100%;
-webkit-flex: 0 0 2em;
flex: 0 0 2em;
background: #cfc;
}
</style>
</head>
<body>
<main>
<div class="head">HEAD</div>
<div class="expand">
<div class="space"></div>
<div class="filler"></div>
<div class="space"></div>
</div>
<div class="foot">FOOT</div>
</main>
</body>
</html>
If I understand it well,
main {
height: auto;
min-height: 100%;
}
.head {
min-height: 3em;
}
.foot {
min-height: 2em;
}
.expand {
flex-basis: 0; /* Initial height */
flex-grow: 1; /* Grow as much as possible */
overflow: auto;
}
body,
html {
height: 100%;
margin: 0;
background: #000;
}
main {
width: 20em;
min-height: 100%;
margin: 0 auto;
background: #333;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.head {
width: 100%;
min-height: 3em;
background: #fcc;
}
.expand {
width: 100%;
flex-basis: 0;
flex-grow: 1;
overflow: auto;
}
.filler {
width: 100%;
height: 20em;
background: #003;
border-bottom: 1px solid #fff;
}
.space {
width: 100%;
height: 2em;
border-bottom: 1px solid #fff;
}
.foot {
width: 100%;
min-height: 2em;
background: #cfc;
}
<main>
<div class="head">HEAD</div>
<div class="expand">
<div class="space"></div>
<div class="filler"></div>
<div class="space"></div>
</div>
<div class="foot">FOOT</div>
</main>

Resources