Why does using excerpt_more filter change link location?

Filters are for modifying values before they are output. Typically the function is passed some value where you can modify it or overwrite it, then pass the result back. Your link is appearing out of place because you’re outputting the value directly, change it to return instead.

Also note that most template tags have versions that output their value, and ones that return. In your function the_permalink is changed to get_permalink.

add_filter( 'excerpt_more', 'edit_more_link', 11 );
function edit_more_link() {
    return '<a class="read-more" href="' . get_permalink() . '?template=iframe">read more &raquo;</a>';
}