]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Prevent nested tables style leaks
authorMartijn Cuppens <martijn.cuppens@gmail.com>
Tue, 24 Mar 2020 14:00:00 +0000 (15:00 +0100)
committerMartijn Cuppens <martijn.cuppens@gmail.com>
Fri, 24 Apr 2020 08:05:10 +0000 (10:05 +0200)
scss/_mixins.scss
scss/_reboot.scss
scss/_tables.scss
scss/_variables.scss
scss/mixins/_table-row.scss [deleted file]
scss/mixins/_table-variants.scss [new file with mode: 0644]
site/content/docs/4.3/content/tables.md
site/content/docs/4.3/migration.md
site/layouts/partials/table-content.html [new file with mode: 0644]
site/layouts/shortcodes/table.html [new file with mode: 0644]

index 5a04655d5471567a223f5dfa80945516fd5744bf..b48761de9ec9ebc3e16bd60131e8e892d62eb8cf 100644 (file)
@@ -27,7 +27,7 @@
 @import "mixins/lists";
 @import "mixins/list-group";
 @import "mixins/forms";
-@import "mixins/table-row";
+@import "mixins/table-variants";
 
 // Skins
 @import "mixins/background-variant";
index c6b10d59fef9ba6988e1956f8cb1afbb513b386e..4c5dfcba41e18f0fbf780d4f35a2d700ff12b498 100644 (file)
@@ -374,6 +374,17 @@ th {
   text-align: -webkit-match-parent; // 2
 }
 
+thead,
+tbody,
+tfoot,
+tr,
+td,
+th {
+  border-color: inherit;
+  border-style: solid;
+  border-width: 0;
+}
+
 
 // Forms
 //
