具有基于视口的列数的 Bootstrap 4 卡片组

Posted

技术标签:

【中文标题】具有基于视口的列数的 Bootstrap 4 卡片组【英文标题】:Bootstrap 4 card-deck with number of columns based on viewport 【发布时间】:2016-07-25 15:46:09 【问题描述】:

我正在尝试在 bootstrap 4 中实现卡片组功能,以使我的所有卡片都具有相同的高度。

bootstrap 提供的示例显示了 4 张不错的卡片,但无论视口如何,它都是一行中的 4 张卡片。见codeply here。

这对我来说没有意义,因为我假设您希望卡片缩小到最小尺寸以使您的内容仍然看起来不错。

然后我尝试添加一些视口类来打破屏幕尺寸,但是一旦添加了该 div,卡片组就不再适用,因此不会使卡片等高。

我怎样才能做到这一点?这是一个将在 Bootstrap 4 的完整版本中解决的缺失功能吗?

这是小提琴:https://jsfiddle.net/crrm5q9m/

<div class="card-deck-wrapper">
  <div class="card-deck">
    <div class="card card-inverse card-success text-center col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-1">
      <div class="card-block">
        <blockquote class="card-blockquote">
          <p>It's really good news that the new Bootstrap 4 now has support for CSS 3 flexbox.</p>
          <footer>Makes flexible layouts <cite title="Source Title">Faster</cite></footer>
        </blockquote>
      </div>
    </div>
    <div class="card card-inverse card-danger text-center col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-1">
      <div class="card-block">
        <blockquote class="card-blockquote">
          <p>The Bootstrap 3.x element that was called "Panel" before, is now called a "Card".</p>
          <footer>All of this makes more <cite title="Source Title">Sense</cite></footer>
        </blockquote>
      </div>
    </div>
    <div class="card card-inverse card-warning text-center col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-1">
      <div class="card-block">
        <blockquote class="card-blockquote">
          <p>There are also some interesting new text classes for uppercase and capitalize.</p>
          <footer>These handy utilities make it <cite title="Source Title">Easy</cite></footer>
        </blockquote>
      </div>
    </div>
    <div class="card card-inverse card-info text-center col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-1">
      <div class="card-block">
        <blockquote class="card-blockquote">
          <p>If you want to use cool icons in Bootstrap 4, you'll have to find your own such as Font Awesome or Ionicons.</p>
          <footer>The Glyphicons are not <cite title="Source Title">Included</cite></footer>
        </blockquote>
      </div>
    </div>
        <div class="card card-inverse card-success text-center col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-1">
      <div class="card-block">
        <blockquote class="card-blockquote">
          <p>It's really good news that the new Bootstrap 4 now has support for CSS 3 flexbox.</p>
          <footer>Makes flexible layouts <cite title="Source Title">Faster</cite></footer>
        </blockquote>
      </div>
    </div>
    <div class="card card-inverse card-danger text-center col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-1">
      <div class="card-block">
        <blockquote class="card-blockquote">
          <p>The Bootstrap 3.x element that was called "Panel" before, is now called a "Card".</p>
          <footer>All of this makes more <cite title="Source Title">Sense</cite></footer>
        </blockquote>
      </div>
    </div>
    <div class="card card-inverse card-warning text-center col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-1">
      <div class="card-block">
        <blockquote class="card-blockquote">
          <p>There are also some interesting new text classes for uppercase and capitalize.</p>
          <footer>These handy utilities make it <cite title="Source Title">Easy</cite></footer>
        </blockquote>
      </div>
    </div>
    <div class="card card-inverse card-info text-center col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-1">
      <div class="card-block">
        <blockquote class="card-blockquote">
          <p>If you want to use cool icons in Bootstrap 4, you'll have to find your own such as Font Awesome or Ionicons.</p>
          <footer>The Glyphicons are not <cite title="Source Title">Included</cite></footer>
        </blockquote>
      </div>
    </div>
  </div>
</div>

【问题讨论】:

codeply.com/go/AP1MpYKY2H/bootstrap-4-card-deck-columns-per-row 【参考方案1】:

2018 年更新

如果您想要responsive card-deck,请使用可见性工具强制在不同视口宽度(断点)上的每 X 列换行...

Bootstrap 4 responsive card-deck (v 4.1)


Bootstrap 4 alpha 2 的原始答案:

您可以使用网格col-*-* 来获得不同的宽度(而不是卡片组),然后使用 flexbox 为列设置相同的高度。

