Search code examples
javascripthtmlcsscss-floatcentering

How to wrap elements around a central image


I have a container that has an image that needs to be centered and multiple buttons that should wrap around the container.

Floating left or right gives the correct behavior but the goal would be to have it float center horizontally and vertically in the middle. I've included a picture of the desired result

Desired Result


Solution

  • The dynamic generation of items makes the whole logic and approach much more complicated and brings a lot of caveats. This is a very non-trival task with many questions and edge cases.

    See the code below.

    Important: see the snippet below in full-page view mode.

    However, there are a few limitations and things to mention:

    1. Width of the top and side items cannot be the same because the top item width depends on the total number of items. If you need them to be equal, you will have to calculate everything manually in JS.
    2. The logic below assumes that the number of items is even, i.e., it can be divided by 2 without a reminder. If you need to handle any number of items, you will need to adjust the logic to handle how to distribute uneven elements.
    3. Size and shape of the circle are hardcoded for now. From requirements, it is unclear how it should be calculated.
    4. Gaps between items are hardcoded because it is not clear what size of items should depend on and, therefore, how gaps should be calculated.

    Please let me know if this helps.

    const itemsCount = 16;
    
    // arbitrary selected value to allocate 30% of items for top and bottom
    const topCount = Math.round(itemsCount * 0.3);      
    const bottomCount = topCount;
    const vertCount = (itemsCount - topCount - bottomCount) / 2;
    
    const topCell = document.querySelector('.top').children[0];
    const leftCell = document.querySelector('.left').children[0];
    const rightCell = document.querySelector('.right').children[0];
    const bottomCell = document.querySelector('.bottom').children[0];
    
    const createCell = (index) => {
        const cell = document.createElement('div');
        cell.className = 'cell';
        cell.innerText = index + 1;
        return cell;
    };
    
    for (let index=0; index<itemsCount; index ++) {
        if (index < topCount) {
            topCell.appendChild(createCell(index));
        }
        if (index >= topCount && index < topCount + vertCount * 2) {
            if (index % 2 !== 0)
                leftCell.appendChild(createCell(index));
            else
                rightCell.appendChild(createCell(index));
        }
        if (index >= topCount + vertCount * 2) {
            bottomCell.appendChild(createCell(index));
        }
    }
    body {
        margin: 0px;
        padding: 0px;
        font-size: 18pt;
        font-family: Tahoma;
        color: white;
        background-color: #4472c4;
    }
    
    .top {
        grid-area: top;
        position: relative;
        margin-bottom: 40px;
    }
    
    .left {
        grid-area: left;
        position: relative;
    }
    
    .main {
        display: flex;
        grid-area: main;
        justify-content: center;
        align-items: center;
    }
    
    .circle {
        display: flex;
        width: 60vh;
        height: 60vh;
        border-radius: 50%;
        background-color: #ed7d31;
    }
    
    .right {
        grid-area: right;
        position: relative;
    }
    
    .bottom {
        grid-area: bottom;
        position: relative;
        margin-top: 40px;
    }
    
    .horiz {
        display: flex;
        flex-direction: row;
        justify-content: space-between;
        gap: 40px;
        position: absolute;
        width: 100%;
        height: 100%;
    }
    
    .vert {
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        gap: 40px;
        position: absolute;
        width: 100%;
        height: 100%;
    }
    
    .cell {
        display: flex;
        flex-grow: 1;
        background-color: #71ad47;
        justify-content: center;
        align-items: center;
    }
    
    .grid-container {
        display: grid;
        grid-template-areas:
            'top top top'
            'left main right'
            'bottom bottom bottom';
        grid-template-rows: 1fr 4fr 1fr;
        grid-template-columns: 1fr 5fr 1fr;
        width: 100vw;
        height: 100vh;
    }
    <html>
    <body>
        <div class="grid-container">
            <div class="top">
                <div class="horiz"></div>
            </div>
            <div class="left">
                <div class="vert"></div>
            </div>
            <div class="main">
                <div class="circle"></div>
            </div>
            <div class="right">
                <div class="vert"></div>
            </div>
            <div class="bottom">
                <div class="horiz"></div>
            </div>
        </div>
    </body>
    </html>