Reputation: 1550
There has been a similar task recently and I tried to solve it by Javascript but couldn't. So I need your help.
The idea is this: it's like beads on a lace but the left and the right beads have blue lines only on one side. Also the last square. The structure should be responsive, that's why I have used flex.
The blue lines are spans with a background color, but could be also borders if you like. By the Javascript I move them to the left when I need to hide them. If you put a border to those divs .container > div
, you'll get my idea.
I thought my Javacsript should work but actually it works only partly. Where am I wrong? Thank you.
const moveBackgrounds = () => {
const divs = document.querySelectorAll('.container div');
const getY = (elem) => {
const elemRect = elem.getBoundingClientRect();
return elemRect.top + window.scrollY;
}
let countPerLine = 0; //count of divs per line
let firstDivY = getY(divs[0]);
divs.forEach(div => {
if (getY(div) === firstDivY ) {
countPerLine++
}
});
//positioning the blue divs:
divs.forEach((div, index) => {
if ((index+1) % countPerLine !== 0) {
const spanBg = div.querySelector('.bg');
spanBg.style.left = 0 + 'px';
}
else {
const spanBg = div.querySelector('.bg');
const left = spanBg.style.left;
spanBg.style.left = left - 20 + 'px';
}
});
//move the background of the last div:
const spanBg = divs[divs.length - 1].querySelector('.bg');
console.log(spanBg);
const left = spanBg.style.left;
spanBg.style.left = left - 20 + 'px';
}
window.addEventListener("resize", moveBackgrounds);
window.addEventListener("load", moveBackgrounds);
.wrapper {
text-align:center
}
.container {
display: flex;
flex-wrap: wrap;
width: 40%;
margin: 20px auto;
}
.container > div {
width: 70px;
height:70px;
position:relative
}
.container > div .icon {
display:inline-block;
width: 50px;
height: 50px;
background-color: grey;
position: absolute;
left:0;
top: 50%;
transform:translate(0,-50%);
z-index:2
}
.container .bg{
display: block;
width: 70px;
height:2px;
background-color: blue;
position:absolute;
z-index:1;
top: 50%;
left:0;
transform:translateY(-50%)
}
<div class="wrapper">
<div class="container">
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
</div>
</div>
Upvotes: 0
Views: 161
Reputation: 82976
This effect can be achieved entirely in CSS. To do so, the blue lines are created as the border or background of a space character, and makes use of the fact that spaces at the end of lines are dropped.
.container > div {
display: inline;
}
.container > div .icon {
display: inline-block;
width: 50px;
height: 50px;
background-color: grey;
}
.container .bg::before {
content: ' ';
letter-spacing: 20px; /* adjust this to control the blue line length */
font-size: 25px;
border-bottom: 2px solid blue;
vertical-align: top;
}
/* Just for demonstrating the responsiveness */
.container {
border: 1px solid;
animation: 10s linear 1s infinite alternate setWidth;
}
@keyframes setWidth { from { width: 100%; } to { width: 30%; } }
<div class="wrapper">
<div class="container">
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
</div>
</div>
Upvotes: 1
Reputation: 36426
The problem lies with the calculation of the moving of a blue line element.
Notice that on first load the layout looks fine - the right hand blue line is not there - but on a resize of the window they come back.
Here's what's happening. This line
const left = spanBg.style.left;
picks up the style, which at the start is empty as it hasn't been set. However, once it has been set (either to 0px or -20px) then that's the string that is returned. Notice it is not a number, it has px at the end. Then you try to take away 20 and add a px string. This isn't recognised so the style.left stays as it was - either 0px or 20px.
This snippet sets the blue lines to display: none if they are on the end rather than trying to hide them by moving them. It also has to then set them back to display: block when they are not to be removed (just in case they'd been set to none the last time).
const moveBackgrounds = () => {
const divs = document.querySelectorAll('.container div');
const getY = (elem) => {
const elemRect = elem.getBoundingClientRect();
return elemRect.top + window.scrollY;
}
let countPerLine = 0; //count of divs per line
let firstDivY = getY(divs[0]);
divs.forEach(div => {
if (getY(div) === firstDivY) {
countPerLine++
}
});
//positioning the blue divs:
divs.forEach((div, index) => {
if ((index + 1) % countPerLine !== 0) {
const spanBg = div.querySelector('.bg');
spanBg.style.display = 'block';
} else {
const spanBg = div.querySelector('.bg');
spanBg.style.display = 'none';
}
});
//move the background of the last div:
const spanBg = divs[divs.length - 1].querySelector('.bg');
//console.log(spanBg);
const left = spanBg.style.left;
//spanBg.style.left = left - 20 + 'px';
spanBg.style.display = 'none';
}
window.addEventListener("resize", moveBackgrounds);
window.addEventListener("load", moveBackgrounds);
.wrapper {
text-align: center
}
.container {
display: flex;
flex-wrap: wrap;
width: 40%;
margin: 20px auto;
}
.container>div {
width: 70px;
height: 70px;
position: relative
}
.container>div .icon {
display: inline-block;
width: 50px;
height: 50px;
background-color: grey;
position: absolute;
left: 0;
top: 50%;
transform: translate(0, -50%);
z-index: 2
}
.container .bg {
display: block;
width: 70px;
height: 2px;
background-color: blue;
position: absolute;
z-index: 1;
top: 50%;
left: 0;
transform: translateY(-50%)
}
<div class="wrapper">
<div class="container">
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
<div><span class="icon"></span><span class="bg"></span></div>
</div>
</div>
Upvotes: 1
Reputation: 378
As far as I can see you will get what you want by using:
spanBg.style.display = 'none'
for the last element in the divs list.
If I'm wrong, let me know.
Image added so you can see the result.
Upvotes: 1