Tutorial

Elementor Flex Wrap Filler Placeholder

Uses Plugins

Elementor PRO

Description

When elements wrap on a Flex Container set to “flex-direction: row”, it leaves whitespace in the empty area. I cannot find any CSS property to fill the space with placeholder content, which I think would be useful. I decided to see if I could fill this gap with a JavaScript alternative. This video shows what I came up with. I hope you find it useful.

Steps

1

Basics

No steps. Just watch the video and use the code below if you want to.

Code (click to copy)

Code for the placeholder (javascript)

<script>
    ;((d,w) => {
        const placeholderContainerSelector = '.flex-placeholder';
        const placeHolderFillerClass = 'flex-placeholder-temp';
        const placeholderCollection = d.querySelectorAll(placeholderContainerSelector);

        //utils
        const getElementTotalStyleWidth = el => {
            const totalWidth = el.offsetWidth;
            const cs = getComputedStyle(el);
            const pl = parseFloat(cs.paddingLeft,);
            const pr = parseFloat(cs.paddingRight);
            const ml = parseFloat(cs.marginLeft);
            const mr = parseFloat(cs.marginRight);
            const bl = parseFloat(cs.borderLeftWidth);
            const br = parseFloat(cs.borderRightWidth);
            return pl + pr + ml + mr + bl + br;
        }

        const removeContainersPlaceholders = (collection) => {
            collection.querySelectorAll('.' + placeHolderFillerClass).forEach(el => {
                el.remove();
            })
        }

        const insertPlaceholder = (existingNode, width) => {
            let ph = d.createElement('div');
            ph.classList.add(placeHolderFillerClass);
            ph.style.width = width;
            existingNode.parentNode.insertBefore(ph, existingNode.nextSibling);
        }

        const updatePlaceholders = ()=>{
            placeholderCollection.forEach(collection => {
                const cs = getComputedStyle(collection);
                const colsGap = parseFloat(cs.columnGap);
                const children = collection.children;
                const totalWidth = collection.offsetWidth;
                const elWidth = getElementTotalStyleWidth(collection)

                const innerWidth = totalWidth - elWidth;

                removeContainersPlaceholders(collection);
                let currentCalculatedWidth = 0;
                let lastElement;
                Array.from(children).forEach((el, i) => {
                    lastElement = el; //used for the last placeholder
                    let width = el.offsetWidth;
                    let newWidth = currentCalculatedWidth + colsGap + width;

                    if (newWidth > innerWidth) {
                        insertPlaceholder( el.previousSibling, innerWidth - currentCalculatedWidth + 'px')
                        newWidth = width + colsGap;
                    }
                    currentCalculatedWidth = newWidth;
                });
                //After last element
                if(currentCalculatedWidth < innerWidth){
                    insertPlaceholder( lastElement, innerWidth - currentCalculatedWidth + 'px')
                }
            })
        }
        //Init
        w.addEventListener('resize', updatePlaceholders);
        updatePlaceholders();
    })(document,window)
</script>
<style>
    /* Dot patern default. Override with Custom CSS on Container*/
    .flex-placeholder-temp {
      background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+CiAgPHJlY3Qgd2lkdGg9JzEwJyBoZWlnaHQ9JzEwJyBmaWxsPScjZmZmJyAvPgogIDxjaXJjbGUgY3g9IjEiIGN5PSIxIiByPSIxIiBmaWxsPSIjMDAwIi8+Cjwvc3ZnPg==");
      background-repeat: repeat;
    }

</style>