How to "extract aside" an element from a vertical flexbox layout? - html

Let's say I have a couple elements arranged in a column (using flexbox):
And I would like to "spotlight" element #2 in green and set it aside, but let the rest of the elements remain ordered in a column:
Is there a way to do this with just CSS and retain dynamic layout?
I've thought of a workaround by duplicating the green element and wrapping all of this in another flexbox layout ([2[1234]]) so that in the column case, the first green element is hidden ([#[1234]) whereas in the wider case, the second element is hidden ([2[1#34]), but this is a bit messy in the markup - and actually causes issues when the element has some kind of state (e.g. a <video>) that is expected to be retained in both cases.
I've also thought about using position: absolute on the green element, but I couldn't get that to work nicely either: once I set position: relative on the top-level (black) container, I can position the green element where I want, but setting position: absolute on the column container (red) so that I can position in to the right means green element is now positioned relative to the column container again.
Is there a solution I'm overlooking?

Yes you can do this using just CSS. Here's the code for the answer to your question.
HTML:
<div class="gridcontainer">
<div class="display">
</div>
<div class="flexcontainer">
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
<div class="card">4</div>
<div class="card">5</div>
</div>
</div>
CSS:
.gridcontainer{
display: grid;
background: yellow;
grid-template-columns: 1fr .5fr;
height: 20em;
}
.flexcontainer{
background: skyblue;
padding: .5em;
grid-column: 2;
display: flex;
flex-flow: column nowrap;
align-items: center;
}
.card{
background: pink;
border: .1em solid red;
width: 80%;
padding: 1em;
text-align: center;
}
.flexcontainer .card:hover{
position: absolute;
width: 45%;
height: 15em;
transform: translateX(-50vw) translateY(1vh);
}

const expand = document.querySelector('.expand');
expand.addEventListener('click', () => {
expand.parentNode.classList.toggle('active');
});
body {
margin: 0;
}
aside {
display: flex;
flex-direction: column;
gap: 1em;
flex-wrap: wrap;
width: 50vw;
height: 100vh;
background-color: rgba(0, 0, 0, .1);
padding: 1em;
box-sizing: border-box;
position: relative;
transition: .2s;
}
div {
flex: 1;
background-color: rgba(0, 0, 0, .1);
display: flex;
justify-content: center;
align-items: center;
order: unset;
}
.expand {
position: absolute;
right: 0;
top: 50%;
transform: translate(50%, -50%);
padding: 0;
display: flex;
border: none;
background-color: #ddd;
border-radius: 100%;
width: 24px;
height: 24px;
box-shadow: 0 0 0 3px white;
}
.expand svg {
margin: auto;
border-radius: 100%;
transition: .2s;
}
aside.active {
width: 90vw;
}
.active .expand svg {
transform: rotate(180deg);
}
.active .two {
flex: 100 0 100%;
order: -1;
}
<aside class="aside">
<button class="expand">
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd"><path d="M12 0c6.623 0 12 5.377 12 12s-5.377 12-12 12-12-5.377-12-12 5.377-12 12-12zm0 1c6.071 0 11 4.929 11 11s-4.929 11-11 11-11-4.929-11-11 4.929-11 11-11zm-3 5.753l6.44 5.247-6.44 5.263.678.737 7.322-6-7.335-6-.665.753z"/></svg>
</button>
<div class="one">1</div>
<div class="two">2</div>
<div class="thr">3</div>
<div class="for">4</div>
</aside>

if you want, i can answer this, but not using flexbox, using Grid.

Related

How can i center 3 div inside a div with a space between

