【问题标题】:Using text-overflow: ellipsis with flexbox使用文本溢出:带有弹性框的省略号
【发布时间】:2019-06-19 20:34:24
【问题描述】:

我正在构建一个购物车页面,并希望列出产品的图片、标题、价格和一个表单元素以将其从购物车中删除。

我尝试在我想要截断的元素上同时使用white-space: nowrap;overflow: hidden;text-overflow: ellipsis;,但我不知道如何正确显示它们,尤其是使用img-container 和@987654329 @ 使用弹性框。

这是我的 Django 模板:

<ul>
    {% for product in products %}
    <li class="row product">
        <div class="img-container">
            <a href="{% url 'gallery:product_page' %}?id={{ product.id }}">
                <img src="{{ product.image.url }}" alt="{{ product.name }}">
            </a>
        </div>
        <div class="name-price-container">
            <span>
                <a href="{% url 'gallery:product_page' %}?id={{ product.id }}">{{ product.name }} Loooooooooong Text</a>
            </span>
            <span>${{ product.price_per_unit }}</span>
        </div>
        <div class="btn-container">
            <form method="POST" action="{% url 'gallery:remove_cart' %}">
                {% csrf_token %}
                <input type="hidden" name="id" value="{{ product.id }}">
                <input type="submit" class="btn btn-light" value="Remove">
            </form>
        </div>
    </li>
    {% endfor %}
</ul>

...以及相关的 CSS:

