InnerBlocks breaks Flexbox and CSS Grid styles

You can eliminate the wrapping containers abandoning InnerBlocks and instead using the useInnerBlocksProps hook which is how the blocks that come with core do it. This will allow your block markup to match the frontend without the editor wrapping things in additional tags.

If we look at the official buttons block:

import {
    BlockControls,
    useBlockProps,
    __experimentalUseInnerBlocksProps as useInnerBlocksProps,
    JustifyContentControl,
} from '@wordpress/block-editor';
...

function ButtonsEdit( {
    attributes: { contentJustification, orientation },
    setAttributes,
} ) {
    const blockProps = useBlockProps( {
        className: classnames( {
            [ `is-content-justification-${ contentJustification }` ]: contentJustification,
            'is-vertical': orientation === 'vertical',
        } ),
    } );
    const innerBlocksProps = useInnerBlocksProps( blockProps, {
        allowedBlocks: ALLOWED_BLOCKS,
        template: BUTTONS_TEMPLATE,
        orientation,
        __experimentalLayout: LAYOUT,
        templateInsertUpdatesSelection: true,
    } );
...
    return (
        <>
...
            <div { ...innerBlocksProps } />
        </>
    );
}

https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/buttons/edit.js

The blocks edit component eliminates the tags that surround the buttons block using useBlockProps, then passes the result to useInnerBlocksProps to do the same for its children. It also passes the parameters that it would have given to the InnerBlocks component as a second parameter.

This way it has full control over the markup of the block while still giving the editor the opportunity to add event handlers and other things.

Not that to use this, you must declare you use the v2 API when registering the block. If you don’t then useBlockProps won’t work

"apiVersion": 2,

A more minimal example:

import {
    useBlockProps,
    __experimentalUseInnerBlocksProps as useInnerBlocksProps,
} from '@wordpress/block-editor';

const Edit = ( props ) => {
    const blockProps = useBlockProps( {} );
    const innerBlocksProps = useInnerBlocksProps( blockProps, {} );
    return <div { ...innerBlocksProps } />;
};

This also has the benefit of avoiding a common bug in block validation where the innerblocks component shares a tag with another element, and the whitespace generation causes validation to fail, which isn’t possible here