I have the following layout:
#container {
display: flex;
flex-wrap: wrap;
}
#a {
flex-basis: 100%;
height: 100px;
}
#b {
flex-grow: 1;
height: 150px;
}
#c {
flex-grow: 2;
height: 100px;
}
/* Less relevant styles */
#a, #b, #c {
font-family: sans-serif;
font-size: 3em;
color: white;
text-shadow: 1px 1px 3px grey;
display: flex;
justify-content: center;
align-items: center;
}
#a {
background-color: #FFC300;
}
#b {
background-color: #FF5733;
}
#c {
background-color: #C70039;
}
<div id="container">
<div id="a">A</div>
<div id="b">B</div>
<div id="c">C</div>
</div>
How can I change the A element so that instead of taking up all the horizontal space, it's aligned to the C element? Basically I want to achieve something like that:
Note that I don't want to set something like margin-left: 33% on the A element, because I don't know if the B element will always take up one third of the horizontal space. I want the A element to remain aligned to C even if the width of B or C changes.
If possible, I want to achieve this using flexbox, but I'm open to workarounds.
Wrapping nested flexboxes and justify-content:flex-end is one option.
#container {
display: flex;
}
[class^="wrap"] {
display: flex;
flex-direction: column;
justify-content: flex-end;
}
/* Less relevant styles */
#a,
#b,
#c {
height: 100px;
font-family: sans-serif;
font-size: 3em;
color: white;
text-shadow: 1px 1px 3px grey;
display: flex;
justify-content: center;
align-items: center;
}
#a {
background-color: #FFC300;
}
#b {
background-color: #FF5733;
}
#c {
background-color: #C70039;
}
.wrap-left {
flex: 1;
}
.wrap-right {
flex: 2;
}
<div id="container">
<div class="wrap-left">
<div id="b">B</div>
</div>
<div class="wrap-right">
<div id="a">A</div>
<div id="c">C</div>
</div>
</div>
This sort of layout is standard for a table element (especially because of the variable width of each column). Something to consider, if possible.
Basically, you need to force "A" and "C" into the same column so they can track each other's width.
One method would be to force "B" to consume all space in the first column. This can be done by nesting "B" in a container with 100% height, then aligning "B" to the bottom half.
#container {
display: flex;
flex-flow: column wrap;
height: 200px;
}
nested-container {
flex-basis: 100%;
display: flex;
align-items: flex-end;
}
#b {
flex: 1;
background-color: #FF5733;
}
#a {
background-color: #FFC300;
}
#c {
background-color: #C70039;
}
#a, #b, #c
{
height: 100px;
font-family: sans-serif;
font-size: 3em;
color: white;
text-shadow: 1px 1px 3px grey;
display: flex;
justify-content: center;
align-items: center;
}
<div id="container">
<nested-container>
<div id="b">B</div>
</nested-container>
<div id="a">A</div>
<div id="c">C</div>
</div>
You can group your boxes this way:
<div id="container">
<div class="first-col">
<div id="empty"></div>
<div id="b">B</div>
</div>
<div class="second-col">
<div id="a">A</div>
<div id="c">C</div>
</div>
</div>
and style their width togehter by column, but their color and content by id
Related
This question already has answers here:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
(6 answers)
Closed 4 months ago.
For a layout, I need to have three flex items (rows) in a flex container, and I want them justified as space-between... The first row will contain some cloud tags, the second a price, and the third a Read more link.
But there will be cases where for specific items, only the last row (the Read more) will need to exist.
So, in those cases, for uniformity, I want the Read more link to be placed at the bottom of the container; but space-between doesn't help much towards that approach...
What can I do to have a fallback justify-content property set to end for when there is only one child item?
.container {
background-color: #aaa;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
height: 200px;
margin-bottom: 20px;
}
.tags {
display: flex;
}
.tags span {
background-color: #f0f;
padding: 10px;
margin: 0 0 0 10px;
}
.price {
display: flex;
background-color: #ff0;
padding: 10px;
font-size: 150%
}
.read-more {
display: flex;
background-color: #0ff;
padding: 10px;
}
<div class="container">
<div class="tags">
<span>tag 1</span><span>tag2</span><span>tag 3</span>
</div>
<div class="price">
$100
</div>
<div class="read-more">
Read more >>
</div>
</div>
<div class="container">
<div class="read-more">
Read more >>
</div>
</div>
If you are able/willing to change the order of the flex-items in your HTML code, you can reverse them there and use flex-direction: column-reverse; on the container. That way the "read more" element is the first flex-item and due to the reversed direction at the bottom of the container:
.container {
background-color: #aaa;
display: flex;
flex-direction: column-reverse;
justify-content: space-between;
align-items: flex-end;
height: 200px;
margin-bottom: 20px;
}
.tags {
display: flex;
}
.tags span {
background-color: #f0f;
padding: 10px;
margin: 0 0 0 10px;
}
.price {
display: flex;
background-color: #ff0;
padding: 10px;
font-size: 150%
}
.read-more {
display: flex;
background-color: #0ff;
padding: 10px;
}
<div class="container">
<div class="read-more">
Read more >>
</div>
<div class="price">
$100
</div>
<div class="tags">
<span>tag 1</span><span>tag2</span><span>tag 3</span>
</div>
</div>
<div class="container">
<div class="read-more">
Read more >>
</div>
</div>
You can give the container a position: relative; tag, the .read-more class, and the :only-child pseudo class. Then when it is the only child in the container, it will add the attributes position:absolute; bottom:0; right:0; to it.
This moves it to the bottom right of the container. The justify-content: end !important; doesn't move the container to where you want it to be.
Example:
.container {
background-color: #aaa;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
height: 200px;
margin-bottom: 20px;
position:relative;
}
.tags {
display: flex;
}
.tags span {
background-color: #f0f;
padding: 10px;
margin: 0 0 0 10px;
}
.price {
display: flex;
background-color: #ff0;
padding: 10px;
font-size: 150%
}
.read-more {
display: flex;
background-color: #0ff;
padding: 10px;
}
.read-more:only-child{
position:absolute;
bottom:0;
right:0;
}
<div class="container">
<div class="tags">
<span>tag 1</span><span>tag2</span><span>tag 3</span>
</div>
<div class="price">
$100
</div>
<div class="read-more">
Read more >>
</div>
</div>
<div class="container">
<div class="read-more">
Read more >>
</div>
</div>
counter.js
import "./Counter.css";
const Counter = (props) => {
return (
<div className="counter">
<h1>{`Counter ${props.count}`}</h1>
<div className="counter__buttons">
<button onClick={props.incrementCounter}>Increment</button>
<button onClick={props.decrementCounter}>Decrement</button>
</div>
</div>
);
};
Counter.css
.counter {
display: flex;
color: white;
align-items: center;
width: 100%;
height: 100%;
}
.counter > .counter__buttons > button {
color: black;
background-color: grey;
margin: 10px;
padding: 30px;
border: 0;
border-radius: 10px;
}
i want to move the buttons below counter and place the counter and buttons in the center of the page how to change it , display : flex in counter should not be removed
Would something like this work? You can set the flex-direction of a wrapping div to column and set the second div (in your case your buttons) back to flex-direction: row and finally just center it with margin: 0 auto.
<div id="wrap">
<div id="one">1</div>
<div id="two">2
<div id="three">3</div>
<div id="four">4</div>
</div>
</div>
#wrap {
display: flex;
flex-direction: column;
}
#two {
display: flex;
flex-direction: row;
margin: 0 auto;
}
Do you want something like this?
.page {
background: black;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
}
.counter {
display: flex;
flex-direction: column; /* add this */
color: white;
align-items: center;
/* width: 100%;*/
/* height: 100%;*/
}
.counter > .counter__buttons > button {
color: black;
background-color: grey;
margin: 10px;
padding: 30px;
border: 0;
border-radius: 10px;
}
<div class="page">
<div class="counter">
<h1>Counter 5</h1>
<div class="counter__buttons">
<button onClick={props.incrementCounter}>Increment</button>
<button onClick={props.decrementCounter}>Decrement</button>
</div>
</div>
</div>
If so, you can make your whole page a flex container and use justify-content and align-items just like you did it for the .counter.
(I did HTML instead of JSX so I could add the snippet easier... don't forget to make changes in your own code)
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.
Here is my code snippet:
.container {
display: flex;
flex-direction: column;
}
.container > div {
padding: 20px;
color: #fff;
margin: 5px;
text-align: center;
font-size: 30px;
}
.fruits {
order: 2;
background: #ff5423;
}
.container :not(.fruits) {
order: 1;
}
.flowers {
background: #f970bd;
}
.trees {
background: #049500;
}
<div class="container">
<div class="fruits">The fruits</div>
<div class="flowers">The flowers</div>
<div class="fruits">The fruits</div>
<div class="trees">The trees</div>
<div class="fruits">The fruits</div>
</div>
I am putting all .fruits div in the bottom using flex-direction: column;. There are two other divs .flowers and .trees which can be placed randomly anywhere inside .conatiner and I can't handle that. I want them to take half of its parent width so they take only one row.
What I want to achieve:
Giving 50% width will not work here. I know the rule says the direction is column-wise, however, I still hope if there is any available method/trick to do so! Any other workaround using different technique rather than using flex will also help.
You can do this with flex-direction: row you just need to set flex-wrap: wrap on parent and flex: 0 0 50% on elements you want to take half width.
You also need to use * {box-sizing: border-box} for paddings and calc() for margins.
* {
box-sizing: border-box;
}
.container {
display: flex;
flex-wrap: wrap;
}
.container > div {
padding: 20px;
color: #fff;
margin: 5px;
flex: 0 0 calc(100% - 10px);
text-align: center;
font-size: 30px;
}
.fruits {
order: 2;
background: #ff5423;
}
.container div:not(.fruits) {
order: 1;
flex: 0 0 calc(50% - 10px);
}
.flowers {
background: #f970bd;
}
.trees {
background: #049500;
}
<div class="container">
<div class="fruits">The fruits</div>
<div class="flowers">The flowers</div>
<div class="fruits">The fruits</div>
<div class="trees">The trees</div>
<div class="fruits">The fruits</div>
</div>
My question is simple. Is it possible to have display: table on a flex item?
When I set it on an item, the layout doesn't work as expected - the second flex item doesn't grab the available vertical/horizontal space.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
display: table;
background-color: red;
}
.content > span {
display: table-cell;
vertical-align: middle;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Of course you can, but not necessarily a good solution though.
May I suggest you use flex all the way.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
background-color: red;
display: flex;
align-items: center;
justify-content: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Side note:
A table element is special and doesn't behave as normal block or inline elements. To make it work with display: table, you need to set a height to your parent as well as to the table, like in this sample, http://jsfiddle.net/LGSon/0bzewkf4.
Still, as you can see, the table height is 200px because flex has some flaws when it comes to limit height's, so it is not display:table that breaks your flex, it is flex who is somewhat broken.
Here is another answer of mine, showing yet another workaround where flex doesn't behave: Normalizing Flexbox overflow in IE11
It's a big question why you use table in flexbox...
But you can set width to your table and inherit min-height from parent
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
display: table;
flex:1;
background-color: red;
width:100%;
min-height:inherit;
}
.content > span {
display: table-cell;
vertical-align: middle;
height: 100%;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
You should not need to use a table layout at all here. Just add align-self: center; to .content- > span {.... And make the span element become a flex item as well, by adding display:flex to the .content element. The reason why the table layout is not working for you is because vertcal-align has no effect on the alignment of flex items. So mixing a flex-layout with a table-layout by changing the display property of a flex-item seems not to be a good idea, because you are loosing the flexibility of the flex-layout.
Properties not affecting flexible boxes
Because flexible boxes use a different layout algorithm, some properties do not make sense on a flex container:
column-* properties of the multiple column module have no effect on a flex item.
float and clear have no effect on a flex item. Using float causes the display property of the element to compute to block.
vertical-align has no effect on the alignment of flex items.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
display: flex;
background-color: red;
}
.content > span {
flex: 1;
align-self: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Tables are row or horizontally oriented so wouldn't you get weird results if placed within a flex-column? I changed everything to a good old block, they stack very well in a column flow--vertical harmony.
.content is dead center by using: position: relative; top: 50%; and translateY(360%); for vertical and text-align: center; for horizontal. Oh and of course turning that span into a useful block.
Changed the following:
.content {
flex: 1;
background-color: red;
}
.content > span {
display: block;
position: relative;
top: 50%;
transform: translateY(360%);
text-align: center;
}
I changed display: table to table-row is this what you wanted?
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
background-color: red;
}
.content > span {
display: block;
position: relative;
top: 50%;
transform: translateY(360%);
text-align: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>