.product .img-container {
  background-color: #343a40;
  border: 1px solid #343a40;
  box-sizing: unset;
  height: 128px;
  width: 128px;
  flex: 0 0 auto;
}
.product .img-container img {
  display: block;
  max-height: 128px;
  max-width: 128px;
  width: auto;
  height: auto;
}
.name-price-container {
  margin: 0 1rem;
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}
.name-price-container a {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.btn-container {
  float: right;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.btn-container .btn {
  margin: 0;
}
@media all and (max-width: 768px) {
  body * {
    overflow: hidden;
  }
  .product .img-container {
    height: 64px;
    width: 64px;
  }
  .product .img-container img {
    max-width: 64px;
    max-height: 64px;
  }
}

...以及 470px 宽度的渲染: Image here

请注意,第一个和第三个结果正确呈现,但如果文本比页面上的长度长,表单元素不会被截断,而是换行。

感谢任何帮助。

编辑:这是根据 Andrei 的评论更新后的 jsfiddle

【问题讨论】:

  • “相关 CSS” 表示 this 呈现与您的图像相同的效果。你还没有接近相关。请提供minimal reproducible example。如果您单独提供 HTML 和 CSS,您的问题很容易得到解答,因为它严格来说是一个与样式相关的问题。提示:右键单击并选择“查看页面源代码”以从您的应用程序中复制/粘贴相关的 HTML,并更新您的 CSS 以在您的应用程序中呈现元素。您还可以从 cdn 添加外部资源。
  • 检查编辑以获取更新的示例。

标签: html django twitter-bootstrap css


【解决方案1】:

为了获得所需的行为,您需要进行几项更改。首先,您需要了解您正在处理 flexbox 中的负空间场景。那是当内容长度的总和大于可用的父长度时。
在这种情况下,flexbox 计算它们之间的差异,并尝试根据每个孩子的flex-shrink 因子在允许flex-shrink 的孩子之间平均分配差异。

所以你需要将.name-price-containerflex-shrink设置为1

 .name-price-container {
    flex: 1 1 auto;
 }

没有它,省略号就不会发生,因为内容(您的&lt;a&gt;)将始终根据需要增长,因此设置width,因此设置flex-basis.name-price-container(其中目前无法缩小)。因此,没有省略号。


您的第二个问题是&lt;a&gt; 元素,默认情况下有displayinline。为了使省略号起作用,您需要一种限制其宽度的方法。最简单的方法是给它display:block(因为现在父级缩小了)。另一种方法是将省略号效果移动到span 并给出该跨度width: 100%

最后,您要防止.btn-container 缩小并删除它的overflow。给它flex-shrink: 0 并从中删除overflow: hidden

顺便说一句,body * { overflow: hidden; }确实是您要避免的,因为它会覆盖页面中每个元素的默认值 overflow。如果你改变它,有很多元素将不再按预期工作。下拉菜单、工具提示、弹出框和模态框等等。

这是您的工作示例:

@import url('https://fonts.googleapis.com/css?family=Open+Sans');
* {
  font-family: 'Open Sans', Helvetica, Arial, sans-serif;
}
body {
  background-color: #e6ebf0;
}
ul {
  padding-left: 0;
}
ul li {
  list-style: none;
}
ul li img {
  width: 100%;
}
.img-container {
  background-color: #343a40;
  border: 1px solid #343a40;
	display: flex;
	flex: 1 0 auto;
	flex-direction: column;
  justify-content: center;
  align-items: center;
}
form {
  display: inline;
}
.btn-light {
  background-color: white;
  border: 1px solid #ced4da;
}
.row {
  margin: 0;
}
.product {
  display: flex;
}
.product,
.total {
  margin-top: 0.5rem;
  padding: 1rem;
  background-color: white;
  border: 1px solid #ced4da;
  border-radius: 4px;
}
.product .img-container {
  background-color: #343a40;
  border: 1px solid #343a40;
  box-sizing: unset;
  height: 128px;
  width: 128px;
  flex: 0 0 auto;
}
.product .img-container img {
  display: block;
  max-height: 128px;
  max-width: 128px;
  width: auto;
  height: auto;
}
.name-price-container {
  margin: 0 1rem;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}
.name-price-container a {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.name-price-container a,
.name-price-container a:hover {
  color: #212529;
}
.btn-container {
  height: 130px;
  line-height: 130px;
  min-width: 0;
  white-space: nowrap;
}
.btn-container .btn {
  margin: 0;
  display: inline-block;
}
@media all and (max-width: 768px) {
  .product .img-container {
    height: 64px;
    width: 64px;
  }
  .product .img-container img {
    max-width: 64px;
    max-height: 64px;
  }
  .btn-container {
    height: 66px;
    line-height: 66px;
    flex-shrink: 0;
  }
}
<div class="container">
    <ul>
        
        <li class="row product">
            <div class="img-container">
                <a href="/gallery/product?id=21">
                    <img src="https://i.imgur.com/CyYN9a7.jpg" alt="Vials">
                </a>
            </div>
            <div class="name-price-container">
                <span>
                    <a href="/gallery/product?id=21">Vials Loooooooooong Text</a>
                </span>
                <span>$30.00</span>
            </div>
            <div class="btn-container">
                <form method="POST" action="/gallery/remove_cart">
                    <input type="hidden" name="csrfmiddlewaretoken" value="...">
                    <input type="hidden" name="id" value="21">
                    <input type="submit" class="btn btn-light" value="Remove">
                </form>
            </div>
        </li>
        
        <li class="row product">
            <div class="img-container">
                <a href="/gallery/product?id=22">
                    <img src="https://i.imgur.com/PoCaEjw.jpg" alt="Driftbird">
                </a>
            </div>
            <div class="name-price-container">
                <span>
                    <a href="/gallery/product?id=22">Driftbird Loooooooooong Text</a>
                </span>
                <span>$25.00</span>
            </div>
            <div class="btn-container">
                <form method="POST" action="/gallery/remove_cart">
                    <input type="hidden" name="csrfmiddlewaretoken" value="...">
                    <input type="hidden" name="id" value="22">
                    <input type="submit" class="btn btn-light" value="Remove">
                </form>
            </div>
        </li>
        
        <li class="row product">
            <div class="img-container">
                <a href="/gallery/product?id=19">
                    <img src="https://i.imgur.com/KxAyAyE.jpg" alt="Dragon">
                </a>
            </div>
            <div class="name-price-container">
                <span>
                    <a href="/gallery/product?id=19">Dragon Loooooooooong Text</a>
                </span>
                <span>$300.00</span>
            </div>
            <div class="btn-container">
                <form method="POST" action="/gallery/remove_cart">
                    <input type="hidden" name="csrfmiddlewaretoken" value="...">
                    <input type="hidden" name="id" value="19">
                    <input type="submit" class="btn btn-light" value="Remove">
                </form>
            </div>
        </li>
        
    </ul>
</div>

更新fiddle here

【讨论】:

  • 谢谢安德烈,您发布的更新小提琴完全符合我的预期。但是,在 Bootstrap 的 row 类中使用它会出现问题。我发现我最初包含的类破坏了截断行为,但删除它解决了这个问题。
【解决方案2】:

我知道您的问题专门提到了 flexbox,但在这种情况下我会使用 display: gridGrid 将允许您更准确地定义列,保持行中每个内容部分之间的空间,并在网格区域内截断该内容。

这也将使您无需将浮动与 flexbox 一起使用,这可能会产生意想不到的后果。因为它在任何大小的行和列中保持内容的明确定义,所以网格是您在此处所做的最合适的显示选项。

它可能看起来像这样:

.product { //each .product container will contain 1 row with 3 columns
  display: grid;
  grid-gap: 1rem; //this adds a gap between the sections of your row
  grid-template: "image info button" 128px / 128px auto 128px; //i assumed your button is 128px wide
}

.product .img-container {
  background-color: #343a40;
  border: 1px solid #343a40;
  box-sizing: unset;
  grid-area: image; //this places the .img-container div within the "image" grid area defined above in grid-template
  height: 128px;
  width: 128px;
}
.product .img-container img {
  display: block;
  max-height: 128px;
  max-width: 128px;
  width: auto;
  height: auto;
}
.name-price-container {
  display: flex;
  flex-direction: column;
  grid-area: info; //this places the .img-container div within the "info" grid area
  justify-content: center;
  min-width: 0;
}
.name-price-container span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.btn-container {
  display: flex;
  flex-direction: column;
  grid-area: button; //this places the .img-container div within the "button" grid area
  justify-content: center;
}
.btn-container .btn {
  margin: 0;
}
@media all and (max-width: 768px) {
  body * {
    overflow: hidden;
  }
  .product {
    grid-template: "image info button" 64px / 64px auto 128px;
  }
  .product .img-container {
    height: 64px;
    width: 64px;
  }
  .product .img-container img {
    max-width: 64px;
    max-height: 64px;
  }
}

请参阅 this codepen 以了解此操作的示例。

有一种方法可以用 flexbox 完成您想要做的事情,但它并不那么容易维护。如果您花时间将其转换为网格,您将拥有更可靠的布局。如果你尝试这段代码,你会发现

请注意,-ms 供应商前缀来实现网格布局有一些特殊的技巧。 Here 是一篇很棒的文章,详细介绍了您可以使用的一些技巧(以及一个自动将您的 CSS 转换为与 IE11 兼容的模块)。

我希望这会有所帮助!

【讨论】:

  • 这很好,只是它不会像我要求的那样截断文本。
  • @user2858094 - 抱歉,刚刚添加了截断。您只需要将截断样式添加到包裹锚点的跨度中,而不是锚点本身,然后将 min-width: 0 添加到 .name-price-container 的容器中(就像在 flexbox 中一样)。如果您遇到问题,请告诉我!
  • 在这种情况下我最终坚持使用 flexbox,因为 Andrei 发布了一个不涉及重构我的代码的简单解决方案,但是您发布的 CSS Tricks 链接将非常有帮助,谢谢。
  • Andrei 有一个出色的解决方案,它教会了我很多关于 flexbox 的知识。很高兴他能帮助你!
猜你喜欢
  • 2022-07-19
  • 2021-12-17
  • 2020-09-15
  • 1970-01-01
  • 2017-05-08
  • 2017-02-11
  • 2018-07-22
  • 1970-01-01
  • 2019-11-25
相关资源
最近更新 更多