.row > div[class*='col-'] 
  display: flex;
  flex:1 0 auto;

http://codeply.com/go/O0KdSG2YX2(阿尔法 2)

问题是没有启用 flexbox 的 card-deck 使用 table-cell 很难控制宽度。自 Bootstrap 4 Alpha 6 起,flexbox 是默认的,因此 flexbox 不需要额外的 CSS,并且 h-100 类可用于使卡片全高:http://www.codeply.com/go/gnOzxd4Spk


相关问题: Bootstrap 4 - Responsive cards in card-columns

【讨论】:

我忘了,在 Bootstrap 4 中是否默认启用了 flexbox? 知道了,想知道为什么它在我的小提琴中不起作用。我回家后必须玩它,这样我才能打开 flexbox... 知道如何使最后一行的卡片与其他行的宽度相同吗? 我从这个答案开始,制作这样的动态布局很复杂。更好地使用 .row.col 类进行响应。请参阅下面的答案。 我的回答已经说过要使用网格 col 而不是卡片组【参考方案2】:

这里有一个使用 Sass 的解决方案,可以根据断点配置每行的卡数:https://codepen.io/migli/pen/OQVRMw

它适用于 Bootstrap 4 beta 3

// Bootstrap 4 breakpoints & gutter
$grid-breakpoints: (
    xs: 0,
    sm: 576px,
    md: 768px,
    lg: 992px,
    xl: 1200px
) !default;

$grid-gutter-width: 30px !default;

// number of cards per line for each breakpoint
$cards-per-line: (
    xs: 1,
    sm: 2,
    md: 3,
    lg: 4,
    xl: 5
);

