diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index f1e08616d847bbc5f7d97e2d6b94fe0d5c6ec41a..337f38380146c4dff30d45d3c77ea23c745cc744 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -13,6 +13,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Extension\ExtensionNameLengthException;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\RenderWrapper;
 use Drupal\Core\Utility\ThemeRegistry;
 use Drupal\Core\Theme\ThemeSettings;
 use Drupal\Component\Utility\NestedArray;
@@ -2690,6 +2691,24 @@ function template_preprocess_html(&$variables) {
   if ($suggestions = theme_get_suggestions(arg(), 'html')) {
     $variables['theme_hook_suggestions'] = $suggestions;
   }
+
+  drupal_add_library('system', 'html5shiv', TRUE);
+  // Render page_top and page_bottom into top level variables.
+  $variables['page_top'] = isset($variables['page']['page_top']) ? drupal_render($variables['page']['page_top']) : '';
+  $variables['page_bottom'] = array();
+  $variables['page_bottom'][] = isset($variables['page']['page_bottom']) ? drupal_render($variables['page']['page_bottom']) : array();
+  // Add footer scripts as '#markup' so they can be rendered with other
+  // elements in page_bottom.
+  $footer_scripts = new RenderWrapper('drupal_get_js', array('footer'));
+  $variables['page_bottom'][] = array('#markup' => $footer_scripts);
+
+  // Wrap function calls in an object so they can be called when printed.
+  $variables['head'] = new RenderWrapper('drupal_get_html_head');
+  $variables['styles'] = new RenderWrapper('drupal_get_css');
+  $variables['scripts'] = new RenderWrapper('drupal_get_js');
+
+  // Place the rendered HTML for the page body into a top level variable.
+  $variables['page'] = drupal_render($variables['page']);
 }
 
 /**
@@ -2815,30 +2834,6 @@ function template_process_page(&$variables) {
   }
 }
 
-/**
- * Processes variables for html.html.twig.
- *
- * Perform final addition and modification of variables before passing into
- * the template. To customize these variables, call drupal_render() on elements
- * in $variables['page'] during THEME_preprocess_page().
- *
- * @see template_preprocess_html()
- */
-function template_process_html(&$variables) {
-  drupal_add_library('system', 'html5shiv', TRUE);
-  // Render page_top and page_bottom into top level variables.
-  $variables['page_top'] = isset($variables['page']['page_top']) ? drupal_render($variables['page']['page_top']) : '';
-  $variables['page_bottom'] = isset($variables['page']['page_bottom']) ? drupal_render($variables['page']['page_bottom']) : '';
-  // Place the rendered HTML for the page body into a top level variable.
-  $variables['page'] = $variables['page']['#children'];
-  $variables['page_bottom'] .= drupal_get_js('footer');
-
-  $variables['head']    = drupal_get_html_head();
-  $variables['css']     = drupal_add_css();
-  $variables['styles']  = drupal_get_css();
-  $variables['scripts'] = drupal_get_js();
-}
-
 /**
  * Generate an array of suggestions from path arguments.
  *
@@ -3012,28 +3007,18 @@ function template_preprocess_maintenance_page(&$variables) {
   if (isset($variables['db_is_active']) && !$variables['db_is_active']) {
     $variables['theme_hook_suggestion'] = 'maintenance_page__offline';
   }
-}
 
-/**
- * Theme process function for theme_maintenance_field().
- *
- * The variables array generated here is a mirror of template_process_html().
- * This processor will run its course when theme_maintenance_page() is invoked.
- *
- * @see maintenance-page.html.twig
- * @see template_process_html()
- */
-function template_process_maintenance_page(&$variables) {
   $variables['head'] = drupal_get_html_head();
 
   // While this code is used in the installer, the language module may not be
   // enabled yet (even maybe no database set up yet), but an RTL language
   // selected should result in RTL stylesheets loaded properly already.
-  $variables['css'] = $css = drupal_add_css();
+  $css = drupal_add_css();
   include_once DRUPAL_ROOT . '/core/modules/language/language.module';
-  $variables['styles'] = drupal_get_css($css);
-
-  $variables['scripts'] = drupal_get_js();
+  // Wrapping drupal_get_css() and drupal_get_js() in an object so they can
+  // be called when printed.
+  $variables['styles'] = new RenderWrapper('drupal_get_css', array($css));
+  $variables['scripts'] = new RenderWrapper('drupal_get_js');
 }
 
 /**
@@ -3059,17 +3044,6 @@ function template_preprocess_install_page(&$variables) {
   $variables['site_name'] = drupal_install_profile_distribution_name();
 }
 
-/**
- * Preprocess variables for install-page.html.twig.
- *
- * @see install-page.html.twig
- * @see template_process_html()
- *
- */
-function template_process_install_page(&$variables) {
-  template_process_maintenance_page($variables);
-}
-
 /**
  * Preprocess variables for region.tpl.php
  *
diff --git a/core/lib/Drupal/Core/Template/RenderWrapper.php b/core/lib/Drupal/Core/Template/RenderWrapper.php
new file mode 100644
index 0000000000000000000000000000000000000000..7d7770d89502125d564e6d7facdaf0aaed52cbb5
--- /dev/null
+++ b/core/lib/Drupal/Core/Template/RenderWrapper.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Template\RenderWrapper.
+ */
+
+namespace Drupal\Core\Template;
+
+/**
+ * A class that wraps functions to call them while printing in a template.
+ *
+ * To use, one may pass in the function name as a string followed by an array of
+ * arguments to the constructor.
+ * @code
+ * $variables['scripts'] = new RenderWrapper('drupal_get_js', array('footer'));
+ * @endcode
+ */
+class RenderWrapper {
+
+  /**
+   * Stores the callback function to be called when rendered.
+   *
+   * @var callable
+   */
+  public $callback;
+
+  /**
+   * Stores the callback's arguments.
+   *
+   * @var array
+   */
+  public $args = array();
+
+  /**
+   * Constructs a RenderWrapper object.
+   *
+   * @param string $callback
+   *   The callback function name.
+   * @param array $args
+   *   The arguments to pass to the callback function.
+   */
+  public function __construct($callback, array $args = array()) {
+    if (!is_callable($callback)) {
+      throw new \InvalidArgumentException('Callback passed to RenderWrapper is not callable.');
+    }
+    $this->callback = $callback;
+    $this->args = $args;
+  }
+
+  /**
+   * Implements the magic __toString() method.
+   */
+  public function __toString() {
+    return $this->render();
+  }
+
+  /**
+   * Returns a string provided by the callback function.
+   *
+   * @return string
+   *   The results of the callback function.
+   */
+  public function render() {
+    if (!empty($this->callback) && is_callable($this->callback)) {
+      return call_user_func_array($this->callback, $this->args);
+    }
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Common/RenderWrapperTest.php b/core/tests/Drupal/Tests/Core/Common/RenderWrapperTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1a1b5688f09139e3d4aa54b26b4aa27e7911742a
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Common/RenderWrapperTest.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Common\RenderWrapperTest.
+ */
+
+namespace Drupal\Tests\Core\Common;
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\Core\Template\RenderWrapper;
+
+/**
+ * Tests the \Drupal\Core\Template\RenderWrapper functionality.
+ */
+class RenderWrapperTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Render wrapper',
+      'description' => 'Tests the RenderWrapper class used for late rendering.',
+      'group' => 'Common',
+    );
+  }
+
+  /**
+   * Provides data for the RenderWrapper test.
+   *
+   * @return array
+   */
+  public function providerTestRenderWrapperData() {
+    return array(
+      array('ucwords', array('Amazingly few discotheques provide jukeboxes.'), 'Amazingly Few Discotheques Provide Jukeboxes.', 'Simple string manipulation callback.'),
+      array('phpversion', array(), phpversion(), 'Callback with no arguments.'),
+      array(array('Drupal\Component\Utility\String', 'checkPlain'), array('<script>'), '<script>', 'Namespaced callback.'),
+    );
+  }
+
+  /**
+   * Tests casting a RenderWrapper object to a string.
+   *
+   * @see \Drupal\Core\Template\RenderWrapper::__toString()
+   *
+   * @dataProvider providerTestRenderWrapperData
+   */
+  public function testDrupalRenderWrapper($callback, $arguments, $expected, $message) {
+    $this->assertSame($expected, (string) new RenderWrapper($callback, $arguments), $message);
+  }
+
+  /**
+   * Tests that an invalid callback throws an exception.
+   *
+   * @expectedException InvalidArgumentException
+   */
+  public function testInvalidCallback() {
+    new RenderWrapper(FALSE);
+  }
+
+}
diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme
index 1e4a6b8659234853d5a55bc2e2754b3484cf23bb..d3f6567bb686c87d7aaf0542cdf21df6e7a20fb2 100644
--- a/core/themes/seven/seven.theme
+++ b/core/themes/seven/seven.theme
@@ -144,6 +144,8 @@ function seven_tablesort_indicator($variables) {
 function seven_preprocess_install_page(&$variables) {
   drupal_add_js(drupal_get_path('theme', 'seven') . '/js/mobile.install.js');
   drupal_add_css(drupal_get_path('theme', 'seven') . '/install-page.css', array('group' => CSS_AGGREGATE_THEME));
+  $variables['styles'] = drupal_get_css();
+  $variables['scripts'] = drupal_get_js();
 }
 
 /**