I would like to center all the content of the "box" container div, then all the "items" in the "shop-box" with a space between them. This is what I've tried so far using CSS flexbox.
.shop-container {
height: auto;
margin: 0 auto;
padding: 10px;
position: relative;
margin-top: 30px;
border: 5px solid red;
width: 100%;
height: 400px;
}
.shop-box {
width: 95%;
height: 83%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border: 5px solid rgb(51, 255, 0);
}
.box {
display: flex;
position: absolute;
width: 100%;
margin: 5 5px;
}
.item {
background: gray;
width: 300px;
height: 300px;
margin: 0 5px;
}
<div class="shop-container">
<div class="shop-box">
<div class="box">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</div>
You can do that by using a flexbox, which you already are (though with some problems).
On .shop-container you'll want either the width: 100%; or margin: 0 auto;. Both doesn't make sense (if it takes up the whole width, centering it becomes a meaningless act.
I'm not sure if you need the position: relative for some unrelated reason ? If not then i'd get rid of that.
The fact that you've wrapped the content (the 3 <a>s) within 3 layers of <div>s is generally a bad idea (again unless you have some unrelated reason to do so). I'd recommend simplifying it a lot, such as this:
.box {
display: flex;
min-width: fit-content;
flex-flow: row nowrap; /* = (horizontal) dont wrap if the items dont fit horizontally; alternatives: wrap | nowrap; */
margin: 0 auto; /* = center the box, if it happens to be not as wide as its parent */
justify-content: center; /* = (horizontal) center the <a>s ; try these alternatives: flex-start | flex-end | center | space-between | space-around | space-evenly */
align-items: flex-start; /* = (vertical) align the <a>s to the top of this container (if they were to have different heights); possible alternatives: center | stretch | flex-start | flex-end | baseline */
gap: 0.4rem; /* = space between the <a>s */
border: 0.4rem solid rgb(51, 255, 0);
}
a {
display: flex;
flex: 0 0 auto; /* = start off autosized based on the item(s) inside here; neither grow nor shrink beyond that. */
flex-flow: column nowrap; /* = (vertical) place additional content that is located within the <a> (if any) under the current content */
justify-content: flex-start; /* = (vertical) the item(s), if different heights, should cling to the top */
align-items: center; /* = (horizontal) if the <a>s were to be be allowed to grow wider than neccecary, then center the item(s) within the link; alternatives: flex-start | flex-end | center */
}
.item {
width: 300px;
height: 300px;
background: gray;
}
/* a { padding: 0.4rem; background: blue; } /* uncomment to see that the <a> could be bigger than its content */
/* a:first-child .item { height: 400px; } /* uncomment to see what happens when one of the items is taller */
/* .box { width: 800px; } .item { width: 100px; } /* uncomment to see what happens if the box was wider than neccecary */
<div class="box">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Perhaps this might help. I'm adding display: flex and align-items: center to the .shop-box class, and justify-content: space-between to .box.
Learn more about CSS Flexbox here.
.shop-container {
height: auto;
margin: 0 auto;
padding: 10px;
position: relative;
margin-top: 30px;
border: 5px solid red;
width: 100%;
height: 400px;
}
.shop-box {
display: flex;
align-items: center;
width: 95%;
height: 83%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border: 5px solid rgb(51, 255, 0);
}
.box {
display: flex;
justify-content: space-between;
position: absolute;
width: 100%;
margin: 5 5px;
}
.item {
background: gray;
width: 300px;
height: 300px;
margin: 0 5px;
}
<div class="shop-container">
<div class="shop-box">
<div class="box">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</div>

Flex child overflowing parent height in modal [duplicate]

This question already has answers here:
How to make an element width: 100% minus padding?
(15 answers)
Fill remaining vertical space with CSS using display:flex
(6 answers)
Make a div fill the height of the remaining screen space
(41 answers)
Closed 2 years ago.
I'm trying to build a modal screen using CSS, HTML. Code below:
.container {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 1;
background-color: rgba(0, 0, 0, 0.6);
}
.content {
border-radius: 4px;
background-color: white;
padding: 16px;
height: 80vh;
width: 80vw;
}
.title {
padding: 16px;
}
.body {
padding: 16px;
height: 100%;
width: 100%;
background-color: blue;
min-height: 0;
}
<div class="container">
<div class="content">
<div class="title">The bugged modal screen</div>
<div class="body">
This is overflowing
</div>
</div>
</div>
As the example shows, the flex child (blue content) is overflowing its parent. I've tried to use min-height: 0 seens not to be working for me. Help apprecited to put the child inside inside its boundaries.
Add flex rules to container .content. Like this:
.content {
...
display: flex;
flex-direction: column;
}
Also, remove width: 100% out of .body.
.container {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 1;
background-color: rgba(0, 0, 0, 0.6);
}
.content {
border-radius: 4px;
background-color: white;
padding: 16px;
height: 80vh;
width: 80vw;
display: flex;
flex-direction: column;
}
.title {
padding: 16px;
}
.body {
padding: 16px;
height: 100%;
/*width: 100%;*/
background-color: blue;
}
<div class="container">
<div class="content">
<div class="title">The bugged modal screen</div>
<div class="body">
This is overflowing
</div>
</div>
</div>

How to wrap content in the div?

i have flexbox container and divs in it. I want the content to stay inside the div. In the sense that if the content exceeds the width of div then it should start from next line.
What i have tried doing?
used white-space: nowrap property. This added horizontal scrollbar which is not desired.
Below is the code,
CSS:
.notification_message_wrapper {
width: calc(100% - 450px);
position: absolute;
top: 105px;
left: 250px;
margin: 0 auto;
display: flex;
align-items: center;
.box {
background-color: white;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.3);
top: 100px;
left: 250px;
flex: 1;
}
.message {
display: flex;
color: green;
flex-direction: column;
justify-content: space-between;
font-weight: normal;
padding: 10px;
white-space: nowrap;
.content {
height: auto;
white-space: nowrap;
}}}
HTML:
<div class="box_wrapper">
<div class="box">
<div class='message>
<div class="container">
<div>title</div>
<div>detail</div>
<div>
<div>
<h2>Debug</h2>
someresponse
<div/></div></div></div></div>
<div>close</div></div>
The divs with title, detail should not go out of the div...how could i solve this. could someone help. thanks.
just add overflow: auto; or overflow: hidden to your div. refer this link https://www.w3schools.com/cssref/tryit.asp?filename=trycss_overflow

