diff --git a/core/includes/common.inc b/core/includes/common.inc
index e57821e..e7e2a70 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1653,26 +1653,6 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
         $setting['ajaxPageState']['theme_token'] = \Drupal::csrfToken()->get($theme_key);
       }
 
-      // Provide the page with information about the individual JavaScript files
-      // used, information not otherwise available when aggregation is enabled.
-      $setting['ajaxPageState']['js'] = array_fill_keys(array_keys($javascript), 1);
-      unset($setting['ajaxPageState']['js']['settings']);
-
-      // Provide the page with information about the individual CSS files used,
-      // information not otherwise available when CSS aggregation is enabled.
-      // The setting is attached later in this function, but is set here, so
-      // that CSS files removed in drupal_process_attached() are still
-      // considered "used" and prevented from being added in a later AJAX
-      // request.
-      // Skip if no files were added to the page otherwise jQuery.extend() will
-      // overwrite the drupalSettings.ajaxPageState.css object with an empty
-      // array.
-      $css = _drupal_add_css();
-      if (!empty($css)) {
-        // Cast the array to an object to be on the safe side even if not empty.
-        $setting['ajaxPageState']['css'] = (object) array_fill_keys(array_keys($css), 1);
-      }
-
       _drupal_add_js($setting, 'setting');
 
       // If we're outputting the header scope, then this might be the final time
diff --git a/core/lib/Drupal/Core/Asset/CssCollectionRenderer.php b/core/lib/Drupal/Core/Asset/CssCollectionRenderer.php
index ab07555..db6ac69 100644
--- a/core/lib/Drupal/Core/Asset/CssCollectionRenderer.php
+++ b/core/lib/Drupal/Core/Asset/CssCollectionRenderer.php
@@ -94,6 +94,7 @@ public function render(array $css_assets) {
             $element['#attributes']['href'] = file_create_url($css_asset['data']) . $query_string_separator . $query_string;
             $element['#attributes']['media'] = $css_asset['media'];
             $element['#browsers'] = $css_asset['browsers'];
+            $element['#attributes']['data-css-files'] = $css_asset['data'];
             $elements[] = $element;
           }
           // The current page will run into IE's limits for CSS assets: work
