diff --git a/core/modules/views/templates/views-view-grid.html.twig b/core/modules/views/templates/views-view-grid.html.twig
index a5a813c..494acd4 100644
--- a/core/modules/views/templates/views-view-grid.html.twig
+++ b/core/modules/views/templates/views-view-grid.html.twig
@@ -9,6 +9,10 @@
  * - view: The view object.
  * - rows: The rendered view results.
  * - options: The view plugin style options.
+ *   - row_class_default: A flag indicating whether default classes should be
+ *   used on rows.
+ *   - col_class_default: A flag indicating whether default classes should be
+ *   used on columns.
  * - items: A list of grid items. Each item contains a list of rows or columns.
  *   The order in what comes first (row or column) depends on which alignment
  *   type is chosen (horizontal or vertical).
@@ -22,15 +26,40 @@
  * @ingroup themeable
  */
 #}
+{%
+  set classes = [
+    'views-view-grid',
+    options.alignment,
+    'cols-' ~ options.columns,
+    'clearfix',
+  ]
+%}
 {% if title %}
   <h3>{{ title }}</h3>
 {% endif %}
-<div{{ attributes }}>
+<div{{ attributes.addClass(classes) }}>
 {% if options.alignment == 'horizontal' %}
   {% for row in items %}
-  <div{{ row.attributes }}>
+  {% if options.row_class_default %}
+    {%
+      set row_classes = [
+        'views-row',
+        'row-' ~ loop.index,
+        'clearfix',
+      ]
+    %}
+  {% endif %}
+  <div{{ row.attributes.addClass(row_classes) }}>
     {% for column in row.content %}
-    <div{{ column.attributes }}>
+    {% if options.col_class_default %}
+      {%
+        set col_classes = [
+          'views-col',
+          'col-' ~ loop.index,
+        ]
+      %}
+    {% endif %}
+    <div{{ column.attributes.addClass(col_classes) }}>
       {{ column.content }}
     </div>
     {% endfor %}
@@ -38,12 +67,29 @@
   {% endfor %}
 {% else %}
   {% for column in items %}
-  <div{{ column.attributes }}>
-    {% for row in column.content %}
-      <div{{ row.attributes }}>
-        {{ row.content }}
-      </div>
-    {% endfor %}
+    {% if options.col_class_default %}
+      {%
+        set col_classes = [
+          'views-col',
+          'col-' ~ loop.index,
+          'clearfix',
+        ]
+      %}
+    {% endif %}
+    <div{{ column.attributes.addClass(col_classes) }}>
+      {% for row in column.content %}
+        {% if options.row_class_default %}
+          {%
+            set row_classes = [
+              'views-row',
+              'row-' ~ loop.index,
+            ]
+          %}
+        {% endif %}
+        <div{{ row.attributes.addClass(row_classes) }}>
+          {{ row.content }}
+        </div>
+      {% endfor %}
     </div>
   {% endfor %}
 {% endif %}
diff --git a/core/modules/views/templates/views-view-summary-unformatted.html.twig b/core/modules/views/templates/views-view-summary-unformatted.html.twig
index 9120dd4..b0b0170 100644
--- a/core/modules/views/templates/views-view-summary-unformatted.html.twig
+++ b/core/modules/views/templates/views-view-summary-unformatted.html.twig
@@ -9,6 +9,7 @@
  *   - count: The number of items this summary item represents.
  *   - separator: A separator between each row.
  *   - attributes: HTML attributes for a row.
+ *   - active: A flag indicating whtether the row is active.
  * - options: Flags indicating how each row should be displayed. This contains:
  *   - count: A flag indicating whether the row's 'count' should be displayed.
  *   - inline: A flag indicating whether the item should be wrapped in an inline
@@ -24,6 +25,9 @@
   {% if row.separator -%}
     {{ row.separator }}
   {%- endif %}