How to layer shapes in flexbox

I am currently using this solution for modified for my use case specifically here. When I originally saw the design I figured that I would make two divs inside one flexbox container, the div on the right would be z index'd above the one on the right. Something like...
.container {
display: flex;
width: 200px;
flex-direction: row;
}
.left-side {
flex: 4;
background-color: red;
}
.right-side {
flex: 1;
background-color: orange;
z-index: 3;
border-style: 2px solid white;
border-radius: 50%;
}
<div class="container">
<div class="left-side">
View Cart
</div>
<div class="right-side">
3
</div>
</div>
This doesn't layer my elements on top of one another at all because they are positioned next to each other. So my question is:
How can I use make a layered layout while still taking advantage of all the nice positioning flexbox allows without the position absolute / position relative solution that I'm hacking together? Or, is this position absolute / relative the correct way to solve my problem?
You can apply the red background to the container, and use transform: translateX(50%) to move the orange circle half way outside of the container to pull off that effect.
.container {
display: flex;
width: 200px;
flex-direction: row;
background: red;
position: relative;
color: white;
}
.container:before {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
content: '';
}
.container:before,
.count {
border: 2px solid white;
}
.left-side {
flex-grow: 1;
}
.center {
display: flex;
justify-content: center;
align-items: center;
}
.count {
width: 50px;
height: 50px;
background-color: orange;
border-radius: 50%;
transform: translateX(50%);
}
<div class="container">
<div class="left-side center">
View Cart
</div>
<div class="right-side">
<div class="count center">3</div>
</div>
</div>
Negative margins
You can use negative margins to solve the problem without using position absolute/relative solution.
.container {
display: flex;
width: 200px;
flex-direction: row;
}
.left-side {
flex: 4;
background-color: red;
}
.right-side {
flex: 1;
background-color: orange;
z-index: 3;
border-style: 2px solid white;
border-radius: 50%;
margin-left: -60px;
text-align: center;
}
<div class="container">
<div class="left-side">
View Cart
</div>
<div class="right-side">
3
</div>
</div>

Flex basis 100% in column flexbox: full height in Firefox, not in Chrome