@@ -107,12 +108,14 @@ public function render(array $css_assets) {
               $element['#attributes']['href'] = file_create_url($css_asset['data']) . $query_string_separator . $query_string;
               $element['#attributes']['media'] = $css_asset['media'];
               $element['#browsers'] = $css_asset['browsers'];
+              $element['#attributes']['data-css-files'] = $css_asset['data'];
               $elements[] = $element;
             }
             // The file CSS asset can be aggregated, but hasn't been: combine
             // multiple items into as few STYLE tags as possible.
             else {
               $import = array();
+              $files = array();
               // Start with the current CSS asset, iterate over subsequent CSS
               // assets and find which ones have the same 'type', 'group',
               // 'every_page', 'preprocess', 'media' and 'browsers' properties.
@@ -125,6 +128,7 @@ public function render(array $css_assets) {
                 // the @import statement, so we instead specify the media for
                 // the group on the STYLE tag.
                 $import[] = '@import url("' . String::checkPlain(file_create_url($next_css_asset['data']) . '?' . $query_string) . '");';
+                $files[] = $next_css_asset['data'];
                 // Move the outer for loop skip the next item, since we
                 // processed it here.
                 $i = $j;
@@ -152,6 +156,7 @@ public function render(array $css_assets) {
                 $element['#value'] = "\n" . implode("\n", $import_batch) . "\n";
                 $element['#attributes']['media'] = $css_asset['media'];
                 $element['#browsers'] = $css_asset['browsers'];
+                $element['#attributes']['data-css-files'] = implode(',', $files);
                 $elements[] = $element;
               }
             }
@@ -180,6 +185,7 @@ public function render(array $css_assets) {
           $element['#attributes']['href'] = $css_asset['data'];
           $element['#attributes']['media'] = $css_asset['media'];
           $element['#browsers'] = $css_asset['browsers'];
+          $element['#attributes']['data-css-files'] = $css_asset['data'];
           $elements[] = $element;
           break;
 
diff --git a/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php b/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php
index 807179f..c7f8a08 100644
--- a/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php
+++ b/core/lib/Drupal/Core/Asset/JsCollectionRenderer.php
@@ -87,10 +87,12 @@ public function render(array $js_assets) {
           if (!isset($js_asset['preprocessed'])) {
             $element['#attributes']['src'] .= $query_string_separator . ($js_asset['cache'] ? $query_string : REQUEST_TIME);
           }
+          $element['#attributes']['data-js-files'] = $js_asset['data'];
           break;
 
         case 'external':
           $element['#attributes']['src'] = $js_asset['data'];
+          $element['#attributes']['data-js-files'] = $js_asset['data'];
           break;
 
         default:
diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index 705d592..8c07a11 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -361,6 +361,17 @@
    * before field data is collected.
    */
   Drupal.ajax.prototype.beforeSerialize = function (element, options) {
+    // Helper function to split a list of filenames and add them to the proper
+    // ajax_page_state value.
+    function addFiles (type, files) {
+      if (files) {
+        files = files.split(',');
+        for (var i = 0, il = files.length; i < il; i += 1) {
+          options.data['ajax_page_state[' + type + '][' + files[i] + ']'] = 1;
+        }
+      }
+    }
+
     // Allow detaching behaviors to update field values before collecting them.
     // This is only needed when field values are added to the POST data, so only
     // when there is a form such that this.$form.ajaxSubmit() is used instead of
@@ -389,16 +400,17 @@
     var pageState = drupalSettings.ajaxPageState;
     options.data['ajax_page_state[theme]'] = pageState.theme;
     options.data['ajax_page_state[theme_token]'] = pageState.theme_token;
-    for (var cssFile in pageState.css) {
-      if (pageState.css.hasOwnProperty(cssFile)) {
-        options.data['ajax_page_state[css][' + cssFile + ']'] = 1;
-      }
-    }
     for (var jsFile in pageState.js) {
       if (pageState.js.hasOwnProperty(jsFile)) {
         options.data['ajax_page_state[js][' + jsFile + ']'] = 1;
       }
     }
+    $('[data-css-files]').each(function () {
+      addFiles('css', $(this).attr('data-css-files'));
+    });
+    $('[data-js-files]').each(function () {
+      addFiles('js', $(this).attr('data-js-files'));
+    });
   };
 
   /**
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index ab560b2..a878f4c 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -1951,12 +1951,6 @@ protected function getAjaxPageStatePostData() {
     if (isset($drupal_settings['ajaxPageState'])) {
       $post['ajax_page_state[theme]'] = $drupal_settings['ajaxPageState']['theme'];
       $post['ajax_page_state[theme_token]'] = $drupal_settings['ajaxPageState']['theme_token'];
-      foreach ($drupal_settings['ajaxPageState']['css'] as $key => $value) {
-        $post["ajax_page_state[css][$key]"] = 1;
-      }
-      foreach ($drupal_settings['ajaxPageState']['js'] as $key => $value) {
-        $post["ajax_page_state[js][$key]"] = 1;
-      }
     }
     return $post;
   }
diff --git a/core/modules/system/src/Tests/Ajax/FrameworkTest.php b/core/modules/system/src/Tests/Ajax/FrameworkTest.php
index 0928c2a..1342970 100644
--- a/core/modules/system/src/Tests/Ajax/FrameworkTest.php
+++ b/core/modules/system/src/Tests/Ajax/FrameworkTest.php
@@ -111,96 +111,6 @@ public function testAJAXRenderError() {
   }
 
   /**
-   * Tests that new JavaScript and CSS files are lazy-loaded on an AJAX request.
-   */
-  public function testLazyLoad() {
-    $expected = array(
-      'setting_name' => 'ajax_forms_test_lazy_load_form_submit',
-      'setting_value' => 'executed',
-      'css' => drupal_get_path('module', 'system') . '/css/system.admin.css',
-      'js' => drupal_get_path('module', 'system') . '/system.js',
-    );
-    // CSS files are stored by basename, see _drupal_add_css().
-    $expected_css_basename = drupal_basename($expected['css']);
-
-    // @todo D8: Add a drupal_css_defaults() helper function.
-    $expected_css_html = drupal_get_css(array($expected_css_basename => array(
-      'type' => 'file',
-      'group' => CSS_AGGREGATE_DEFAULT,
-      'weight' => 0,
-      'every_page' => FALSE,
-      'media' => 'all',
-      'preprocess' => TRUE,
-      'data' => $expected['css'],
-      'browsers' => array('IE' => TRUE, '!IE' => TRUE),
-    )), TRUE);
-    $expected_js_html = drupal_get_js('header', array($expected['js'] => drupal_js_defaults($expected['js'])), TRUE);
-
-    // Get the base page.
-    $this->drupalGet('ajax_forms_test_lazy_load_form');
-    $original_settings = $this->drupalGetSettings();
-    $original_css = $original_settings['ajaxPageState']['css'];
-    $original_js = $original_settings['ajaxPageState']['js'];
-
-    // Verify that the base page doesn't have the settings and files that are to
-    // be lazy loaded as part of the next requests.
-    $this->assertTrue(!isset($original_settings[$expected['setting_name']]), format_string('Page originally lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
-    $this->assertTrue(!isset($original_css[$expected['css']]), format_string('Page originally lacks the %css file, as expected.', array('%css' => $expected['css'])));
-    $this->assertTrue(!isset($original_js[$expected['js']]), format_string('Page originally lacks the %js file, as expected.', array('%js' => $expected['js'])));
-
-    // Submit the AJAX request without triggering files getting added.
-    $commands = $this->drupalPostAjaxForm(NULL, array('add_files' => FALSE), array('op' => t('Submit')));
-    $new_settings = $this->drupalGetSettings();
-    $new_css = $new_settings['ajaxPageState']['css'];
-    $new_js = $new_settings['ajaxPageState']['js'];
-
-    // Verify the setting was not added when not expected.
-    $this->assertTrue(!isset($new_settings[$expected['setting_name']]), format_string('Page still lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
-    $this->assertTrue(!isset($new_css[$expected['css']]), format_string('Page still lacks the %css file, as expected.', array('%css' => $expected['css'])));
-    $this->assertTrue(!isset($new_js[$expected['js']]), format_string('Page still lacks the %js file, as expected.', array('%js' => $expected['js'])));
-    // Verify a settings command does not add CSS or scripts to drupalSettings
-    // and no command inserts the corresponding tags on the page.
-    $found_settings_command = FALSE;
-    $found_markup_command = FALSE;
-    foreach ($commands as $command) {
-      if ($command['command'] == 'settings' && (array_key_exists('css', $command['settings']['ajaxPageState']) || array_key_exists('js', $command['settings']['ajaxPageState']))) {
-        $found_settings_command = TRUE;
-      }
-      if (isset($command['data']) && ($command['data'] == $expected_js_html || $command['data'] == $expected_css_html)) {
-        $found_markup_command = TRUE;
-      }
-    }
-    $this->assertFalse($found_settings_command, format_string('Page state still lacks the %css and %js files, as expected.', array('%css' => $expected['css'], '%js' => $expected['js'])));
-    $this->assertFalse($found_markup_command, format_string('Page still lacks the %css and %js files, as expected.', array('%css' => $expected['css'], '%js' => $expected['js'])));
-
-    // Submit the AJAX request and trigger adding files.
-    $commands = $this->drupalPostAjaxForm(NULL, array('add_files' => TRUE), array('op' => t('Submit')));
-    $new_settings = $this->drupalGetSettings();
-    $new_css = $new_settings['ajaxPageState']['css'];
-    $new_js = $new_settings['ajaxPageState']['js'];
-
-    // Verify the expected setting was added, both to drupalSettings, and as
-    // the first AJAX command.
-    $this->assertIdentical($new_settings[$expected['setting_name']], $expected['setting_value'], format_string('Page now has the %setting.', array('%setting' => $expected['setting_name'])));
-    $expected_command = new SettingsCommand(array($expected['setting_name'] => $expected['setting_value']), TRUE);
-    $this->assertCommand(array_slice($commands, 0, 1), $expected_command->render(), format_string('The settings command was first.'));
-
-    // Verify the expected CSS file was added, both to drupalSettings, and as
-    // the second AJAX command for inclusion into the HTML.
-    $this->assertEqual($new_css, $original_css + array($expected_css_basename => 1), format_string('Page state now has the %css file.', array('%css' => $expected['css'])));
-    $this->assertCommand(array_slice($commands, 1, 1), array('data' => $expected_css_html), format_string('Page now has the %css file.', array('%css' => $expected['css'])));
-
-    // Verify the expected JS file was added, both to drupalSettings, and as
-    // the third AJAX command for inclusion into the HTML. By testing for an
-    // exact HTML string containing the SCRIPT tag, we also ensure that
-    // unexpected JavaScript code, such as a jQuery.extend() that would
-    // potentially clobber rather than properly merge settings, didn't
-    // accidentally get added.
-    $this->assertEqual($new_js, $original_js + array($expected['js'] => 1), format_string('Page state now has the %js file.', array('%js' => $expected['js'])));
-    $this->assertCommand(array_slice($commands, 2, 1), array('data' => $expected_js_html), format_string('Page now has the %js file.', array('%js' => $expected['js'])));
-  }
-
-  /**
    * Tests that drupalSettings.currentPath is not updated on AJAX requests.
    */
   public function testCurrentPathChange() {
