I am using a flexbox to create a sort of pill navigation/wizard system like this:
.wizard-container {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
}
.pill {
background: orange;
padding: 3px 15px;
color: white;
margin: 0;
display: inline-block;
border-radius: 10px;
}
.connector {
display: inline-block;
background: orange;
height: 7px;
flex-grow: 1;
}
<div class="wizard-container">
<div class="pill">Hello</div>
<div class="connector"></div>
<div class="pill">Beautiful</div>
<div class="connector"></div>
<div class="pill">World</div>
</div>
As you may be able to see, the flexbox wraps the .pill elements vertically when the viewport is reduced, but the .connector elements remain horizontal and frankly look quite ugly. I could write a media query to display: none them out, but I was wondering if it's possible to sort of have them draw a sort of snake path starting from the right side of the pill above and ending by the left of the pill below?
I would do this differently using pseudo element and the connector will disappear when the element will wrap. You can have a vertical ones as a bonus to keep the linking.
.wizard-container {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
overflow:hidden; /* This one is important */
}
.pill {
background: orange;
padding: 3px 15px;
color: white;
border-radius: 10px;
font-size:25px;
position:relative;
margin:0 0 10px;
}
.pill:before {
content:"";
position:absolute;
z-index:-1;
right:100%;
height:7px;
top:50%;
transform:translateY(-50%);
width:100vw;
background:inherit;
}
.pill:after {
content:"";
position:absolute;
z-index:-1;
bottom:100%;
width:7px;
left:40px;
height:100vh;
background:inherit;
}
<div class="wizard-container">
<div class="pill">Hello</div>
<div class="pill">Beautiful</div>
<div class="pill">World</div>
</div>
Related
How can we make a margin element fill a flexbox item that is not itself a flexbox?
An element (even a nested one with margins) can easily fill its container using position: absolute -- if it's not inside a flexbox item. Why does this not work for an element inside a flexbox item?
<main>
<nav>NAV</nav>
<section>
<div>DIV</div>
</section>
</main>
<style>
html, body {
position:absolute; top:0; left:0; right:0; bottom:0;
margin: 0;
}
main {
position:absolute; top:0; left:0; right:0; bottom:0;
display: flex;
}
nav {
flex-basis: 250px;
background-color: #eee;
}
section {
flex-basis: 100%;
background-color: #ccc;
margin: 10px;
}
div {
/* position:absolute; top:0; left:0; right:0; bottom:0; */
/* why doesn't the above line work? */
background-color: #cfc;
margin: 10px;
}
</style>
There are many similar-looking questions like this one and this one that don't really apply to items inside flexboxes or items with margin. There are loads of special-case solutions like align-self: stretch, height: 100% and box-sizing: border-box that just don't work in this example because of the nested margin or the fact that the flexboxes themselves aren't nested. The problems with these one-off hacks go on and on...
So what is the general method to fill a flexbox item? What is the issue with position:absolute here? What is the most general way to make an element fill its container?
<main>
<nav>NAV</nav>
<section>
<div>DIV</div>
</section>
</main>
<style>
html, body {
position:absolute; top:0; left:0; right:0; bottom:0;
margin: 0;
min-height: 100%;
}
main {
position:absolute; top:0; left:0; right:0; bottom:0;
display: flex;
min-height: 100%;
}
nav {
flex-basis: 250px;
background-color: #eee;
}
section {
flex-basis: 100%;
background-color: #ccc;
margin: 10px;
display: flex;
}
div {
/* position:absolute; top:0; left:0; right:0; bottom:0; */
/* why doesn't the above line work? */
background-color: #cfc;
margin: 10px;
flex: 1;
}
</style>
Below is an idea you might find worth exploring? I put the nav as a sibling of main rather than a child. That's not necessary for the CSS but the structure makes most sense. Ideally, you have header, nav``main,footer, possibly an aside as well. You really want to avoid all that absolute positioning. It does not play well on mobile phone - imagine what happens if you put a textbox or textarea on your page and a mobile user clicks on it and the soft-keyboard pops up.
body {
display: grid;
grid-template-columns: [left] 196px [main] 1fr [right];
grid-template-rows: [top] 1fr [bottom];
grid-gap: 4px;
outline: 1px dashed #616161;
min-height: 100vh;
min-width: 0;
}
body > nav {
outline: 1px dashed red;
grid-column-start: left;
grid-column-end: main;
grid-row-start: top;
grid-row-end: bottom;
}
body > main {
outline: 1px dashed blue;
grid-column-start: main;
grid-column-end: right;
grid-row-start: top;
grid-row-end: bottom;
display: flex;
flex-flow: column nowrap;
}
section {
flex: 1 1 auto;
display: flex;
flex-flow: column nowrap;
}
div {
flex: 1 1 auto;
margin: 4px;
outline: 1px dotted green;
min-height: auto;
}
<nav>NAV</nav>
<main>
<section>
<div>DIV</div>
</section>
</main>
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>
The title doesn't describe my problem but did'nt find a better one.
So, I have one div containing 3 divs, I wan't two columns with div A in the first one and div B and C in the second, on large screens and one only column on small screens. I could use #media but I think flex can do it without.
This is what I tried:
<div id="container">
<div>
</div>
<div>
</div>
<div>
</div>
</div>
#container
{
border:1px solid #aaa;
height:300px;
width:500px;
max-width:100%;
display:flex;
flex-flow:column;
flex-wrap:wrap;
}
#container > div
{
border:1px solid #aaa;
margin:2px;
flex-grow:1;
min-width:200px;
height:10px;
}
#container > div:first-of-type
{
height:300px;
flex-grow:1;
}
Demo
I fixed the height to force the content to go to 2 columns but then it never goes to onel colum.
Just remove the last css element:
https://jsfiddle.net/j2brc3t3/1/
Live example:
#container
{
border:1px solid #aaa;
height:300px;
width:500px;
max-width:100%;
display:flex;
flex-flow:column;
flex-wrap:wrap;
}
#container > div
{
border:1px solid #aaa;
margin:2px;
flex-grow:1;
min-width:200px;
height:10px;
}
<div id="container">
<div>
</div>
<div>
</div>
<div>
</div>
</div>
#container {
border: 1px solid #aaa;
width: 600px;
max-width: 100%;
display: flex;
text-align: center;
flex-wrap: wrap;
}
#in1 {
background: #a1d;
margin: 5px;
height: 200px;
flex-grow: 1;
min-width: 200px;
}
#in2 {
flex-grow: 1;
display: flex;
flex-flow: column;
min-width: 200px;
}
#in2>div {
background: #e25;
flex-grow: 1;
}
/*
#in2 div:first-child {
margin-bottom: 5px;
}
*/
<div id="container">
<div id="in1">div1</div>
<div id="in2">
<div>div2</div>
<div>div3</div>
</div>
</div>
I found a near solution:
Demo
It answer my question but show a new issue with margins, I need no margin around the container, just 5px between the inner divs, if someone has the perfect solution...
How do I achieve the following layout:
I've attempted to use flexbox, justifying the content using jusitfy-content: space-around;. Which almost works, except the first row each column is justified to the container.
Additionally, this may have to work with six items. In that instance then the bottom row should reflect the same as the top row.
Items are generated dynamically.
Is this at all possible? How would I achieve this?
I can update this if you provide me code but this how I did it in my example.
Working example - https://codepen.io/anon/pen/dJodeZ
.item {
width: 350px;
border-bottom: 1px solid black;
padding: 10px 0px 50px 0px;
margin-bottom: 50px;
margin-left: 25px;
display: inline-block;
}
.wrapper{
text-align: center;
justify-content: center;
width: 95%;
margin-top: 100px;
margin-left: 2.5%;
}
I added a button which you can use to generate more boxes with the class "thing" in the flexbox and see how the layout changes. Hope, it helps. :)
$("button").click(function(){
$(".things").append("<div class='thing'></div>");
});
.things {
padding: 0;
margin: 0;
flex-flow:row wrap;
display: flex;
justify-content: space-around;
}
.thing {
border:1px solid black;
padding: 10px;
margin:30px;
flex:1 0 300px;
min-width:300px;
max-width:350px;
height:300px;
background:red;
align-items:center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>CLick me to make boxes!</button>
<div class="things">
<div class="thing"></div>
<div class="thing"></div>
</div>
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.