index 253282c98d4b3c6198258db74612b525abae438d..4969d8949610c2f2930a9dbd7d5ec713c679805a 100644 (file)
@@ -3,29 +3,45 @@
 //
 
 .table {
+  --table-bg: #{$table-bg};
+  --table-accent-bg: transparent;
+  --table-striped-color: #{$table-striped-color};
+  --table-striped-bg: #{$table-striped-bg};
+  --table-active-color: #{$table-active-color};
+  --table-active-bg: #{$table-active-bg};
+  --table-hover-color: #{$table-hover-color};
+  --table-hover-bg: #{$table-hover-bg};
+
   width: 100%;
   margin-bottom: $spacer;
   color: $table-color;
   vertical-align: $table-cell-vertical-align;
-  background-color: $table-bg; // Reset for nesting within parents with `background-color`.
-
-  th,
-  td {
+  border-color: $table-border-color;
+
+  // Target th & td
+  // We need the child combinator to prevent styles leaking to nested tables which doesn't have a `.table` class.
+  // We use the universal selectors here to simplify the selector (else we would need 6 different selectors).
+  // Another advantage is that this generates less code and makes the selector less specific making it easier to override.
+  // stylelint-disable-next-line selector-max-universal
+  > :not(caption) > * > * {
     padding: $table-cell-padding;
-    border-bottom: $table-border-width solid $table-border-color;
+    background-color: var(--table-bg);
+    background-image: linear-gradient(var(--table-accent-bg), var(--table-accent-bg));
+    border-bottom-width: $table-border-width;
   }
 
-  tbody {
+  tbody {
     vertical-align: inherit;
   }
 
-  thead th {
+  > thead {
     vertical-align: bottom;
-    border-bottom-color: $table-head-border-color;
   }
 
-  tbody + tbody {
-    border-top: (2 * $table-border-width) solid $table-border-color;
+  // Highlight border color between thead, tbody and tfoot.
+  // stylelint-disable-next-line selector-max-universal
+  > :not(:last-child) > :last-child > * {
+    border-bottom-color: currentColor;
   }
 }
 
@@ -34,7 +50,9 @@
 // Change placement of captions with a class
 //
 
-.caption-top { caption-side: top; }
+.caption-top {
+  caption-side: top;
+}
 
 
 //
@@ -42,8 +60,8 @@
 //
 
 .table-sm {
-  th,
-  td {
+  // stylelint-disable-next-line selector-max-universal
+  > :not(caption) > * > * {
     padding: $table-cell-padding-sm;
   }
 }
 // Border versions
 //
 // Add or remove borders all around the table and between all the columns.
+//
+// When borders are added on all sides of the cells, the corners can render odd when
+// these borders do not have the same color or if they are semi-transparent.
+// Therefor we add top and border bottoms to the `tr`s and left and right borders
+// to the `td`s or `th`s
 
 .table-bordered {
-  border: $table-border-width solid $table-border-color;
+  // stylelint-disable-next-line selector-max-universal
+  > :not(caption) > * {
+    border-width: $table-border-width 0;
 
-  th,
-  td {
-    border: $table-border-width solid $table-border-color;
-  }
-
-  thead {
-    th,
-    td {
-      border-bottom-width: 2 * $table-border-width;
+    // stylelint-disable-next-line selector-max-universal
+    > * {
+      border-width: 0 $table-border-width;
     }
   }
 }
 
 .table-borderless {
-  th,
-  td,
-  thead th,
-  tbody + tbody {
-    border: 0;
+  // stylelint-disable-next-line selector-max-universal
+  > :not(caption) > * > * {
+    border-bottom-width: 0;
   }
 }
 
 // Default zebra-stripe styles (alternating gray and transparent backgrounds)
 
 .table-striped {
-  tbody tr:nth-of-type(#{$table-striped-order}) {
-    background-color: $table-accent-bg;
+  > tbody > tr:nth-of-type(#{$table-striped-order}) {
+    --table-accent-bg: var(--table-striped-bg);
+    color: var(--table-striped-color);
   }
 }
 
+// Active table
+//
+// The `.table-active` class can be added to highlight rows or cells
+
+.table-active {
+  --table-accent-bg: var(--table-active-bg);
+  color: var(--table-active-color);
+}
 
 // Hover effect
 //
 // Placed here since it has to come after the potential zebra striping
 
 .table-hover {
-  tbody tr {
-    &:hover {
-      color: $table-hover-color;
-      background-color: $table-hover-bg;
-    }
+  > tbody > tr:hover {
+    --table-accent-bg: var(--table-hover-bg);
+    color: var(--table-hover-color);
   }
 }
 
 
-// Table backgrounds
+// Table variants
 //
-// Exact selectors below required to override `.table-striped` and prevent
-// inheritance to nested tables.
+// Table variants set the table cell backgrounds, border colors
+// and the colors of the striped, hovered & active tables
 
-@each $color, $value in $theme-colors {
-  @include table-row-variant($color, color-level($value, $table-bg-level), color-level($value, $table-border-level));
+@each $color, $value in $table-variants {
+  @include table-variant($color, $value);
 }
 
-@include table-row-variant(active, $table-active-bg);
-
-
-// Dark styles
-//
-// Same table markup, but inverted color scheme: dark background and light text.
-
-// stylelint-disable-next-line no-duplicate-selectors
-.table {
-  .thead-dark {
-    th {
-      color: $table-dark-color;
-      background-color: $table-dark-bg;
-      border-color: $table-dark-border-color;
-    }
-  }
-
-  .thead-light {
-    th {
-      color: $table-head-color;
-      background-color: $table-head-bg;
-      border-color: $table-border-color;
-    }
-  }
-}
-
-.table-dark {
-  color: $table-dark-color;
-  background-color: $table-dark-bg;
-
-  th,
-  td,
-  thead th {
-    border-color: $table-dark-border-color;
-  }
-
-  &.table-bordered {
-    border: 0;
-  }
-
-  &.table-striped {
-    tbody tr:nth-of-type(#{$table-striped-order}) {
-      background-color: $table-dark-accent-bg;
-    }
-  }
-
-  &.table-hover {
-    tbody tr {
-      &:hover {
-        color: $table-dark-hover-color;
-        background-color: $table-dark-hover-bg;
-      }
-    }
-  }
-}
-
-
 // Responsive tables
 //
 // Generate series of `.table-responsive-*` classes for configuring the screen
index fb71319866a21a566a19ff00e8cca627e95b5f40..9a2348df66aef11bf8945b6e798f17341a86ce5f 100644 (file)
@@ -465,38 +465,48 @@ $mark-bg:                     #fcf8e3 !default;
 //
 // Customizes the `.table` component with basic values, each used across all table variations.
 
+// scss-docs-start table-variables
 $table-cell-padding:          .5rem !default;
 $table-cell-padding-sm:       .25rem !default;
 
 $table-cell-vertical-align:   top !default;
 
 $table-color:                 $body-color !default;
-$table-bg:                    null !default;
-$table-accent-bg:             rgba($black, .05) !default;
+$table-bg:                    transparent !default;
+
+$table-striped-color:         $table-color !default;
+$table-striped-bg-factor:      .05 !default;
+$table-striped-bg:             rgba($black, $table-striped-bg-factor) !default;
+
+$table-active-color:          $table-color !default;
+$table-active-bg-factor:      .1 !default;
+$table-active-bg:             rgba($black, $table-active-bg-factor) !default;
+
 $table-hover-color:           $table-color !default;
-$table-hover-bg:              rgba($black, .075) !default;
-$table-active-bg:             $table-hover-bg !default;
+$table-hover-bg-factor:       .075 !default;
+$table-hover-bg:              rgba($black, $table-hover-bg-factor) !default;
 
+$table-border-factor:         .1 !default;
 $table-border-width:          $border-width !default;
 $table-border-color:          $border-color !default;
 
-$table-head-bg:               $gray-200 !default;
-$table-head-color:            $gray-700 !default;
-$table-head-border-color:     $gray-700 !default;
-
-$table-dark-color:            $white !default;
-$table-dark-bg:               $gray-800 !default;
-$table-dark-accent-bg:        rgba($white, .05) !default;
-$table-dark-hover-color:      $table-dark-color !default;
-$table-dark-hover-bg:         rgba($white, .075) !default;
-$table-dark-border-color:     lighten($table-dark-bg, 7.5%) !default;
-
 $table-striped-order:         odd !default;
 
 $table-caption-color:         $text-muted !default;
 
 $table-bg-level:              -9 !default;
-$table-border-level:          -6 !default;
+
+$table-variants: (
+  "primary":    color-level($primary, $table-bg-level),
+  "secondary":  color-level($secondary, $table-bg-level),
+  "success":    color-level($success, $table-bg-level),
+  "info":       color-level($info, $table-bg-level),
+  "warning":    color-level($warning, $table-bg-level),
+  "danger":     color-level($danger, $table-bg-level),
+  "light":      $light,
+  "dark":       $dark,
+) !default;
+// scss-docs-end table-variables
 
 
 // Buttons + Forms
diff --git a/scss/mixins/_table-row.scss b/scss/mixins/_table-row.scss
deleted file mode 100644 (file)
index 517229e..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// Tables
-
-@mixin table-row-variant($state, $background, $border: null) {
-  // Exact selectors below required to override `.table-striped` and prevent
-  // inheritance to nested tables.
-  .table-#{$state} {
-    &,
-    > th,
-    > td {
-      background-color: $background;
-    }
-
-    @if $border != null {
-      th,
-      td,
-      thead th,
-      tbody + tbody {
-        border-color: $border;
-      }
-    }
-  }
-
-  // Hover states for `.table-hover`
-  // Note: this is not available for cells or rows within `thead` or `tfoot`.
-  .table-hover {
-    $hover-background: darken($background, 5%);
-
-    .table-#{$state} {
-      &:hover {
-        background-color: $hover-background;
-
-        > td,
-        > th {
-          background-color: $hover-background;
-        }
-      }
-    }
-  }
-}
diff --git a/scss/mixins/_table-variants.scss b/scss/mixins/_table-variants.scss
new file mode 100644 (file)
index 0000000..9fd066e
--- /dev/null
@@ -0,0 +1,21 @@
+// scss-docs-start table-variant
+@mixin table-variant($state, $background) {
+  .table-#{$state} {
+    $color: color-contrast(opaque($body-bg, $background));
+    $hover-bg: mix($color, $background, percentage($table-hover-bg-factor));
+    $striped-bg: mix($color, $background, percentage($table-striped-bg-factor));
+    $active-bg: mix($color, $background, percentage($table-active-bg-factor));
+
+    --table-bg: #{$background};
+    --table-striped-bg: #{$striped-bg};
+    --table-striped-color: #{color-contrast($striped-bg)};
+    --table-active-bg: #{$active-bg};
+    --table-active-color: #{color-contrast($active-bg)};
+    --table-hover-bg: #{$hover-bg};
+    --table-hover-color: #{color-contrast($hover-bg)};
+
+    color: $color;
+    border-color: mix($color, $background, percentage($table-border-factor));
+  }
+}
+// scss-docs-end table-variant
index 76b799fca31cae44f09746c0409e2185ae8e5a89..bcf400720548d859b1d9ab379c9c756042471bd9 100644 (file)
@@ -8,296 +8,321 @@ toc: true
 
 ## Overview
 
-Due to the widespread use of `<table>` elements across third-party widgets like calendars and date pickers, Bootstrap's tables are **opt-in**. Add the base class `.table` to any `<table>`, then extend with our optional modifier classes or custom styles. **All table styles are inherited in Bootstrap**, meaning any nested tables will be styled in the same manner as the parent.
+Due to the widespread use of `<table>` elements across third-party widgets like calendars and date pickers, Bootstrap's tables are **opt-in**. Add the base class `.table` to any `<table>`, then extend with our optional modifier classes or custom styles. All table styles are not inherited in Bootstrap, meaning any nested tables can be styled independent from the parent.
 
 Using the most basic table markup, here's how `.table`-based tables look in Bootstrap.
 
-{{< example >}}
-<table class="table">
-  <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
-    </tr>
-    <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
-    </tr>
-    <tr>
-      <th scope="row">3</th>
-      <td>Larry</td>
-      <td>the Bird</td>
-      <td>@twitter</td>
-    </tr>
-  </tbody>
-</table>
-{{< /example >}}
+{{< table class="table" simplified="false" >}}
+
+## Variants
 
-## Options
+Use contextual classes to color tables, table rows or individual cells.
 
-### Inverted
+<div class="bd-example">
+  <table class="table">
+    <thead>
+      <tr>
+        <th scope="col">Class</th>
+        <th scope="col">Heading</th>
+        <th scope="col">Heading</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr>
+        <th scope="row">Default</th>
+        <td>Cell</td>
+        <td>Cell</td>
+      </tr>
+      {{< table.inline >}}
+      {{- range (index $.Site.Data "theme-colors") }}
+        <tr class="table-{{ .name }}">
+          <th scope="row">{{ .name | title }}</th>
+          <td>Cell</td>
+          <td>Cell</td>
+        </tr>
+      {{- end -}}
+      {{< /table.inline >}}
+    </tbody>
+  </table>
+</div>
 
-You can also invert the colors—with light text on dark backgrounds—with `.table-dark`.
+{{< highlight html >}}
+<!-- On tables -->{{< table.inline >}}
+{{- range (index $.Site.Data "theme-colors") }}
+<table class="table-{{ .name }}">...</table>
+{{- end -}}
+{{< /table.inline >}}
 
-{{< example >}}
-<table class="table table-dark">
-  <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
-    </tr>
-    <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
-    </tr>
-    <tr>
-      <th scope="row">3</th>
-      <td>Larry</td>
-      <td>the Bird</td>
-      <td>@twitter</td>
-    </tr>
-  </tbody>
-</table>
-{{< /example >}}
+<!-- On rows -->{{< table.inline >}}
+{{- range (index $.Site.Data "theme-colors") }}
+<tr class="table-{{ .name }}">...</tr>
+{{- end -}}
+{{< /table.inline >}}
+
+<!-- On cells (`td` or `th`) -->
+<tr>{{< table.inline >}}
+{{- range (index $.Site.Data "theme-colors") }}
+  <td class="table-{{ .name }}">...</td>
+{{- end -}}
+{{< /table.inline >}}
+</tr>
+{{< /highlight >}}
+
+{{< callout info >}}
+{{< partial "callout-warning-color-assistive-technologies.md" >}}
+{{< /callout >}}
+
+## Accented tables
 
 ### Striped rows
 
 Use `.table-striped` to add zebra-striping to any table row within the `<tbody>`.
 
-{{< example >}}
-<table class="table table-striped">
+{{< table class="table table-striped" >}}
+
+These classes can also be added to table variants:
+
+{{< table class="table table-dark table-striped" >}}
+
+{{< table class="table table-success table-striped" >}}
+
+### Hoverable rows
+
+Add `.table-hover` to enable a hover state on table rows within a `<tbody>`.
+
+{{< table class="table table-hover" >}}
+
+{{< table class="table table-dark table-hover" >}}
+
+These hoverable rows can also be combined with the striped variant:
+
+{{< table class="table table-striped table-hover" >}}
+
+### Active tables
+
+Highlight a table row or cell by adding a `.table-active` class.
+
+<div class="bd-example">
+  <table class="table">
+    <thead>
+      <tr>
+        <th scope="col">#</th>
+        <th scope="col">First</th>
+        <th scope="col">Last</th>
+        <th scope="col">Handle</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr class="table-active">
+        <th scope="row">1</th>
+        <td>Mark</td>
+        <td>Otto</td>
+        <td>@mdo</td>
+      </tr>
+      <tr>
+        <th scope="row">2</th>
+        <td>Jacob</td>
+        <td>Thornton</td>
+        <td>@fat</td>
+      </tr>
+      <tr>
+        <th scope="row">3</th>
+        <td colspan="2" class="table-active">Larry the Bird</td>
+        <td>@twitter</td>
+      </tr>
+    </tbody>
+  </table>
+</div>
+
+{{< highlight html >}}
+<table class="table">
   <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
+    ...
   </thead>
   <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
+    <tr class="table-active">
+      ...
     </tr>
     <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
+      ...
     </tr>
     <tr>
       <th scope="row">3</th>
-      <td>Larry</td>
-      <td>the Bird</td>
+      <td colspan="2" class="table-active">Larry the Bird</td>
       <td>@twitter</td>
     </tr>
   </tbody>
 </table>
-{{< /example >}}
+{{< /highlight >}}
 
-{{< example >}}
-<table class="table table-striped table-dark">
+<div class="bd-example">
+  <table class="table table-dark">
+    <thead>
+      <tr>
+        <th scope="col">#</th>
+        <th scope="col">First</th>
+        <th scope="col">Last</th>
+        <th scope="col">Handle</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr class="table-active">
+        <th scope="row">1</th>
+        <td>Mark</td>
+        <td>Otto</td>
+        <td>@mdo</td>
+      </tr>
+      <tr>
+        <th scope="row">2</th>
+        <td>Jacob</td>
+        <td>Thornton</td>
+        <td>@fat</td>
+      </tr>
+      <tr>
+        <th scope="row">3</th>
+        <td colspan="2" class="table-active">Larry the Bird</td>
+        <td>@twitter</td>
+      </tr>
+    </tbody>
+  </table>
+</div>
+
+{{< highlight html >}}
+<table class="table table-dark">
   <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
+    ...
   </thead>
   <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
+    <tr class="table-active">
+      ...
     </tr>
     <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
+      ...
     </tr>
     <tr>
       <th scope="row">3</th>
-      <td>Larry</td>
-      <td>the Bird</td>
+      <td colspan="2" class="table-active">Larry the Bird</td>
       <td>@twitter</td>
     </tr>
   </tbody>
 </table>
-{{< /example >}}
+{{< /highlight >}}
 
-### Bordered
+## How do the variants and accented tables work?
+
+For the accented tables ([striped rows](#striped-rows), [hoverable rows](#hoverable-rows) and [active tables](#active-tables)), we used some techniques to make these effects work for all our [table variants](#variants):
+
+- First of all we set the background of a table cell with the `--table-bg` custom property. All table variants then set that custom property to colorize the table cells. This way, we don't get into trouble if semi-transparent colors are used as table backgrounds.
+- Then we add a linear background to the table cells with `background-image: linear-gradient(var(--table-accent-bg), var(--table-accent-bg));`. Since `--table-accent-bg` is transparent by default, we have an invisible transparent linear gradient by default.
+- When either `.table-striped`, `.table-hover` or `.table-active` classes are added, the `--table-accent-bg` is set to a semitransparent color to colorize the background.
+- For each table variant the `--table-accent-bg` color with the most contrast is generated, therefor `.table-primary` has a darkened accent color and `.table-dark` has a lightened accent color.
+- The text color and border color are also generated the same way. The colors and border colors are inherited by default.
+
+Behind the scenes it looks like this:
+
+{{< scss-docs name="table-variant" file="scss/mixins/_table-variants.scss" >}}
+
+## Table borders
+
+### Bordered tables
 
 Add `.table-bordered` for borders on all sides of the table and cells.
 
-{{< example >}}
-<table class="table table-bordered">
-  <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
-    </tr>
-    <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
-    </tr>
-    <tr>
-      <th scope="row">3</th>
-      <td colspan="2">Larry the Bird</td>
-      <td>@twitter</td>
-    </tr>
-  </tbody>
-</table>
-{{< /example >}}
+{{< table class="table table-bordered" >}}
 
-{{< example >}}
-<table class="table table-bordered table-dark">
-  <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
-    </tr>
-    <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
-    </tr>
-    <tr>
-      <th scope="row">3</th>
-      <td colspan="2">Larry the Bird</td>
-      <td>@twitter</td>
-    </tr>
-  </tbody>
-</table>
-{{< /example >}}
+[Border color utilities]({{< docsref "/utilities/borders#border-color" >}}) can be added to change colors:
+
+{{< table class="table table-bordered border-primary" >}}
 
-### No borders
+### Tables without borders
 
 Add `.table-borderless` for a table without borders.
 
-{{< example >}}
-<table class="table table-borderless">
-  <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
-    </tr>
-    <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
-    </tr>
-    <tr>
-      <th scope="row">3</th>
-      <td colspan="2">Larry the Bird</td>
-      <td>@twitter</td>
-    </tr>
-  </tbody>
-</table>
-{{< /example >}}
+{{< table class="table table-borderless" >}}
 
-`.table-borderless` can also be used on dark tables.
+{{< table class="table table-dark table-borderless" >}}
 
-{{< example >}}
-<table class="table table-borderless table-dark">
-  <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
-    </tr>
-    <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
-    </tr>
-    <tr>
-      <th scope="row">3</th>
-      <td colspan="2">Larry the Bird</td>
-      <td>@twitter</td>
-    </tr>
-  </tbody>
+### Small tables
+
+Add `.table-sm` to make any `.table` more compact by cutting all cell `padding` in half.
+
+{{< table class="table table-sm" >}}
+
+{{< table class="table table-dark table-sm" >}}
+
+## Vertical alignment
+
+Table cells of `<thead>` are always vertical aligned to the bottom. Table cells in `<tbody>` inherit their alignment from `<table>` and are aligned to the the top by default. Use the [vertical align]({{< docsref "/utilities/vertical-align" >}}) classes to re-align where needed.
+
+<div class="bd-example">
+  <div class="table-responsive">
+    <table class="table align-middle">
+      <thead>
+        <tr>
+          <th scope="col" class="w-25">Heading 1</th>
+          <th scope="col" class="w-25">Heading 2</th>
+          <th scope="col" class="w-25">Heading 3</th>
+          <th scope="col" class="w-25">Heading 4</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
+          <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
+          <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
+          <td>Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum. Vestibulum id ligula porta felis euismod semper.</td>
+        </tr>
+        <tr class="align-bottom">
+          <td>This cell inherits <code>vertical-align: bottom;</code> from the table row</td>
+          <td>This cell inherits <code>vertical-align: bottom;</code> from the table row</td>
+          <td>This cell inherits <code>vertical-align: bottom;</code> from the table row</td>
+          <td>Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum. Vestibulum id ligula porta felis euismod semper.</td>
+        </tr>
+        <tr>
+          <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
+          <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
+          <td class="align-top">This cell is aligned to the top.</td>
+          <td>Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum. Vestibulum id ligula porta felis euismod semper.</td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
+</div>
+
+{{< highlight html >}}
+<table class="table table-sm table-dark">
+  <div class="table-responsive">
+    <table class="table align-middle">
+      <thead>
+        <tr>
+          ...
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          ...
+        </tr>
+        <tr class="align-bottom">
+          ...
+        </tr>
+        <tr>
+          <td>...</td>
+          <td>...</td>
+          <td class="align-top">This cell is aligned to the top.</td>
+          <td>...</td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
 </table>
-{{< /example >}}
+{{< /highlight >}}
 
-### Hoverable rows
+## Nesting
 
-Add `.table-hover` to enable a hover state on table rows within a `<tbody>`.
+Neither border styles, active styles nor table variants are inherited by nested tables:
 
-{{< example >}}
-<table class="table table-hover">
+<div class="bd-example">
+<table class="table table-striped table-bordered">
   <thead>
     <tr>
       <th scope="col">#</th>
@@ -314,59 +339,77 @@ Add `.table-hover` to enable a hover state on table rows within a `<tbody>`.
       <td>@mdo</td>
     </tr>
     <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
+      <td colspan="4">
+        <table class="table mb-0">
+          <thead>
+            <tr>
+              <th scope="col">Header</th>
+              <th scope="col">Header</th>
+              <th scope="col">Header</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <th scope="row">A</th>
+              <td>First</td>
+              <td>Last</td>
+            </tr>
+            <tr>
+              <th scope="row">B</th>
+              <td>First</td>
+              <td>Last</td>
+            </tr>
+            <tr>
+              <th scope="row">C</th>
+              <td>First</td>
+              <td>Last</td>
+            </tr>
+          </tbody>
+        </table>
+      </td>
     </tr>
     <tr>
       <th scope="row">3</th>
-      <td colspan="2">Larry the Bird</td>
+      <td>Larry</td>
+      <td>the Bird</td>
       <td>@twitter</td>
     </tr>
   </tbody>
 </table>
-{{< /example >}}
+</div>
 
-{{< example >}}
-<table class="table table-hover table-dark">
+{{< highlight html >}}
+<table class="table table-striped">
   <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
+    ...
   </thead>
   <tbody>
+    ...
     <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
-    </tr>
-    <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
-    </tr>
-    <tr>
-      <th scope="row">3</th>
-      <td colspan="2">Larry the Bird</td>
-      <td>@twitter</td>
+      <td colspan="4">
+        <table class="table mb-0">
+          ...
+        </table>
+      </td>
     </tr>
+    ...
   </tbody>
 </table>
-{{< /example >}}
+{{< /highlight >}}
 
-### Small tables
+## How nesting works
 
-Add `.table-sm` to make any `.table` more compact by cutting all cell `padding` in half.
+To prevent **any** style from leaking to nested tables we worked with the child combinator (`>`). Since we needed to target all the `td`s and `th`s in the `thead`, `tbody` and `tfoot`, our selector would look pretty long. Therefor we use the rather odd looking `.table > :not(caption) > * > * ` selector to target all `td`s and `th`s of the `.table` and not a nested table. Note: if you add `<tr>`s as direct children of a table, those `<tr>` will be wrapped in a `<tbody>` by default and therefor making the selector work.
 
-{{< example >}}
-<table class="table table-sm">
-  <thead>
+## Anatomy
+
+### Table head
+
+Similar to tables and dark tables, use the modifier classes `.table-light` or `.table-dark` to make `<thead>`s appear light or dark gray.
+
+<div class="bd-example">
+<table class="table">
+  <thead class="table-light">
     <tr>
       <th scope="col">#</th>
       <th scope="col">First</th>
@@ -389,201 +432,28 @@ Add `.table-sm` to make any `.table` more compact by cutting all cell `padding`
     </tr>
     <tr>
       <th scope="row">3</th>
-      <td colspan="2">Larry the Bird</td>
+      <td>Larry</td>
+      <td>the Bird</td>
       <td>@twitter</td>
     </tr>
   </tbody>
 </table>
-{{< /example >}}
-
-## Vertical alignment
-
-Table cells of `<thead>` are always vertical aligned to the bottom. Table cells in `<tbody>` inherit their alignment from `<table>` and are aligned to the the top by default.
-
-{{< example >}}
-<div class="table-responsive">
-  <table class="table align-middle">
-    <thead>
-      <tr>
-        <th scope="col" class="w-25">Heading 1</th>
-        <th scope="col" class="w-25">Heading 2</th>
-        <th scope="col" class="w-25">Heading 3</th>
-        <th scope="col" class="w-25">Heading 4</th>
-      </tr>
-    </thead>
-    <tbody>
-      <tr>
-        <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
-        <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
-        <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
-        <td>Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum. Vestibulum id ligula porta felis euismod semper.</td>
-      </tr>
-      <tr class="align-bottom">
-        <td>This cell inherits <code>vertical-align: bottom;</code> from the table row</td>
-        <td>This cell inherits <code>vertical-align: bottom;</code> from the table row</td>
-        <td>This cell inherits <code>vertical-align: bottom;</code> from the table row</td>
-        <td>Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum. Vestibulum id ligula porta felis euismod semper.</td>
-      </tr>
-      <tr>
-        <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
-        <td>This cell inherits <code>vertical-align: middle;</code> from the table</td>
-        <td class="align-top">This cell is aligned to the top.</td>
-        <td>Nulla vitae elit libero, a pharetra augue. Cras mattis consectetur purus sit amet fermentum. Vestibulum id ligula porta felis euismod semper.</td>
-      </tr>
-    </tbody>
-  </table>
-</div>
-{{< /example >}}
-
-### Variants
-
-Use contextual classes to color table rows or individual cells.
-
-<div class="bd-example">
-  <table class="table">
-    <thead>
-      <tr>
-        <th scope="col">Class</th>
-        <th scope="col">Heading</th>
-        <th scope="col">Heading</th>
-      </tr>
-    </thead>
-    <tbody>
-      <tr class="table-active">
-        <th scope="row">Active</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr>
-        <th scope="row">Default</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      {{< table.inline >}}
-      {{- range (index $.Site.Data "theme-colors") }}
-        <tr class="table-{{ .name }}">
-          <th scope="row">{{ .name | title }}</th>
-          <td>Cell</td>
-          <td>Cell</td>
-        </tr>
-      {{- end -}}
-      {{< /table.inline >}}
-    </tbody>
-  </table>
 </div>
 
 {{< highlight html >}}
-<!-- On rows -->
-<tr class="table-active">...</tr>
-{{< table.inline >}}
-{{- range (index $.Site.Data "theme-colors") }}
-<tr class="table-{{ .name }}">...</tr>
-{{- end -}}
-{{< /table.inline >}}
-
-<!-- On cells (`td` or `th`) -->
-<tr>
-  <td class="table-active">...</td>
-{{< table.inline >}}
-{{- range (index $.Site.Data "theme-colors") }}
-  <td class="table-{{ .name }}">...</td>
-{{- end -}}
-{{< /table.inline >}}
-</tr>
+<table class="table">
+  <thead class="table-light">
+    ...
+  </thead>
+  <tbody>
+    ...
+  </tbody>
+</table>
 {{< /highlight >}}
 
-Regular table background variants are not available with the dark table, however, you may use [text or background utilities]({{< docsref "/utilities/colors" >}}) to achieve similar styles.
-
 <div class="bd-example">
-  <table class="table table-dark">
-    <thead>
-      <tr>
-        <th scope="col">#</th>
-        <th scope="col">Heading</th>
-        <th scope="col">Heading</th>
-      </tr>
-    </thead>
-    <tbody>
-      <tr class="bg-primary">
-        <th scope="row">1</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr>
-        <th scope="row">2</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr class="bg-success">
-        <th scope="row">3</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr>
-        <th scope="row">4</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr class="bg-info">
-        <th scope="row">5</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr>
-        <th scope="row">6</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr class="bg-warning">
-        <th scope="row">7</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr>
-        <th scope="row">8</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-      <tr class="bg-danger">
-        <th scope="row">9</th>
-        <td>Cell</td>
-        <td>Cell</td>
-      </tr>
-    </tbody>
-  </table>
-</div>
-
-{{< highlight html >}}
-<!-- On rows -->
-<tr class="bg-primary">...</tr>
-<tr class="bg-success">...</tr>
-<tr class="bg-warning">...</tr>
-<tr class="bg-danger">...</tr>
-<tr class="bg-info">...</tr>
-
-<!-- On cells (`td` or `th`) -->
-<tr>
-  <td class="bg-primary">...</td>
-  <td class="bg-success">...</td>
-  <td class="bg-warning">...</td>
-  <td class="bg-danger">...</td>
-  <td class="bg-info">...</td>
-</tr>
-{{< /highlight >}}
-
-{{< callout info >}}
-{{< partial "callout-warning-color-assistive-technologies.md" >}}
-{{< /callout >}}
-
-## Anatomy
-
-### Table head
-
-Similar to tables and dark tables, use the modifier classes `.thead-light` or `.thead-dark` to make `<thead>`s appear light or dark gray.
-
-{{< example >}}
 <table class="table">
-  <thead class="thead-dark">
+  <thead class="table-dark">
     <tr>
       <th scope="col">#</th>
       <th scope="col">First</th>
@@ -612,9 +482,25 @@ Similar to tables and dark tables, use the modifier classes `.thead-light` or `.
     </tr>
   </tbody>
 </table>
+</div>
+
+{{< highlight html >}}
+<table class="table">
+  <thead class="table-dark">
+    ...
+  </thead>
+  <tbody>
+    ...
+  </tbody>
+</table>
+{{< /highlight >}}
+
 
+### Table foot
+
+<div class="bd-example">
 <table class="table">
-  <thead class="thead-light">
+  <thead class="table-light">
     <tr>
       <th scope="col">#</th>
       <th scope="col">First</th>
@@ -642,46 +528,53 @@ Similar to tables and dark tables, use the modifier classes `.thead-light` or `.
       <td>@twitter</td>
     </tr>
   </tbody>
+  <tfoot>
+    <tr>
+      <td>Footer</td>
+      <td>Footer</td>
+      <td>Footer</td>
+      <td>Footer</td>
+    </tr>
+  </tfoot>
 </table>
-{{< /example >}}
+</div>
+
+{{< highlight html >}}
+<table class="table">
+  <thead>
+    ...
+  </thead>
+  <tbody>
+    ...
+  </tbody>
+  <tfoot>
+    ...
+  </tfoot>
+</table>
+{{< /highlight >}}
 
 ### Captions
 
 A `<caption>` functions like a heading for a table. It helps users with screen readers to find a table and understand what it's about and decide if they want to read it.
 
-{{< example >}}
-<table class="table">
+<div class="bd-example">
+  <table class="table">
+    <caption>List of users</caption>
+    {{< partial "table-content.html" >}}
+  </table>
+</div>
+
+{{< highlight html >}}
+<table class="table table-sm">
   <caption>List of users</caption>
   <thead>
-    <tr>
-      <th scope="col">#</th>
-      <th scope="col">First</th>
-      <th scope="col">Last</th>
-      <th scope="col">Handle</th>
-    </tr>
+    ...
   </thead>
   <tbody>
-    <tr>
-      <th scope="row">1</th>
-      <td>Mark</td>
-      <td>Otto</td>
-      <td>@mdo</td>
-    </tr>
-    <tr>
-      <th scope="row">2</th>
-      <td>Jacob</td>
-      <td>Thornton</td>
-      <td>@fat</td>
-    </tr>
-    <tr>
-      <th scope="row">3</th>
-      <td>Larry</td>
-      <td>the Bird</td>
-      <td>@twitter</td>
-    </tr>
+    ...
   </tbody>
 </table>
-{{< /example >}}
+{{< /highlight >}}
 
 You can also put the `<caption>` on the top of the table with `.caption-top`.
 
@@ -880,3 +773,10 @@ Use `.table-responsive{-sm|-md|-lg|-xl|-xxl}` as needed to create responsive tab
 {{- end -}}
 {{< /tables.inline >}}
 {{< /highlight >}}
+
+## Customizing in Sass
+
+- The factor variables (`$table-striped-bg-factor`, `$table-active-bg-factor` & `$table-hover-bg-factor`) are used to determine the contrast in table variants.
+- Apart from the light & dark table variants, theme colors are lightened by the `$table-bg-level` variable.
+
+{{< scss-docs name="table-variables" file="scss/_variables.scss" >}}
index 34f8dc9f0f10de1795c6ceb62b96c588918ca904..3806b6049ab2badebddd0cc0083780a2cf0f4b1d 100644 (file)
@@ -72,7 +72,10 @@ Changes to Reboot, typography, tables, and more.
 
 - [RFS]({{< docsref "/getting-started/rfs" >}}) enabled for automated font size rescaling. [See #29152](https://github.com/twbs/bootstrap/pull/29152)
 - Reset default horizontal `padding-left` on `<ul>` and `<ol>` elements from browser default `40px` to `2rem`.
-- Simplified table styles (no more 2px border on `thead > th` elements) and tightened cell padding.
+- Simplified table styles (no more odd top border) and tightened cell padding.
+- Nested tables do not inherit styles anymore.
+- `.thead-light` and `.thead-dark` are dropped in favor of the `.table-*` variant classes which can be used for all table elements (`thead`, `tbody`, `tfoot`, `tr`, `th` and `td`).
+- The `table-row-variant()` mixin is renamed to `table-variant()` and accepts only 2 parameters: `$color` (colon name) and `$value` (color code). The border color and accent colors are automatically calculated based on the table factor variables.
 - Dropped `.pre-scrollable` class. [See #29135](https://github.com/twbs/bootstrap/pull/29135)
 - `.text-*` utilities do not add hover and focus states to links anymore. `.link-*` helper classes can be used instead. [See #29267](https://github.com/twbs/bootstrap/pull/29267)
 - Drop `.text-justify` class. [See #229793](https://github.com/twbs/bootstrap/pull/29793)
diff --git a/site/layouts/partials/table-content.html b/site/layouts/partials/table-content.html
new file mode 100644 (file)
index 0000000..71fca1d
--- /dev/null
@@ -0,0 +1,27 @@
+  <thead>
+    <tr>
+      <th scope="col">#</th>
+      <th scope="col">First</th>
+      <th scope="col">Last</th>
+      <th scope="col">Handle</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <th scope="row">1</th>
+      <td>Mark</td>
+      <td>Otto</td>
+      <td>@mdo</td>
+    </tr>
+    <tr>
+      <th scope="row">2</th>
+      <td>Jacob</td>
+      <td>Thornton</td>
+      <td>@fat</td>
+    </tr>
+    <tr>
+      <th scope="row">3</th>
+      <td colspan="2">Larry the Bird</td>
+      <td>@twitter</td>
+    </tr>
+  </tbody>
diff --git a/site/layouts/shortcodes/table.html b/site/layouts/shortcodes/table.html
new file mode 100644 (file)
index 0000000..43f230a
--- /dev/null
@@ -0,0 +1,30 @@
+{{- /*
+  Usage: `table [args]`
+
+  `args` are optional and can be one of the following:
+  class: any class(es) to be added to the `table` - default ""
+  simplified: show a simplified version in the examples - default `true`
+*/ -}}
+
+{{- $simplified := .Get "simplified" | default true -}}
+
+{{- $table_attributes := "" -}}
+{{- $table_content := "  ...\n" -}}
+
+{{- with .Get "class" -}}
+{{- $table_attributes = printf ` class="%s"` . -}}
+{{- end -}}
+
+{{- if eq $simplified "false" -}}
+{{- $table_content = partialCached "table-content" . -}}
+{{- end -}}
+
+{{- $table := printf "<table%s>\n%s</table>" $table_attributes $table_content -}}
+
+<div class="bd-example">
+  <table{{ with .Get "class" }} class="{{ . }}"{{ end }}>
+    {{ partialCached "table-content" . }}
+  </table>
+</div>
+
+{{- highlight $table "html" "" -}}