+  {% if row.active %}
+    {% set row.attributes = row.attributes.addClass('active') %}
+  {% endif %}
   <a href="{{ row.url }}"{{ row.attributes }}>{{ row.link }}</a>
   {% if options.count %}
     ({{ row.count }})
diff --git a/core/modules/views/templates/views-view-summary.html.twig b/core/modules/views/templates/views-view-summary.html.twig
index 4d8ed8f..f7f0fcf 100644
--- a/core/modules/views/templates/views-view-summary.html.twig
+++ b/core/modules/views/templates/views-view-summary.html.twig
@@ -10,6 +10,7 @@
  *   - link: The summary link text.
  *   - count: The number of items under this grouping.
  *   - attributes: HTML attributes to apply to each row.
+ *   - active: A flag indicating whtether the row is active.
  * - options: Flags indicating how the summary should be displayed.
  *   This contains:
  *   - count: A flag indicating whether the count should be displayed.
@@ -22,7 +23,12 @@
 <div class="item-list">
   <ul class="views-summary">
   {% for row in rows %}
-    <li><a href="{{ row.url }}"{{ row.attributes }}>{{ row.link }}</a>
+    {%
+      set row_classes = [
+        row.active ? 'active',
+      ]
+    %}
+    <li><a href="{{ row.url }}"{{ row.attributes.addClass(row_classes) }}>{{ row.link }}</a>
       {% if options.count %}
         ({{ row.count }})
       {% endif %}
diff --git a/core/modules/views/templates/views-view-table.html.twig b/core/modules/views/templates/views-view-table.html.twig
index 6b0b26c..0cb77ed 100644
--- a/core/modules/views/templates/views-view-table.html.twig
+++ b/core/modules/views/templates/views-view-table.html.twig
@@ -11,6 +11,8 @@
  *   - attributes: Remaining HTML attributes for the element.
  *   - content: HTML classes to apply to each header cell, indexed by
  *   the header's key.
+ *   - default_classes: A flag indicating whether default classes should be
+ *   used.
  * - caption_needed: Is the caption tag needed.
  * - caption: The caption for this table.
  * - accessibility_description: Extended description for the table details.
@@ -20,13 +22,26 @@
  *   - columns: Row column items. Columns are keyed by column number.
  *     - attributes: HTML classes to apply to each column.
  *     - content: The column content.
+ *   - default_classes: A flag indicating whether default classes should be
+ *   used.
+ * - responsive: A flag indicating whether table is responsive.
+ * - sticky: A flag indicating whether table header is sticky.
  *
  * @see template_preprocess_views_view_table()
  *
  * @ingroup themeable
  */
 #}
-<table{{ attributes }}>
+{%
+  set classes = [
+    'views-table',
+    'views-view-table',
+    'cols-' ~ header|length,
+    responsive ? 'responsive-enabled',
+    sticky ? 'sticky-enabled',
+  ]
+%}
+<table{{ attributes.addClass(classes) }}>
   {% if caption_needed %}
     <caption>
     {% if caption %}
@@ -49,8 +64,16 @@
   {% if header %}
     <thead>
       <tr>
-        {% for column in header %}
-          <th{{ column.attributes }} scope="col">
+        {% for key, column in header %}
+          {% if column.default_classes %}
+            {%
+              set column_classes = [
+                'views-field',
+                'views-field-' ~ fields[key],
+              ]
+            %}
+          {% endif %}
+          <th{{ column.attributes.addClass(column_classes) }} scope="col">
             {{ column.content }}
           </th>
         {% endfor %}
@@ -60,8 +83,16 @@
   <tbody>
     {% for row in rows %}
       <tr{{ row.attributes }}>
-        {% for column in row.columns %}
-          <td{{ column.attributes }}>
+        {% for key, column in row.columns %}
+          {% if column.default_classes %}
+            {%
+              set column_classes = [
+                'views-field',
+                'views-field-' ~ fields[key],
+              ]
+            %}
+          {% endif %}
+          <td{{ column.attributes.addClass(column_classes) }}>
             {{ column.content }}
           </td>
         {% endfor %}