@each $name, $breakpoint in $grid-breakpoints 
    @media (min-width: $breakpoint) 
        .card-deck .card 
            flex: 0 0 calc(#100/map-get($cards-per-line, $name)% - #$grid-gutter-width);
        
    

编辑(2019/10)

我研究了另一个解决方案,它使用 horizo​​ntal lists group + flex utility 而不是 card-deck:

https://codepen.io/migli/pen/gOOmYLb

这是一种将任何类型的元素组织到响应式网格中的简单解决方案

<div class="container">
    <ul class="list-group list-group-horizontal align-items-stretch flex-wrap">
        <li class="list-group-item">Cras justo odio</li>
        <li class="list-group-item">Dapibus ac facilisis in</li>
        <li class="list-group-item">Morbi leo risus</li>
        <li class="list-group-item">Cras justo odio</li>
        <li class="list-group-item">Dapibus ac facilisis in</li>
        <!--= add as many items as you need  =-->
    </ul>
</div>
.list-group-item 
    width: 95%;
    margin: 1% !important;


@media (min-width: 576px) 
    .list-group-item 
        width: 47%;
        margin: 5px 1.5% !important;
    


@media (min-width: 768px) 
    .list-group-item 
        width: 31.333%;
        margin: 5px 1% !important;
    


@media (min-width: 992px) 
    .list-group-item 
        width: 23%;
        margin: 5px 1% !important;
    


@media (min-width: 1200px) 
    .list-group-item 
        width: 19%;
        margin: 5px .5% !important;
    

【讨论】:

@trainoasis 它对我来说并没有破坏任何东西。请参阅答案中的 CodePen 链接:codepen.io/migli/pen/OQVRMw。当我更改 $cards-per-line 时,卡片的数量也会相应地发生变化。 我明白了,你。也许我已经有太多的自定义 CSS 并且某处存在冲突。会尝试找到它。 它就像一个魅力,也适用于 bootstrap v 4.1.1。谢谢。 在除 IE 11 之外的任何地方都可以正常工作。任何解决方案? IE 肯定死了【参考方案3】:

我花了一点时间才弄明白,但答案是不使用卡片组,而是使用.row.cols。

这会生成一组响应式卡片,其中包含针对每种屏幕尺寸的详细信息:3 张卡片用于xl,2 张卡片用于lgmd,1 张卡片用于smxs.my-3 在顶部和底部放置了一个填充,这样它们看起来不错。

mixin postList(stuff)
  .row
    - site.posts.each(function(post, index)
      .col-sm-12.col-md-6.col-lg-6.col-xl-4
        .card.my-3
          img.card-img-top(src="...",  )
          .card-body
            h5.card-title Card title #index
            p.card-text Some quick example text to build on the card title and make up the bulk of the cards content.
            a.btn.btn-primary(href="#") Go somewhere
    - )

【讨论】:

这种方法不会像卡片组那样将卡片的高度设置为相等的高度。【参考方案4】:

对此有更简单的解决方案 - 设置卡片元素的固定高度 - 标题和正文。这样,我们可以使用标准的 boostrap 列网格设置响应式布局。

这是我的例子: http://codeply.com/go/RHDawRSBol

 <div class="card-deck text-center">
    <div class="col-sm-6 col-md-4 col-lg-3">
        <div class="card mb-4">
            <img class="card-img-top img-fluid" src="//placehold.it/500x280" >
            <div class="card-body" style="height: 20rem">
                <h4 class="card-title">1 Card title</h4>
                <p class="card-text">This is a longer card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
                <p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
            </div>
        </div>

【讨论】:

但这不是标准方式。 如果您这样做,您必须始终知道卡片中有多少内容。这不适用于动态内容。【参考方案5】:
<div class="w-100 d-lg-none mt-4"></div>

我创建了 4 张卡片,并将这段代码放在第二张和第三张卡片之间,试试这个。

【讨论】:

不错的解决方案,但要使其正常工作,您需要删除 d-lg-none 类,所以它应该是 &lt;div class="w-100 mt-4"&gt;&lt;/div&gt;【参考方案6】:

此答案适用于使用 Bootstrap 4.1+ 以及关心 IE 11 的用户

卡片组不会根据视口大小调整可见卡片的数量。

以上方法有效,但不支持 IE。通过以下方法,您可以实现类似的功能和响应卡。

您可以管理在不同断点中显示/隐藏的卡片数量。

在 Bootstrap 4.1+ 中,默认情况下列的高度相同,只需确保您的卡片/内容使用所有可用空间。 运行sn -p,你就明白了

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="container">
    <div class="row">
        <div class="col-sm-6 col-lg-4 mb-3">
            <div class="card mb-3 h-100">

                <div class="card-body">
                    <h5 class="card-title">Card title</h5>
                    <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
                    <p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
                </div>
            </div>
        </div>
        <div class="col-sm-6 col-lg-4 mb-3">
            <div class="card mb-3 h-100">
                <div class="card-body">
                    <h5 class="card-title">Card title</h5>
                    <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
                    <p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
                </div>
            </div>
        </div>
        <div class="col-sm-6 col-lg-4 mb-3">
            <div class="card mb-3 h-100">
                <div class="card-body">
                    <h5 class="card-title">Card title</h5>
                    <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
                    <p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
                </div>
            </div>
        </div>
    </div>
</div>

【讨论】:

问题需要使用 CardDeck 是的@IanWarner。我使用 CardDeck 并在上述答案中建议了更新,但幸运的是,我不得不支持 IE,但似乎没有任何效果,我使用这种方法解决了它。【参考方案7】:

我通过在卡片上添加 min-width 来实现这一点:

<div class="card mb-3" style="min-width: 18rem;">
  <p>Card content</p>
</div>

卡片不会低于此宽度,但仍能正确填满每一行并具有相等的高度。

【讨论】:

解决 Bootstrap 中一个重大问题的好方法 我也放了“...max-width: 22rem;”避免新行上的卡片太宽 这很完美,无需在 django 模板上创建疯狂的标签条件 这是最好的解决方案之一,简洁有效【参考方案8】:

我使用 CSS Grid 来解决这个问题。 CSS Grid 将使所有元素在同一行,高度相同。

我还没有考虑让所有行中的所有元素都具有相同的高度。

无论如何,这是可以做到的:

html

<div class="grid-container">

  <div class="card">...</div>
  <div class="card">...</div>
</div>

CSS:

.grid-container 
  display: grid;  
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

这是一个完整的 JSFiddle。 https://jsfiddle.net/bluegrounds/owjvhstq/4/

【讨论】:

【参考方案9】:

根据视口按最小宽度定义列:


    /* Number of Cards by Row based on Viewport */
    @media (min-width: 576px) 
        .card-deck .card 
            min-width: 50.1%; /* 1 Column */
            margin-bottom: 12px;
        
    

    @media (min-width: 768px) 
        .card-deck .card 
            min-width: 33.4%;  /* 2 Columns */
        
    

    @media (min-width: 992px) 
        .card-deck .card 
            min-width: 25.1%;  /* 3 Columns */
        
    

    @media (min-width: 1200px) 
        .card-deck .card 
            min-width: 20.1%;  /* 4 Columns */
        
    

【讨论】:

这是一个很好的解决方案。【参考方案10】:

@Zim 在上面提供了一个很好的解决方案(我当之无愧的投票),但是,它并不完全符合我的需要,因为我在 Jekyll 中实现了它并且希望我的卡片组每次添加时都会自动更新一个帖子到我的网站。在 Jekyll 中,随着每个新帖子发展出这样的卡片组是直截了当的,挑战在于正确放置断点。我的解决方案利用了额外的液体标签和模数学。

虽然这个问题很老,但我发现它并发现它很有用,也许有一天会有人想要和 Jekyll 一起做这个。

<div class = "container">
  <div class = "card-deck">

    % for post in site.posts %
      <div class = "card border-0 mt-2">
        <a href = " post.url "><img src = " site.baseurl  post.image " class = "mx-auto" alt = "..."></a>
        <div class = "card-body">
          <h5 class = "card-title"><a href = " post.url "> post.title </a></h5>
          <span>Published:  post.date | date_to_long_string  </span>
          <p class = "text-muted"> post.excerpt </p>
        </div>
        <div class = "card-footer bg-white border-0"><a href = " post.url " class = "btn btn-primary">Read more</a></div>
      </div>

      <!-- Use modulo to add divs to handle break points -->
      % assign sm = forloop.index | modulo: 2 %
      % assign md = forloop.index | modulo: 3 %
      % assign lg = forloop.index | modulo: 4 %
      % assign xl = forloop.index | modulo: 5 %

      % if sm == 0 %
        <div class="w-100 d-none d-sm-block d-md-none"><!-- wrap every 2 on sm--></div>
      % endif %

      % if md == 0 %
        <div class="w-100 d-none d-md-block d-lg-none"><!-- wrap every 3 on md--></div>
      % endif %

      % if lg == 0 %
        <div class="w-100 d-none d-lg-block d-xl-none"><!-- wrap every 4 on lg--></div>
      % endif %

      % if xl == 0 %
        <div class="w-100 d-none d-xl-block"><!-- wrap every 5 on xl--></div>
      % endif %

    % endfor %
  </div>
</div>

整个代码块可以直接在网站中使用,也可以保存在您的 Jekyll 项目_includes 文件夹中。

【讨论】:

【参考方案11】:

使用 Bootstrap 4.4.1,我可以通过添加一些 scss 来使用简单的类来设置每副牌的数量。

HTML

<div class="card-deck deck-1 deck-md-2 deck-lg-3">
   <div class="card">
      <h2 class="card-header">Card 1</h3>
      <div class="card-body">
          Card body
      </div>
      <div class="card-footer">
          Card footer
      </div>
   </div>
   <div class="card">
      <h2 class="card-header">Card 2</h3>
      <div class="card-body">
          Card body
      </div>
      <div class="card-footer">
          Card footer
      </div>
   </div>
   <div class="card">
      <h2 class="card-header">Card 3</h3>
      <div class="card-body">
          Card body
      </div>
      <div class="card-footer">
          Card footer
      </div>
   </div>
</div>

SCSS

// _card_deck_columns.scss
// add deck-X and deck-BP-X classes to select the number of cards per line
@for $i from 1 through $grid-columns 
  .deck-#$i > .card 
    $percentage: percentage(1 / $i);
    @if $i == 1 
      $width: $percentage;
      flex-basis: $width;
      max-width: $width;
      margin-left: 0;
      margin-right: 0;
     @else 
      $width: unquote("calc(#$percentage - #$grid-gutter-width)");
      flex-basis: $width;
      max-width: $width;
    
  

@each $breakpoint in map-keys($grid-breakpoints) 
  $infix: breakpoint-infix($breakpoint, $grid-breakpoints);
  @include media-breakpoint-up($breakpoint) 
    @for $i from 1 through $grid-columns 
      .deck#$infix-#$i > .card 
        $percentage: percentage(1 / $i);
        @if $i == 1 
          $width: $percentage;
          flex-basis: $width;
          max-width: $width;
          margin-left: 0;
          margin-right: 0;
         @else 
          $width: unquote("calc(#$percentage - #$grid-gutter-width)");
          flex-basis: $width;
          max-width: $width;
          margin-left: $grid-gutter-width / 2;
          margin-right: $grid-gutter-width / 2;
        
      
    
  

CSS

.deck-1 > .card 
  flex-basis: 100%;
  max-width: 100%;
  margin-left: 0;
  margin-right: 0; 

.deck-2 > .card 
  flex-basis: calc(50% - 30px);
  max-width: calc(50% - 30px); 

.deck-3 > .card 
  flex-basis: calc(33.3333333333% - 30px);
  max-width: calc(33.3333333333% - 30px); 

.deck-4 > .card 
  flex-basis: calc(25% - 30px);
  max-width: calc(25% - 30px); 

.deck-5 > .card 
  flex-basis: calc(20% - 30px);
  max-width: calc(20% - 30px); 

.deck-6 > .card 
  flex-basis: calc(16.6666666667% - 30px);
  max-width: calc(16.6666666667% - 30px); 

.deck-7 > .card 
  flex-basis: calc(14.2857142857% - 30px);
  max-width: calc(14.2857142857% - 30px); 

.deck-8 > .card 
  flex-basis: calc(12.5% - 30px);
  max-width: calc(12.5% - 30px); 

.deck-9 > .card 
  flex-basis: calc(11.1111111111% - 30px);
  max-width: calc(11.1111111111% - 30px); 

.deck-10 > .card 
  flex-basis: calc(10% - 30px);
  max-width: calc(10% - 30px); 

.deck-11 > .card 
  flex-basis: calc(9.0909090909% - 30px);
  max-width: calc(9.0909090909% - 30px); 

.deck-12 > .card 
  flex-basis: calc(8.3333333333% - 30px);
  max-width: calc(8.3333333333% - 30px); 

.deck-1 > .card 
  flex-basis: 100%;
  max-width: 100%;
  margin-left: 0;
  margin-right: 0; 

.deck-2 > .card 
  flex-basis: calc(50% - 30px);
  max-width: calc(50% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-3 > .card 
  flex-basis: calc(33.3333333333% - 30px);
  max-width: calc(33.3333333333% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-4 > .card 
  flex-basis: calc(25% - 30px);
  max-width: calc(25% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-5 > .card 
  flex-basis: calc(20% - 30px);
  max-width: calc(20% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-6 > .card 
  flex-basis: calc(16.6666666667% - 30px);
  max-width: calc(16.6666666667% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-7 > .card 
  flex-basis: calc(14.2857142857% - 30px);
  max-width: calc(14.2857142857% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-8 > .card 
  flex-basis: calc(12.5% - 30px);
  max-width: calc(12.5% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-9 > .card 
  flex-basis: calc(11.1111111111% - 30px);
  max-width: calc(11.1111111111% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-10 > .card 
  flex-basis: calc(10% - 30px);
  max-width: calc(10% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-11 > .card 
  flex-basis: calc(9.0909090909% - 30px);
  max-width: calc(9.0909090909% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

.deck-12 > .card 
  flex-basis: calc(8.3333333333% - 30px);
  max-width: calc(8.3333333333% - 30px);
  margin-left: 15px;
  margin-right: 15px; 

@media (min-width: 576px) 
  .deck-sm-1 > .card 
    flex-basis: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0; 

  .deck-sm-2 > .card 
    flex-basis: calc(50% - 30px);
    max-width: calc(50% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-3 > .card 
    flex-basis: calc(33.3333333333% - 30px);
    max-width: calc(33.3333333333% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-4 > .card 
    flex-basis: calc(25% - 30px);
    max-width: calc(25% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-5 > .card 
    flex-basis: calc(20% - 30px);
    max-width: calc(20% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-6 > .card 
    flex-basis: calc(16.6666666667% - 30px);
    max-width: calc(16.6666666667% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-7 > .card 
    flex-basis: calc(14.2857142857% - 30px);
    max-width: calc(14.2857142857% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-8 > .card 
    flex-basis: calc(12.5% - 30px);
    max-width: calc(12.5% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-9 > .card 
    flex-basis: calc(11.1111111111% - 30px);
    max-width: calc(11.1111111111% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-10 > .card 
    flex-basis: calc(10% - 30px);
    max-width: calc(10% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-11 > .card 
    flex-basis: calc(9.0909090909% - 30px);
    max-width: calc(9.0909090909% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-sm-12 > .card 
    flex-basis: calc(8.3333333333% - 30px);
    max-width: calc(8.3333333333% - 30px);
    margin-left: 15px;
    margin-right: 15px;  
@media (min-width: 768px) 
  .deck-md-1 > .card 
    flex-basis: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0; 

  .deck-md-2 > .card 
    flex-basis: calc(50% - 30px);
    max-width: calc(50% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-3 > .card 
    flex-basis: calc(33.3333333333% - 30px);
    max-width: calc(33.3333333333% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-4 > .card 
    flex-basis: calc(25% - 30px);
    max-width: calc(25% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-5 > .card 
    flex-basis: calc(20% - 30px);
    max-width: calc(20% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-6 > .card 
    flex-basis: calc(16.6666666667% - 30px);
    max-width: calc(16.6666666667% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-7 > .card 
    flex-basis: calc(14.2857142857% - 30px);
    max-width: calc(14.2857142857% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-8 > .card 
    flex-basis: calc(12.5% - 30px);
    max-width: calc(12.5% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-9 > .card 
    flex-basis: calc(11.1111111111% - 30px);
    max-width: calc(11.1111111111% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-10 > .card 
    flex-basis: calc(10% - 30px);
    max-width: calc(10% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-11 > .card 
    flex-basis: calc(9.0909090909% - 30px);
    max-width: calc(9.0909090909% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-md-12 > .card 
    flex-basis: calc(8.3333333333% - 30px);
    max-width: calc(8.3333333333% - 30px);
    margin-left: 15px;
    margin-right: 15px;  
@media (min-width: 992px) 
  .deck-lg-1 > .card 
    flex-basis: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0; 

  .deck-lg-2 > .card 
    flex-basis: calc(50% - 30px);
    max-width: calc(50% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-3 > .card 
    flex-basis: calc(33.3333333333% - 30px);
    max-width: calc(33.3333333333% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-4 > .card 
    flex-basis: calc(25% - 30px);
    max-width: calc(25% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-5 > .card 
    flex-basis: calc(20% - 30px);
    max-width: calc(20% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-6 > .card 
    flex-basis: calc(16.6666666667% - 30px);
    max-width: calc(16.6666666667% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-7 > .card 
    flex-basis: calc(14.2857142857% - 30px);
    max-width: calc(14.2857142857% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-8 > .card 
    flex-basis: calc(12.5% - 30px);
    max-width: calc(12.5% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-9 > .card 
    flex-basis: calc(11.1111111111% - 30px);
    max-width: calc(11.1111111111% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-10 > .card 
    flex-basis: calc(10% - 30px);
    max-width: calc(10% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-11 > .card 
    flex-basis: calc(9.0909090909% - 30px);
    max-width: calc(9.0909090909% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-lg-12 > .card 
    flex-basis: calc(8.3333333333% - 30px);
    max-width: calc(8.3333333333% - 30px);
    margin-left: 15px;
    margin-right: 15px;  
@media (min-width: 1200px) 
  .deck-xl-1 > .card 
    flex-basis: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0; 

  .deck-xl-2 > .card 
    flex-basis: calc(50% - 30px);
    max-width: calc(50% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-3 > .card 
    flex-basis: calc(33.3333333333% - 30px);
    max-width: calc(33.3333333333% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-4 > .card 
    flex-basis: calc(25% - 30px);
    max-width: calc(25% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-5 > .card 
    flex-basis: calc(20% - 30px);
    max-width: calc(20% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-6 > .card 
    flex-basis: calc(16.6666666667% - 30px);
    max-width: calc(16.6666666667% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-7 > .card 
    flex-basis: calc(14.2857142857% - 30px);
    max-width: calc(14.2857142857% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-8 > .card 
    flex-basis: calc(12.5% - 30px);
    max-width: calc(12.5% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-9 > .card 
    flex-basis: calc(11.1111111111% - 30px);
    max-width: calc(11.1111111111% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-10 > .card 
    flex-basis: calc(10% - 30px);
    max-width: calc(10% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-11 > .card 
    flex-basis: calc(9.0909090909% - 30px);
    max-width: calc(9.0909090909% - 30px);
    margin-left: 15px;
    margin-right: 15px; 

  .deck-xl-12 > .card 
    flex-basis: calc(8.3333333333% - 30px);
    max-width: calc(8.3333333333% - 30px);
    margin-left: 15px;
    margin-right: 15px;  

【讨论】:

以上是关于具有基于视口的列数的 Bootstrap 4 卡片组的主要内容,如果未能解决你的问题,请参考以下文章

Bootstrap 4(Alpha 3):卡片列 - 自定义列数

具有每行动态列数的 Android GridLayout

使用与具有不同列数的另一个QGridLayout相同的列间距

具有不同列数的数据表

合并具有不同列数的表

具有动态列数的 QML TableView