I would like a column of divs, of any number, each with width 100% and height 100% of their parent div, so one is visible initially, and the others overflow the parent downwards. I've set the divs to have flex: 0 0 100%;, inside a parent div with display: flex and flex-direction: column to achieve this.
The parent div is itself of unknown height, so it is also a child of a display: flex and flex-direction: column, set to flex: 1 0 0 to take remaining space in its container.
In Firefox the output is as I would like it:
However, not in Chrome:
How can I achieve the Firefox style in Chrome, without Javascript?
You can see this in action at http://plnkr.co/edit/WnAcmwAPnFaAhqqtwhLL?p=preview, as well as the corresponding version with flex-direction: row, which works consistently in both Firefox and Chrome.
For reference, the full CSS
.wrapper {
display: flex;
flex-direction: column;
height: 150px;
width: 200px;
border: 4px solid green;
margin-bottom: 20px;
}
.column-parent {
flex: 1 0 0;
display: flex;
flex-direction: column;
border: 2px solid blue;
}
.column-child {
flex: 0 0 100%;
border: 2px solid red;
}
and HTML
<div class="wrapper">
<p>Some content of unknown size</p>
<div class="column-parent">
<div class="column-child">
Should be inside green
</div>
<div class="column-child">
Should be outside green
</div>
</div>
</div>
This seems to be a bug with Chrome. Similar to the ones reported here (issue 428049) and perhaps related to (issue 346275).
This says:
- Browsers are supposed to resolve percentages on the flex item's child, *if* its flex-basis is definite.
- Gecko is *always* resolving percentages regardless of the flex-basis.
- Chrome is *never* resolving percentages, regardless of the flex-basis.
Summarily, Chrome is not resolving percent heights on flex-item's child (even if the child itself is a flex-item), while all other browsers do.
This can be demonstrated in the below snippet: (Fiddle here)
* { box-sizing: border-box; margin: 0; padding: 0; }
div.wrap {
height: 120px; width: 240px; margin: 0px 12px;
border: 1px solid blue; float: left;
display: flex; flex-direction: column;
}
div.parent {
flex: 0 0 100%;
border: 1px solid green;
display: flex; flex-direction: column;
}
div.item {
flex: 0 0 100%;
border: 1px solid red;
}
<div class="wrap">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
</div>
<div class="wrap">
<div class="parent">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
</div>
</div>
The second div should show the same behaviour as the first one. Other browsers (IE11, Edge, FF39) show it correctly. Chrome fails here and does not resolve div.item correctly. It needs a fixed height on its parent, without which it uses min-content as its height and thus does not overflow.
Whereas, in the first div, the div.items are correctly resolved and overflow accordingly. This is because there is a fixed height on the parent (i.e. div.wrap)
Possible Solution:
As a workaround, if you are sure to have only two elements (p and div) inside your wrapper, then you could give them a 50% height. You have to provide a height:50% to your .column-parent. Chrome needs a fixed height on parent as demonstrated above.
Then everything will work as you need to.
Demo Fiddle: http://jsfiddle.net/abhitalks/kqncm65n/
Relevant CSS:
.wrapper > p { flex: 0 0 50%; } /* this can be on flex-basis */
.column-parent {
flex: 1 0 auto; height: 50%; /* but, this needs to be fixed height */
display: flex; flex-direction: column;
border: 2px solid blue;
}
.column-child {
flex: 0 0 100%; /* this flex-basis is then enough */
border: 2px solid red;
}
PS: There also seem to be differences in the way jsfiddle and plnkr render. I don't know why, but sometimes I get different results!
As stated in Abhitalks response, there is a bug (or a different interpretation of the standard) in the way Chrome handles the height attribute here.
I have found a hack that is working both in Chrome FF and IE
The only issue is that you ned to have as many rules as posible children there are.
The trick is to set the flex-direction to row, set the flex-basis (that is now the width) to 100%, and then translate the elements
.container {
border: solid 2px blue;
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
position: relative;
}
.filler {
border: solid 1px black;
flex: 0 0 80px;
background-color: lightgreen;
transition: flex 1s;
}
.container:hover .filler {
flex: 0 0 40px;
}
.test {
border: solid 1px red;
flex: 1 0 25px;
display: flex;
flex-direction: row;
position: relative;
}
.child {
background-color: rgba(200, 0, 0, 0.26);
flex: 0 0 100%;
}
.child:nth-child(2) {
background-color: rgba(255, 255, 0, 0.48);
transform: translateX(-100%) translateY(100%);
}
.child:nth-child(3) {
background-color: rgba(173, 216, 230, 0.28);
transform: translateX(-200%) translateY(200%);
}
<div class="container">
<div class="filler"></div>
<div class="filler"></div>
<div class="test">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
</div>
</div>
If there could be another child, you would need a nth-child(4) rule, and so on
I have added an hover effect to check how the size adapts
My previous answer is a hack that exploits a particular setup of the layout wanted.
An alternate way, more general, of getting around this Chrome bug is to use an intermediate element in the layout, and set this element size using top: 0px and bottom: 0px. (instead of height: 100%) There is still a bug in the way Chrome handles the calculus, that needs a fake animation to make it adjust properly
.container {
border: solid 2px blue;
height: 200px;
width: 200px;
display: flex;
flex-direction: column;
position: relative;
}
.filler {
border: solid 1px black;
flex: 0 0 94px;
background-color: lightgreen;
transition: 1s;
}
.container:hover .filler {
flex: 0 0 50px;
}
.test {
border: solid 1px red;
flex: 1 0 25px;
display: flex;
flex-direction: row;
position: relative;
}
#-webkit-keyframes adjust2 {
0% {flex-basis: 100%;}
100% {flex-basis: 100.1%;}
}
.child {
background-color: rgba(200, 0, 0, 0.26);
width: 100%;
height: 100%;
flex: 1 0 100%;
-webkit-animation: adjust2 1s infinite; /* only needed for webkit bug */
}
.intermediate {
width: 100%;
position: absolute;
top: 0px;
bottom: 0px;
display: flex;
flex-direction: column;
}
.child:nth-child(n+2) {
background-color: rgba(255, 255, 0, 0.48);
}
.child:nth-child(n+3) {
background-color: rgba(173, 216, 230, 0.28);
}
<div class="container">
<div class="filler"></div>
<div class="test">
<div class="intermediate">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
</div>
</div>
What about adding 100% to the container:
.column-parent {
flex: 1 0 100%;
}
And flex-grow to 1 in the contained element without adjusting the flex basis:
.column-child {
flex: 1 0 0;
}
Here's how it would look: http://plnkr.co/edit/H25NQxLtbi65oaltNVax?p=preview