I'm trying to create a triangular grid with HTML and CSS which involves offsetting each successive triangle in the grid to the left by larger and larger amounts so that each triangle fits neatly next to the previous one. Since the amount that each triangle needs to move is based on it's index in the parent container, I'm currently using JS to set this offset. I'm looking for a way to do this with pure CSS. Using JS like this feels like a hack and I'm wondering if I'm missing something in CSS that would let me access each triangle div's index or perhaps there's another way altogether in CSS to achieve what I'm doing.
let triangleRows = [...document.getElementsByClassName('triangle-row')]
triangleRows.forEach(row => {
let children = [...row.children]
// set each triangle's --tri-index variable to its index
children.forEach((tri, idx) => tri.style.setProperty('--tri-index', idx))
})
:root {
--tri-width: 5rem;
--tri-ratio: 0.86603;
--offset: -2.25rem
}
.triangle-row {
display: flex;
margin-top: 0.2rem;
}
.triangle {
position: relative;
height: calc(var(--tri-width) * var(--tri-ratio));
width: var(--tri-width);
left: calc(var(--offset) * var(--tri-index));
background-color: red;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}
.triangle:hover {
background-color: yellow;
}
.flipped {
clip-path: polygon(0% 0%, 50% 100%, 100% 0%);
}
<div class="triangle-row">
<div class="triangle"></div>
<div class="triangle flipped"></div>
<div class="triangle"></div>
<div class="triangle flipped"></div>
<div class="triangle"></div>
</div>
<div class="triangle-row">
<div class="triangle flipped"></div>
<div class="triangle"></div>
<div class="triangle flipped"></div>
<div class="triangle"></div>
<div class="triangle flipped"></div>
</div>
I created the same result with a negative margin. So the triangles don't have to move an increasing space to the left.
:root {
--tri-width: 5rem;
--tri-ratio: 0.86603;
--offset: -2.25rem
}
.triangle-row {
display: flex;
margin-top: 0.2rem;
}
.triangle {
position: relative;
height: calc(var(--tri-width) * var(--tri-ratio));
width: var(--tri-width);
margin-left: var(--offset); /* add the offset */
background-color: red;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}
.triangle:first-child{
margin-left: 0;
}
.triangle:hover {
background-color: yellow;
}
.flipped {
clip-path: polygon(0% 0%, 50% 100%, 100% 0%);
}
<div class="triangle-row">
<div class="triangle"></div>
<div class="triangle flipped"></div>
<div class="triangle"></div>
<div class="triangle flipped"></div>
<div class="triangle"></div>
</div>
<div class="triangle-row">
<div class="triangle flipped"></div>
<div class="triangle"></div>
<div class="triangle flipped"></div>
<div class="triangle"></div>
<div class="triangle flipped"></div>
</div>
Edit: I implemented the input from @Bryce Howitson and removed the alternation of the classes flipped. The CSS is now a bit complex, but it is now easy to include more triangles or more lines of triangles.
:root {
--tri-width: 5rem;
--tri-ratio: 0.86603;
--offset: -2.25rem
}
.triangle-row {
display: flex;
margin-top: 0.2rem;
}
.triangle {
position: relative;
height: calc(var(--tri-width) * var(--tri-ratio));
width: var(--tri-width);
margin-left: var(--offset); /* add the offset */
background-color: red;
}
.triangle:hover {
background-color: yellow;
}
.triangle:first-child {
margin-left: 0;
}
.triangle-row:nth-child(odd) .triangle:nth-child(odd),
.triangle-row:nth-child(even) .triangle:nth-child(even) {
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}
.triangle-row:nth-child(even) .triangle:nth-child(odd),
.triangle-row:nth-child(odd) .triangle:nth-child(even){
clip-path: polygon(0% 0%, 50% 100%, 100% 0%);
}
<div class="triangle-row">
<div class="triangle"></div>
<div class="triangle"></div>
<div class="triangle"></div>
<div class="triangle"></div>
<div class="triangle"></div>
</div>
<div class="triangle-row">
<div class="triangle"></div>
<div class="triangle"></div>
<div class="triangle"></div>
<div class="triangle"></div>
<div class="triangle"></div>
</div>