diff --git a/core/modules/views/templates/views-view-unformatted.html.twig b/core/modules/views/templates/views-view-unformatted.html.twig
index e3fb2e3..7ee1f81 100644
--- a/core/modules/views/templates/views-view-unformatted.html.twig
+++ b/core/modules/views/templates/views-view-unformatted.html.twig
@@ -8,6 +8,9 @@
  * - rows: A list of the view's row items.
  *   - attributes: The row's HTML attributes.
  *   - content: The row's content.
+ * - view: The view object.
+ * - default_row_class: A flag indicating whether default classes should be
+ *   used on rows.
  *
  * @see template_preprocess_views_view_unformatted()
  *
@@ -18,7 +21,12 @@
   <h3>{{ title }}</h3>
 {% endif %}
 {% for row in rows %}
-  <div{{ row.attributes }}>
+  {%
+    set row_classes = [
+      default_row_class ? 'views-row',
+    ]
+  %}
+  <div{{ row.attributes.addClass(row_classes) }}>
     {{ row.content }}
   </div>
 {% endfor %}
diff --git a/core/modules/views/templates/views-view.html.twig b/core/modules/views/templates/views-view.html.twig
index 46c7e0a..a62bde1 100644
--- a/core/modules/views/templates/views-view.html.twig
+++ b/core/modules/views/templates/views-view.html.twig
@@ -4,14 +4,7 @@
  * Default theme implementation for main view template.
  *
  * Available variables:
- * - attributes: Remaining HTML attributes for the element including:
- *   - class: HTML classes that can be used to style contextually
- *     through CSS, including:
- *     - view
- *     - view-[css_name]
- *     - view-id-[view_name]
- *     - view-display-id-[display_name]
- *     - view-dom-id-[dom_id]
+ * - attributes: Remaining HTML attributes for the element.
  * - css_name: A css-safe version of the view name.
  * - css_class: The user-specified classes names, if any.
  * - header: The optional header.
@@ -31,13 +24,24 @@
  *   view content.
  * - attachment_after: An optional attachment view to be displayed after the
  *   view content.
+ * - dom_id: Unique id for every view being printed to give unique class for
+ *   Javascript.
  *
  * @see template_preprocess_views_view()
  *
  * @ingroup themeable
  */
 #}
-<div{{ attributes }}>
+{%
+  set classes = [
+    'view',
+    'view-' ~ id|clean_class,
+    'view-id-' ~ id,
+    'view-display-id-' ~ display_id,
+    dom_id ? 'view-dom-id-' ~ dom_id,
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
   {{ title_prefix }}
   {% if title %}
     {{ title }}
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index d4fb797..f7b874c 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -29,13 +29,6 @@ function template_preprocess_views_view(&$variables) {
   $variables['id'] = $id;
   $variables['display_id'] = $view->current_display;
 
-  // Basic classes.
-  $variables['attributes']['class'] = array();
-  $variables['attributes']['class'][] = 'view';
-  $variables['attributes']['class'][] = 'view-' . Html::cleanCssIdentifier($variables['id']);
-  $variables['attributes']['class'][] = 'view-id-' . $variables['id'];
-  $variables['attributes']['class'][] = 'view-display-id-' . $variables['display_id'];
-
   $css_class = $view->display_handler->getOption('css_class');
   if (!empty($css_class)) {
     $variables['css_class'] = preg_replace('/[^a-zA-Z0-9- ]/', '-', $css_class);
@@ -55,7 +48,6 @@ function template_preprocess_views_view(&$variables) {
     // identifier for each view. This identifier is written to both
     // drupalSettings and the DIV wrapper.
     $variables['dom_id'] = $view->dom_id;
-    $variables['attributes']['class'][] = 'view-dom-id-' . $variables['dom_id'];
   }
 }
 
@@ -330,10 +322,8 @@ function template_preprocess_views_view_summary(&$variables) {
     }
     $variables['rows'][$id]->url = _url($view->getUrl($args, $base_path), $url_options);
     $variables['rows'][$id]->count = intval($row->{$argument->count_alias});
-    if (isset($active_urls[$variables['rows'][$id]->url])) {
-      $variables['rows'][$id]->attributes['class'][] = 'active';
-    }
     $variables['rows'][$id]->attributes = new Attribute($variables['rows'][$id]->attributes);
+    $variables['rows'][$id]->active = isset($active_urls[$variables['rows'][$id]->url]);
   }
 }
 
@@ -394,9 +384,7 @@ function template_preprocess_views_view_summary_unformatted(&$variables) {
     }
     $variables['rows'][$id]->url = _url($view->getUrl($args, $base_path), $url_options);
     $variables['rows'][$id]->count = intval($row->{$argument->count_alias});
-    if (isset($active_urls[$variables['rows'][$id]->url])) {
-      $variables['rows'][$id]->attributes['class'][] = 'active';
-    }
+    $variables['rows'][$id]->active = isset($active_urls[$variables['rows'][$id]->url]);
     $variables['rows'][$id]->attributes = new Attribute($variables['rows'][$id]->attributes);
   }
 }
