Усекать текст в середине ряда divs
У меня есть компонент, который в настоящее время отобразит что-то, что выглядит следующим образом:
Corvid/ Игры/ World of Warcraft/ Активы/ Модели символов/ Альянс/ Ночной эльф/ Малфурион
Я всегда хочу, чтобы первые два элемента и последние два элемента были видимыми, однако я хочу, чтобы все в середине обрезалось в ...
, если это было возможно. То есть, если строка, указанная выше, должна переполнять содержащую div, она должна иметь следующий результат:
Corvid/ Игры/.../ Ночной эльф/ Малфурион
Я пробовал сделать структуру следующим образом:
<div className={styles.container}>
<div className={styles.first}>
{/** Contains first two items */}
</div>
<div className={styles.truncate}>
{/** N arbitrary path items */}
</div>
<div className={styles.last}>
{/** Last two items */}
</div>
</div>
Можно ли это сделать с помощью CSS?
Ответы
Ответ 1
Интересная проблема - к сожалению, я не вижу надежного решения только для CSS. То есть, если структура HTML не может быть отредактирована, и даже тогда будет некоторая жесткая кодировка, я не верю, что есть надежное решение только для CSS.
Однако здесь есть 3 потенциальных решения:
- Простая функция служебной программы JavaScript
- Функциональный (безгосударственный) компонент реагирования
- Компонент с учетом состояния
1. Функция JavaScript
В приведенном ниже примере я создал функцию truncateBreadcrumbs()
, которая принимает 3 параметра:
-
selector
- селектор CSS, соответствующий элементам, которые вы хотите усекать
-
separator
- символ, используемый для разделения элементов
-
segments
- количество сегментов, которые вы хотите усечь строку, чтобы
Его можно использовать как:
truncateBreadcrumbs(".js-truncate", "/", 4);
который найдет все элементы с классом .js-truncate
и усечет содержимое до 4 элементов с разделителем ...
в середине, например:
Corvid / Games / ... / Night Elf / Malfurion
Также могут использоваться нечетные числа сегментов, например 5
будет генерировать:
Corvid / Games / World of Warcraft / ... / Night Elf / Malfurion
Если аргумент segment
равен или больше числа элементов, не происходит усечения.
И вот полный рабочий пример:
function truncateBreadcrumbs(selector, separator, segments) {
const els = Array.from(document.querySelectorAll(selector));
els.forEach(el => {
const split = Math.ceil(segments / 2);
const elContent = el.innerHTML.split(separator);
if (elContent.length <= segments) {
return;
}
el.innerHTML = [].concat(
elContent.slice(0, split),
["..."],
elContent.slice(-(segments-split))
).join(` ${separator} `);
});
}
truncateBreadcrumbs(".js-truncate--2", "/", 2);
truncateBreadcrumbs(".js-truncate--4", "/", 4);
truncateBreadcrumbs(".js-truncate--5", "/", 5);
<div class="js-truncate--2">Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion</div>
<div class="js-truncate--4">Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion</div>
<div class="js-truncate--5">Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion</div>
<div class="js-truncate--4">Corvid / Games / Night Elf / Malfurion</div>
Ответ 2
Это один из способов для него, хорошо работает только в том случае, если всегда есть более 4 элементов.
ul { list-style-type: none; }
ul li { display: none; }
ul li:nth-last-child(n+2):after { content: " / "; }
ul li:nth-child(2):after { content: " / ... /"; }
ul li:nth-child(-n+2), ul li:nth-last-of-type(-n+2) { display: inline-block; }
<ul>
<li><a href="#">Corvid</a></li>
<li><a href="#">Games</a></li>
<li><a href="#">World of Warcraft</a></li>
<li><a href="#">Assets</a></li>
<li><a href="#">Character Models</a></li>
<li><a href="#">Alliance</a></li>
<li><a href="#">Night Elf</a></li>
<li><a href="#">Malfurion</a></li>
</ul>
Ответ 3
.enumeration > div{display:inline-block;font-size:150%}
.enumeration > div:after{content: " / ";color:blue;font-weight:bold;}
.enumeration > div:nth-child(n+3) {display:none;}
.enumeration > div:nth-child(n+2):after {content: " / ... / ";color: red;}
.enumeration > div:nth-last-child(-n+2) {display:inline-block;}
.enumeration > div:nth-last-child(-n+3):after{content:" / ";color:green;}
.enumeration > div:nth-last-child(-n+2):after{content:" / ";color:orange;}
.enumeration > div:last-child:after{content:""}
Немного сложно, но это только css и работает с любым размером списка.:)
(Цвета и жирный шрифт - это просто, чтобы упростить просмотр, где применяется каждый селектор.)
- отображение "/" после каждого элемента
- Не показывать элементы после второго элемента
- отобразите "/.../" после элемента из второго
- отображать последние два элемента (они скрыты в 2)
- отображение "/" после третьего элемента с конца
- отображение "/" после второго элемента с конца
- не отображаются "/" после последнего элемента.
.enumeration > div{display:inline-block;font-size:150%}
.enumeration > div:after{content: " / ";color:blue;font-weight:bold;} /*1*/
.enumeration > div:nth-child(n+3) {display:none;}/*2*/
.enumeration > div:nth-child(n+2):after {content: " / ... / ";color: red;}/*3*/
.enumeration > div:nth-last-child(-n+2) {display:inline-block;}/*4*/
.enumeration > div:nth-last-child(-n+3):after{content:" / ";color:green;}/*5*/
.enumeration > div:nth-last-child(-n+2):after{content:" / ";color:orange;}/*6*/
.enumeration > div:last-child:after{content:""}/*7*/
<h2>
More than 4 items list
</h2>
<div class="enumeration">
<div>item 1</div>
<div>item 2</div>
<div>item 3</div>
<div>item 4</div>
<div>item 5</div>
<div>item 6</div>
<div>item 7</div>
<div>item 8</div>
<div>item 9</div>
</div>
<h2>
4 items list
</h2>
<div class="enumeration">
<div>item 1</div>
<div>item 2</div>
<div>item 3</div>
<div>item 4</div>
</div>
<h2>
3 items list
</h2>
<div class="enumeration">
<div>item 1</div>
<div>item 2</div>
<div>item 3</div>
</div>
<h2>
2 items list
</h2>
<div class="enumeration">
<div>item 1</div>
<div>item 2</div>
</div>
<h2>
1 item list
</h2>
<div class="enumeration">
<div>item 1</div>
</div>
Ответ 4
Я выставил это доказательство концепции, используя псевдоэлементы и медиа-запросы. Запустите фрагмент на полной странице и измените ширину на менее 500 пикселей.
Я узнал, что медиа-запросы не могут применяться к ширине отдельных элементов, поэтому это может быть не так полезно, вам придется настроить max-width
на реальное значение, основанное на ширине браузера.
DIV.truncate::before {
content: 'World of Warcraft / Assets / Character Models / Alliance';
}
@media (max-width: 500px) {
DIV.truncate::before {
content: '...';
}
}
DIV.container {
font-weight: bold;
font-family: Arial, sans-serif;
font-size: 14px;
white-space: nowrap;
overflow-x: auto;
}
DIV.container>DIV {
display: inline-block;
}
<div class="container">
<div class="first">Corvid / Games /</div>
<div class="truncate"></div>
<div class="last">/ Night Elf / Malfurion</div>
</div>
Ответ 5
Вы можете использовать комбинацию flex и truncate text:
.grid-container {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
width: 320px;
margin-top: 30vh;
margin-right: auto;
margin-left: auto;
}
.grid-item {
overflow: hidden;
height: 1.5em;
line-height: 1.5em;
}
.grid-item.expand {
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
}
<div class="grid-container">
<div class="grid-item" style="background: red">Corvid / Games </div>
<div class="expand grid-item">/ World of Warcraft / Assets / Character Models / Alliance </div>
<div class="grid-item" style="background: blue">/ Night Elf / Malfurion</div>
</div>
Ответ 6
Это использует методы, которые я получил от Lea Verou
См. https://codepen.io/HerrSerker/pen/JOaqjL для примера SCSS
ul.breadcrumb, ul.breadcrumb > li {
list-style: none;
margin: 0;
padding: 0;
}
ul.breadcrumb > li {
display: inline-block;
}
/* this adds the slash between the `<li>` */
ul.breadcrumb > li:not(:last-child):after {
content: ' /';
}
/* this is the second `<li>`, but only if there are 5 or more `<li>` */
/* 5 = 2 + 4 - 1 */
ul.breadcrumb > li:nth-child(2):nth-last-child(n+4):after {
content: ' / … /';
}
/* these are `<li>` No. 3 up to 3rd to last `<li>`, but only if there are 5 or more `<li>` */
/* 5 = 3 + 3 - 1 */
ul.breadcrumb > li:nth-child(n+3):nth-last-child(n+3) {
display: none;
}
<ul class="breadcrumb">
<li>Corvid</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
<li>Character Models</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
<li>Character Models</li>
<li>Alliance</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
<li>Character Models</li>
<li>Alliance</li>
<li>Night Elf</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
<li>Character Models</li>
<li>Alliance</li>
<li>Night Elf</li>
<li>Malfurion</li>
</ul>