diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php
index d047620..d6325ed 100644
--- src/wp-includes/class-wp-customize-manager.php
+++ src/wp-includes/class-wp-customize-manager.php
@@ -1353,6 +1353,7 @@ final class WP_Customize_Manager {
 
 		wp_enqueue_script( 'customize-preview' );
 		add_action( 'wp_head', array( $this, 'customize_preview_loading_style' ) );
+		add_action( 'wp_head', array( $this, 'remove_frameless_preview_messenger_channel' ) );
 		add_action( 'wp_footer', array( $this, 'customize_preview_settings' ), 20 );
 		add_filter( 'get_edit_post_link', '__return_empty_string' );
 
@@ -1488,6 +1489,44 @@ final class WP_Customize_Manager {
 	}
 
 	/**
+	 * Remove customize_messenger_channel query parameter from the preview window when it is not in an iframe.
+	 *
+	 * This ensures that the admin bar will be shown. It also ensures that link navigation will
+	 * work as expected since the parent frame is not being sent the URL to navigate to.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 */
+	public function remove_frameless_preview_messenger_channel( ){
+		if ( ! $this->messenger_channel ) {
+			return;
+		}
+		?>
+		<script>
+		( function() {
+			var urlParser, oldQueryParams, newQueryParams, i;
+			if ( parent !== window ) {
+				return;
+			}
+			urlParser = document.createElement( 'a' );
+			urlParser.href = location.href;
+			oldQueryParams = urlParser.search.substr( 1 ).split( /&/ );
+			newQueryParams = [];
+			for ( i = 0; i < oldQueryParams.length; i += 1 ) {
+				if ( ! /^customize_messenger_channel=/.test( oldQueryParams[ i ] ) ) {
+					newQueryParams.push( oldQueryParams[ i ] );
+				}
+			}
+			urlParser.search = newQueryParams.join( '&' );
+			if ( urlParser.search !== location.search ) {
+				location.replace( urlParser.href );
+			}
+		} )();
+		</script>
+		<?php
+	}
+
+	/**
 	 * Print JavaScript settings for preview frame.
 	 *
 	 * @since 3.4.0
diff --git src/wp-includes/js/customize-preview.js src/wp-includes/js/customize-preview.js
index 9a3944f..7a37ba5 100644
--- src/wp-includes/js/customize-preview.js
+++ src/wp-includes/js/customize-preview.js
@@ -106,18 +106,18 @@
 			preview.add( 'scheme', urlParser.protocol.replace( /:$/, '' ) );
 
 			preview.body = $( document.body );
-
-			preview.body.on( 'click.preview', 'a', function( event ) {
-				preview.handleLinkClick( event );
-			} );
-
-			preview.body.on( 'submit.preview', 'form', function( event ) {
-				preview.handleFormSubmit( event );
-			} );
-
 			preview.window = $( window );
 
 			if ( api.settings.channel ) {
+
+				// If in an iframe, then intercept the link clicks and form submissions.
+				preview.body.on( 'click.preview', 'a', function( event ) {
+					preview.handleLinkClick( event );
+				} );
+				preview.body.on( 'submit.preview', 'form', function( event ) {
+					preview.handleFormSubmit( event );
+				} );
+
 				preview.window.on( 'scroll.preview', debounce( function() {
 					preview.send( 'scroll', preview.window.scrollTop() );
 				}, 200 ) );
@@ -158,11 +158,6 @@
 				return;
 			}
 
-			// If not in an iframe, then allow the link click to proceed normally since the state query params are added.
-			if ( ! api.settings.channel ) {
-				return;
-			}
-
 			// Prevent initiating navigating from click and instead rely on sending url message to pane.
 			event.preventDefault();
 
@@ -199,11 +194,6 @@
 				return;
 			}
 
-			// If not in an iframe, then allow the form submission to proceed normally with the state inputs injected.
-			if ( ! api.settings.channel ) {
-				return;
-			}
-
 			/*
 			 * If the default wasn't prevented already (in which case the form
 			 * submission is already being handled by JS), and if it has a GET
@@ -348,12 +338,16 @@
 		}
 
 		// Make sure links in preview use HTTPS if parent frame uses HTTPS.
-		if ( 'https' === api.preview.scheme.get() && 'http:' === element.protocol && -1 !== api.settings.url.allowedHosts.indexOf( element.host ) ) {
+		if ( api.settings.channel && 'https' === api.preview.scheme.get() && 'http:' === element.protocol && -1 !== api.settings.url.allowedHosts.indexOf( element.host ) ) {
 			element.protocol = 'https:';
 		}
 
 		if ( ! api.isLinkPreviewable( element ) ) {
-			$( element ).addClass( 'customize-unpreviewable' );
+
+			// Style link as unpreviewable only if previewing in iframe; if previewing on frontend, links will be allowed to work normally.
+			if ( api.settings.channel ) {
+				$( element ).addClass( 'customize-unpreviewable' );
+			}
 			return;
 		}
 		$( element ).removeClass( 'customize-unpreviewable' );
@@ -496,13 +490,17 @@
 		urlParser.href = form.action;
 
 		// Make sure forms in preview use HTTPS if parent frame uses HTTPS.
-		if ( 'https' === api.preview.scheme.get() && 'http:' === urlParser.protocol && -1 !== api.settings.url.allowedHosts.indexOf( urlParser.host ) ) {
+		if ( api.settings.channel && 'https' === api.preview.scheme.get() && 'http:' === urlParser.protocol && -1 !== api.settings.url.allowedHosts.indexOf( urlParser.host ) ) {
 			urlParser.protocol = 'https:';
 			form.action = urlParser.href;
 		}
 
 		if ( 'GET' !== form.method.toUpperCase() || ! api.isLinkPreviewable( urlParser ) ) {
-			$( form ).addClass( 'customize-unpreviewable' );
+
+			// Style form as unpreviewable only if previewing in iframe; if previewing on frontend, all forms will be allowed to work normally.
+			if ( api.settings.channel ) {
+				$( form ).addClass( 'customize-unpreviewable' );
+			}
 			return;
 		}
 		$( form ).removeClass( 'customize-unpreviewable' );
diff --git tests/phpunit/tests/customize/manager.php tests/phpunit/tests/customize/manager.php
index 54128f8..b138a35 100644
--- tests/phpunit/tests/customize/manager.php
+++ tests/phpunit/tests/customize/manager.php
@@ -460,6 +460,7 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
 		$this->assertEquals( $did_action_customize_preview_init + 1, did_action( 'customize_preview_init' ) );
 
 		$this->assertEquals( 10, has_action( 'wp_head', 'wp_no_robots' ) );
+		$this->assertEquals( 10, has_action( 'wp_head', array( $wp_customize, 'remove_frameless_preview_messenger_channel' ) ) );
 		$this->assertEquals( 10, has_filter( 'wp_headers', array( $wp_customize, 'filter_iframe_security_headers' ) ) );
 		$this->assertEquals( 10, has_filter( 'wp_redirect', array( $wp_customize, 'add_state_query_params' ) ) );
 		$this->assertTrue( wp_script_is( 'customize-preview', 'enqueued' ) );