@@ -484,12 +472,9 @@ function template_preprocess_views_view_table(&$variables) {
         $variables['header'][$field]['content'] = \Drupal::l($label, new Url('<current>', [], $link_options));
       }
 
+      $variables['header'][$field]['default_classes'] = $fields[$field]->options['element_default_classes'];
       // Set up the header label class.
       $variables['header'][$field]['attributes'] = array();
-      if ($fields[$field]->options['element_default_classes']) {
-        $variables['header'][$field]['attributes']['class'][] = 'views-field';
-        $variables['header'][$field]['attributes']['class'][] = 'views-field-' . $variables['fields'][$field];
-      }
       $class = $fields[$field]->elementLabelClasses(0);
       if ($class) {
         $variables['header'][$field]['attributes']['class'][] = $class;
@@ -537,12 +522,9 @@ function template_preprocess_views_view_table(&$variables) {
       // Reference to the column in the loop to make the code easier to read.
       $column_reference =& $variables['rows'][$num]['columns'][$column];
 
+      $column_reference['default_classes'] = $fields[$field]->options['element_default_classes'];
       // Add field classes.
       $column_reference['attributes'] = array();
-      if ($fields[$field]->options['element_default_classes']) {
-        $column_reference['attributes']['class'][] = 'views-field';
-        $column_reference['attributes']['class'][] = 'views-field-' . $variables['fields'][$field];
-      }
 
       if ($classes = $fields[$field]->elementClasses($num)) {
         $column_reference['attributes']['class'][] = $classes;
@@ -615,8 +597,6 @@ function template_preprocess_views_view_table(&$variables) {
     $variables['rows'][$num]['attributes'] = new Attribute($variables['rows'][$num]['attributes']);
   }
 
-  $variables['attributes']['class'][] = 'views-table';
-  $variables['attributes']['class'][] = 'views-view-table';
   if (empty($variables['rows']) && !empty($options['empty_table'])) {
     $build = $view->display_handler->renderArea('empty');
     $variables['rows'][0]['columns'][0]['content'] = drupal_render($build);
@@ -628,11 +608,11 @@ function template_preprocess_views_view_table(&$variables) {
     ));
   }
 
+  $variables['sticky'] = FALSE;
   if (!empty($options['sticky'])) {
     $variables['view']->element['#attached']['library'][] = 'core/drupal.tableheader';
-    $variables['attributes']['class'][] = "sticky-enabled";
+    $variables['sticky'] = TRUE;
   }
-  $variables['attributes']['class'][] = 'cols-' . count($variables['header']);
 
   // Add the caption to the list if set.
   if (!empty($handler->options['caption'])) {
@@ -648,6 +628,7 @@ function template_preprocess_views_view_table(&$variables) {
   $variables['description'] = $handler->options['description'];
   $variables['caption_needed'] |= !empty($variables['summary']) || !empty($variables['description']);
 
+  $variables['responsive'] = FALSE;
   // If the table has headers and it should react responsively to columns hidden
   // with the classes represented by the constants RESPONSIVE_PRIORITY_MEDIUM
   // and RESPONSIVE_PRIORITY_LOW, add the tableresponsive behaviors.
@@ -655,7 +636,7 @@ function template_preprocess_views_view_table(&$variables) {
     $variables['view']->element['#attached']['library'][] = 'core/drupal.tableresponsive';
     // Add 'responsive-enabled' class to the table to identify it for JS.
     // This is needed to target tables constructed by this function.
-    $variables['attributes']['class'][] = 'responsive-enabled';
+    $variables['responsive'] = TRUE;
   }
 }
 
@@ -673,13 +654,6 @@ function template_preprocess_views_view_grid(&$variables) {
   $options = $variables['options'] = $variables['view']->style_plugin->options;
   $horizontal = ($options['alignment'] === 'horizontal');
 
-  $variables['attributes']['class'] = array(
-    'views-view-grid',
-    $options['alignment'],
-    'cols-' . $options['columns'],
-    'clearfix',
-  );
-
   $col = 0;
   $row = 0;
   $items = array();
@@ -700,14 +674,6 @@ function template_preprocess_views_view_grid(&$variables) {
     // Create attributes for rows.
     if (!$horizontal || ($horizontal && empty($items[$row]['attributes']))) {
       $row_attributes = array('class' => array());
-      // Add default views row classes.
-      if ($options['row_class_default']) {
-        $row_attributes['class'][] = 'views-row';
-        $row_attributes['class'][] = 'row-' . ($row + 1);
-        if ($horizontal) {
-          $row_attributes['class'][] = 'clearfix';
-        }
-      }
       // Add custom row classes.
       $row_class = array_filter(explode(' ', $variables['view']->style_plugin->getCustomClass($result_index, 'row')));
       if (!empty($row_class)) {
@@ -726,13 +692,6 @@ function template_preprocess_views_view_grid(&$variables) {
     if ($horizontal || (!$horizontal && empty($items[$col]['attributes']))) {
       $col_attributes = array('class' => array());
       // Add default views column classes.
-      if ($options['col_class_default']) {
-        $col_attributes['class'][] = 'views-col';
-        $col_attributes['class'][] = 'col-' . ($col + 1);
-        if (!$horizontal) {
-          $col_attributes['class'][] = 'clearfix';
-        }
-      }
       // Add custom column classes.
       $col_class = array_filter(explode(' ', $variables['view']->style_plugin->getCustomClass($result_index, 'col')));
       if (!empty($col_class)) {
@@ -798,18 +757,15 @@ function template_preprocess_views_view_unformatted(&$variables) {
   $style = $view->style_plugin;
   $options = $style->options;
 
-  $default_row_class = isset($options['default_row_class']) ? $options['default_row_class'] : FALSE;
+  $variables['default_row_class'] = isset($options['default_row_class']) ? $options['default_row_class'] : FALSE;
   foreach ($rows as $id => $row) {
     $variables['rows'][$id] = array();
     $variables['rows'][$id]['content'] = $row;
     $variables['rows'][$id]['attributes'] = array();
-    if ($default_row_class) {
-      $variables['rows'][$id]['attributes']['class'][] = 'views-row';
-    }
+    $variables['rows'][$id]['attributes'] = new Attribute($variables['rows'][$id]['attributes']);
     if ($row_class = $view->style_plugin->getRowClass($id)) {
-      $variables['rows'][$id]['attributes']['class'][] = $row_class;
+      $variables['rows'][$id]['attributes']->addClass($row_class);
     }
-    $variables['rows'][$id]['attributes'] = new Attribute($variables['rows'][$id]['attributes']);
   }
 }
 
