Get custom field value from Grandparent Page for Parent and Child Pages

As far as I’m aware there’s no limit to how many levels of ancestry Pages can have, so any solution should not depend on specifically referencing a particular ancestor. The best solution would be to get a list of all ancestors for the page and loop over them until you find a value for your field. Then stop looping over them and return the found value. The function get_post_ancestors() can be used for this:

$colour = null;

/**
 * Get the IDs of the page's ancestors into a list.
 */
$page_ids = get_post_ancestors( $post );

/**
 * Put the current page's ID at the beginning of the list so we don't have to 
 * handle it separately.
 */
array_unshift( $page_ids, $post->ID );

/**
 * Loop over pages and find the first one with a colour.
 */
foreach ( $page_ids as $page_id ) {
    $maybe_colour = get_post_meta( 'colour', $page_id, true );

    /**
     * If the page has a value for colour, put it in the colour variable and 
     * stop the loop.
     */
    if ( $maybe_colour ) {
        $colour = $maybe_colour;
        break;
    }
}

echo $colour;

To save space in your template you could add this to a function and use the function in your template instead:

function wpse_310439_get_the_colour( $post = 0 ) {
    $post = get_post( $post );

    $page_ids = get_post_ancestors( $post );

    array_unshift( $page_ids, $post->ID );

    $colour = null;

    foreach ( $page_ids as $page_id ) {
        $maybe_colour = get_post_meta( 'colour', $page_id, true );

        if ( $maybe_colour ) {
            $colour = $maybe_colour;
            break;
        }
    }

    return $colour;
}

Then in your template:

<div class="<?php echo esc_attr( wpse_310439_get_the_colour() ); ?>">