Reputation: 417
I'd like to use flex to create something similar to this with CSS:
What I've tried so far is this code:
#dot-container {
position: absolute;
width: 30vw;
background: black;
height: 8vw;
justify-content: center;
align-items: center;
display: flex;
}
.dot {
border-radius: 100%;
width: 2vw;
height: 2vw;
margin: 3.2%; /*(30-2*7) / (7-2)*/
background: green;
}
<div id="dot-container">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
But I cannot really get it working such that the leftmost and rightmost dots are exactly at the left and the right corner like you can see it in my image above.
Note: also justify-content: space-between;
seems not to work because the dots themselves are most left but not dots center!
Upvotes: 5
Views: 1823
Reputation: 272779
You can rely on overflow by having the width of elements and the margin exceed the total width. From your figure we have half a circle overflowing from left and right thus a full circle is overflowing
Considering this, the total width is 6*width_of_circle + total_margin
. We can divide this margin to 6 parts (between our 7 cirles) and we will have 6*width_of_circle + 6*small_margin
so each margin will be total_width/6 - width_of_circle
that we split on each side:
#dot-container {
position: absolute;
width: 30vw;
background: black;
height: 8vw;
justify-content: center;
align-items: center;
display: flex;
margin:10px;
}
.dot {
border-radius: 100%;
width: 2vw;
height: 2vw;
margin: 0 calc((100%/6 - 2vw)/2);
background: green;
flex-shrink:0; /* Don't shrink*/
}
<div id="dot-container">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
You can express everything in percentage if you want:
#dot-container {
position: absolute;
width: 30vw;
background: black;
height: 8vw;
justify-content: center;
align-items: center;
display: flex;
margin:10px;
}
.dot {
border-radius: 100%;
width: calc(100%/15);
margin: 0 calc((100%/6 - 100%/15)/2);
background: green;
flex-shrink:0; /* Don't shrink*/
}
/* To keep the square ratio*/
.dot:before {
content:"";
display:block;
padding-top:100%;
}
<div id="dot-container">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
And we can add CSS variable to easily control the width of the dots by keeping the same configuration and the first/last circle overflowing:
#dot-container {
width: 30vw;
background: black;
height: 8vw;
justify-content: center;
align-items: center;
display: flex;
margin:10px;
}
.dot {
border-radius: 100%;
width: calc(100%/var(--d));
margin: 0 calc((100%/6 - 100%/var(--d))/2);
background: green;
flex-shrink:0; /* Don't shrink*/
}
/* To keep the square ratio instead of setting height*/
.dot:before {
content:"";
display:block;
padding-top:100%;
}
<div id="dot-container" style="--d:10">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div id="dot-container" style="--d:8">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div id="dot-container" style="--d:20">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
If you will add/remove dots simply adjust the value 6
which is the number of dots minus one:
#dot-container {
width: 30vw;
background: black;
height: 8vw;
justify-content: center;
align-items: center;
display: flex;
margin:10px;
}
.dot {
border-radius: 100%;
width: calc(100%/var(--d));
margin: 0 calc((100%/(var(--n) - 1) - 100%/var(--d))/2);
background: green;
flex-shrink:0; /* Don't shrink*/
}
/* To keep the square ratio*/
.dot:before {
content:"";
display:block;
padding-top:100%;
}
<div id="dot-container" style="--d:10;--n:5">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div id="dot-container" style="--d:8;--n:7">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div id="dot-container" style="--d:20;--n:9">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
As a side note, the left margin of the first element and the right margin of the last element doesn't need to be equal to the calculated value since they overflowing. They simply need to the be the same value even 0
:
Equal to 0
:
#dot-container {
width: 30vw;
background: black;
height: 8vw;
justify-content: center;
align-items: center;
display: flex;
margin:10px;
}
.dot {
border-radius: 100%;
width: calc(100%/var(--d));
margin: 0 calc((100%/(var(--n) - 1) - 100%/var(--d))/2);
background: green;
flex-shrink:0; /* Don't shrink*/
}
.dot:first-child {
margin-left:0;
}
.dot:last-child {
margin-right:0;
}
/* To keep the square ratio*/
.dot:before {
content:"";
display:block;
padding-top:100%;
}
<div id="dot-container" style="--d:10;--n:5">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div id="dot-container" style="--d:8;--n:7">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div id="dot-container" style="--d:20;--n:9">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
Equal to a random value:
#dot-container {
width: 30vw;
background: black;
height: 8vw;
justify-content: center;
align-items: center;
display: flex;
margin:10px;
}
.dot {
border-radius: 100%;
width: calc(100%/var(--d));
margin: 0 calc((100%/(var(--n) - 1) - 100%/var(--d))/2);
background: green;
flex-shrink:0; /* Don't shrink*/
}
.dot:first-child {
margin-left:658624px;
}
.dot:last-child {
margin-right:658624px;
}
/* To keep the square ratio*/
.dot:before {
content:"";
display:block;
padding-top:100%;
}
<div id="dot-container" style="--d:10;--n:5">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div id="dot-container" style="--d:8;--n:7">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div id="dot-container" style="--d:20;--n:9">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
Upvotes: 1
Reputation: 42352
If possible, you can try multiple backgrounds instead of flexboxes. The idea is to use a radial gradient for the circles and a linear gradient for the background - see the demo below:
div{
width: 30vw;
height: 8vw;
margin: 10px;
background: radial-gradient(circle, green calc(1vw - 2px) calc(1vw - 1px), transparent 1vw) center / calc(100% / var(--n)) 2vw repeat-x,
linear-gradient(black, black) center / calc(100% - 100% / var(--n)) 100% no-repeat;
}
<div style="--n:5"></div>
<div style="--n:9"></div>
Now you can have a fixed width for the black background by changing the width of the div
based on the number of circles - see demo below with a red background to show the actual boundaries:
div {
height: 8vw;
margin: 10px calc(-15vw / var(--n));
position: relative;
width: calc(30vw + 30vw / var(--n));
background: radial-gradient(circle, green calc(1vw - 2px) calc(1vw - 1px), transparent 1vw) 0 50% / calc(30vw / var(--n)) 2vw repeat-x,
linear-gradient(black, black) center / calc(100% - 30vw / var(--n)) 100% no-repeat, red;
}
<div style="--n:3"></div>
<div style="--n:5"></div>
<div style="--n:9"></div>
Finish it up using a pseudo element to apply the background and having the width specified on the div
for generality - final result below:
div {
--w: 30vw;
height: 8vw;
width: var(--w);
margin: 10px;
position: relative;
}
div:after {
content: '';
position: absolute;
height: 100%;
width: calc(100% + 100% / var(--n));
margin: 0 calc(-1 * var(--w) / var(--n) / 2);
background: radial-gradient(circle, green calc(1vw - 2px) calc(1vw - 1px), transparent 1vw) 0 50% / calc(var(--w) / var(--n)) 2vw repeat-x,
linear-gradient(black, black) center / calc(100% - var(--w) / var(--n)) 100% no-repeat;
}
<div style="--n:3"></div>
<div style="--n:7"></div>
<div style="--n:9"></div>
Upvotes: 2
Reputation: 58
You might go for a pseudo element that has the black background. Increase the width of your container a bit so the dots can spread out 1vw more. With justify-content: space-between you don't need the margin on the dots. The dots have position relative so they display on top of the black background.
#dot-container {
position: absolute;
width: 32vw;
height: 8vw;
justify-content: space-between;
align-items: center;
display: flex;
}
#dot-container:before {
content: '';
display: block;
position: absolute;
width: 30vw;
height: 8vw;
margin: 0 1vw;
background: black;
}
.dot {
border-radius: 100%;
width: 2vw;
height: 2vw;
background: green;
position: relative;
}
Upvotes: 0
Reputation: 14413
This can be done using justify-content: space-between
and using a negative margin
.
#dot-container {
position: absolute;
width: 30vw;
background: black;
height: 8vw;
justify-content: space-between;
align-items: center;
display: flex;
}
.dot {
border-radius: 100%;
width: 2vw;
height: 2vw;
margin: -3.2%; /*(30-2*7) / (7-2)*/
background: green;
}
<div id="dot-container">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
Or, if you do not want to calculate margins you can add a child element with absolute positioning, and change number of div.dot
elements like you wish:
#dot-container {
position: relative;
width: 30vw;
height: 6vw;
justify-content: space-between;
align-items: center;
display: flex;
}
#dot-container-inner {
position: absolute;
left: 3%;
top: 0;
z-index: -1;
height: 100%;
width: 95%;
background: black;
}
.dot {
border-radius: 100%;
width: 2vw;
height: 2vw;
background: green;
}
<div id="dot-container">
<div id="dot-container-inner">
</div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
Upvotes: 6