wp_list_pages shortcode jumps above previous content

That’s because your list is printed immediately.

wp_list_pages() has the echo parameter, which is true by default. Make it false like here:

<?php
function roofspan_product_childpages() {
    $list_p = array(
      'sort_column' => 'menu_order, post_title',
      'child_of' => '12',
      'title_li' => 'Products: ',
      'echo' => 0 // Note this
    );
    return wp_list_pages( $list_p );
}
add_shortcode( 'product_childpages', 'roofspan_product_childpages' );