The "right" answer
No. Wrapped flex items are spread on single (main) axis only. There is no automated mechanism to tell wrapped item that it's sibling on secondary axis in previous or following run (row above or below) overlaps some boundary and so should affect items in different row. Since your design involves overlaps on both axes, there is no way to define items' dimensions / transforms and let flex-box layout alone do the maths to produce desired balanced distribution.
Technically correct answer
Yes. But only with precisely "hand-crafted" styles.
As stated above, you would have to manually set extra properties to all "off-grid" overlaps on secondary axis. That means for secondary that each "expanded" item in one row must have manually "condensed" counterpart in adjacent row. Naturally, this could work only when wrapping occurs precisely as designed.
Let's have a look at simplified design sample:
aaaaaaa..b..cccc
aaaaaaa..b..cccc
aaaaaaa..b..cccc
............cccc
dddd..eeee..cccc
......eeee......
gggg..eeee..ffff
gggg............
gggg..h..iiiiiii
gggg..h..iiiiiii
gggg..h..iiiiiii
a
and i
areas are expanded horizontally at the expenses of areas h
and b
. Same applies to c
-f
and d
-g
pairs, just vertically. As we can see, overlaps happens on both axes. Let's say we need each of the four overlaps to have unique size.
POC with use of custom properties for setting width/height "overlap" and corresponding secondary axis (vertical) adjustments could be:
section {
--base: 9em; /* width & height */
--add: calc(var(--base) / 8); /* "unit" for overlap adjustments */
--gap: calc(var(--base) / 20);
--cols: 3; /* example HTML works with 3 only */
--dim: calc( ( var(--cols) * var(--base) ) + ( ( var(--cols) - 1 ) * var(--gap) ) );
width: var(--dim);
height: var(--dim);
gap: var(--gap);
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
article {
width: calc( var(--base) + ( var(--add) * var(--wdt, 0) ) );
margin-bottom: calc( var(--add) * var(--hgh,0) * -1 ); /* expanded items will "pull" next row back */
position: relative;
top: calc( var(--add) * var(--top,0) * 1 );
height: calc( var(--base) + ( var(--add) * var(--hgh,0) ) );
}
/*
Illustrative
*/
section {
outline: #F0F6 solid; outline-offset: -2px;
}
article {
outline: #0FF6 solid; outline-offset: -2px;
background-color: rgba(0,0,0,0.2);
align-items: center;
display: flex;
justify-content: center;
flex-direction: column;
counter-increment: a;
word-break: break-word;
text-align: center;
}
article::before { content: counter(a, lower-alpha); }
article::after { content: attr(style); }
:root { background: dimgray; color: snow; }
:link { color: aqua; } :visited { color: lime; }
<section>
<article style="--wdt: +1;"></article>
<article style="--wdt: -1;"></article>
<article style="--hgh: +2;"></article>
<article style="--hgh: -4"></article>
<article style="/* defaults */"></article>
<article style="--hgh: -2; --top: +2"></article>
<article style="--hgh: +4; --top: -4;"></article>
<article style="--wdt: -3;"></article>
<article style="--wdt: +3;"></article>
</section>
This have quite nice flexibility to set any value as overlap.
"Use grid" they say
Grid layout for our just fairly complex sample design with "3 × 3" base would involve at least 5 × 5 grid definition:
section {
grid-template:
"a a b b c" 60fr
"d e e e c" 10fr
"d e e e f" 20fr
"g e e e f" 30fr
"g h h i i" 60fr
/60fr
05fr
20fr
35fr
60fr;
--base: 9em; /* item width & height */
--gap: calc(var(--base) / 20);
--cols: 3; /* example HTML works with 3 only */
--dim: calc( ( var(--cols) * var(--base) ) + ( ( var(--cols) - 1 ) * var(--gap) ) );
width: var(--dim);
height: var(--dim);
gap: var(--gap);
outline: #F0F6 solid; outline-offset: -2px;
display: grid;
}
/*
Illustrative
*/
article {
outline: #0FF6 solid;
outline-offset: -2px;
background-color: rgba(0,0,0,.3);
align-items: center;
display: flex;
justify-content: center;
flex-direction: column;
counter-increment: a;
word-break: break-word;
text-align: center;
}
article::before {
content: counter(a, lower-alpha);
}
article::after {
content: attr(style);
}
:root { background: dimgray; color: snow; }
:link { color: aqua; } :visited { color: lime; }
<section class="grid">
<article style="grid-area: a"></article>
<article style="grid-area: b"></article>
<article style="grid-area: c;"></article>
<article style="grid-area: d;"></article>
<article style="grid-area: e;"></article>
<article style="grid-area: f;"></article>
<article style="grid-area: g;"></article>
<article style="grid-area: h;"></article>
<article style="grid-area: i;"></article>
</section>
Disadvantage of this approach is that each instance of ovelap on column-row pair demands extra column-row definition. Concrete design from the question (5 × 5) would need at least 19 × 17 grid definition.
Please note that both POC's are synthetic and involves quite modern gap
for flex-box. Real-world usage would most probably be more complicated that this.
Elegant grid approach
Simple rigid grid and irregular adjustments done with only margins.
This approach is taken from other answer of this question, all kudos there.
I didn't know that margin
of grid items could do that; adding example just for completeness. Using logic similar to the first flex-box example:
section {
--base: 9em; /* item width & height */
--add: calc(var(--base) / 8); /* "unit" for overlap adjustments */
--gap: calc(var(--base) / 20);
--cols: 3; /* example HTML works with 3 only */
--dim: calc( ( var(--cols) * var(--base) ) + ( ( var(--cols) - 1 ) * var(--gap) ) );
width: var(--dim);
height: var(--dim);
gap: var(--gap);
display: grid;
grid-auto-rows: 1fr;
grid-template-columns: repeat(var(--cols), 1fr);
}
article {
margin-top: calc( var(--top,0) * var(--add) * -1 );
margin-right: calc( var(--right,0) * var(--add) * -1 );
margin-bottom: calc( var(--bottom,0) * var(--add) * -1 );
margin-left: calc( var(--left,0) * var(--add) * -1 );
}
/*
Illustrative
*/
section {
outline: #F0F6 solid; outline-offset: -2px;
}
article {
outline: #0FF6 solid;
outline-offset: -2px;
background-color: rgba(0,0,0,.3);
align-items: center;
display: flex;
justify-content: center;
flex-direction: column;
counter-increment: a;
word-break: break-word;
text-align: center;
}
article::before {
content: counter(a, lower-alpha);
}
article::after {
content: attr(style);
}
:root { background: dimgray; color: snow; }
:link { color: aqua; } :visited { color: lime; }
<section>
<article style="--right: +1;"></article>
<article style="--left: -1;"></article>
<article style="--bottom: +2;"></article>
<article style="--bottom: -4"></article>
<article style="/* default */"></article>
<article style="--top: -2"></article>
<article style="--top: +4;"></article>
<article style="--right: -3;"></article>
<article style="--left: +3;"></article>
</section>
I see this as the most elegant and versatile way and nice leveraging of rigid grid for design. Manual "number lifting" would be still daunting - especially when need arises to shift "rest" of the row or even worse whole 'table' - but even so it seems as the most intuitive. Again, kudos to Laaouatni Anas for bringing it here.
Pragmatic old-school approach: "abspos"
For really wild rigid irregular design consider absolute positioning. Shown flex-box and first grid approach might make sense for usage when there are some regularities that could be accommodated in code patterns. Otherwise it might be equally viable approach to either use simple absolute positioning and manual dimensions for everything or similar approach with second grid. Sounds terrible - repositioning items further down or right would be pain - but I would not be surprised if would prove as the best solution for this particular task.