Динамический горизонтальный список с линиями переменной ширины и содержимым между узлами

У меня есть система, которая генерирует список узлов, которые могут иметь или не иметь дополнительные элементы между узлами. Я хочу визуализировать этот список горизонтально с линиями, соединяющими узлы, как показано в примере ниже.

Содержимое между двумя узлами является переменным и может даже содержать более сложные элементы, такие как изображения и таблицы. Сами узлы помечаются только текстом (точка A, точка B и т. д.).

Динамический горизонтальный список с линиями переменной ширины и содержимым между узлами

Код и что я пробовал до сих пор

В моей первой попытке визуализировать узлы я просто использовал вертикальный список с псевдоэлементами :before и :after CSS, чтобы нарисовать линии между узлами. Однако мне трудно перевести этот подход в горизонтальный список.

Горизонтальный подход: (обновлено благодаря Ответ Маянка Гупты ниже)

h1, h2 {
	margin: 0;
	padding: 0;
}
ul {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	flex-direction: row;
	text-align: center;
	list-style-type: none;
	font-size: 1.5em;
}
ul li {
	display: flex;
	justify-content: flex-start;
	flex: 2;
	position: relative;
	border-bottom: 2px solid #000;
	padding-bottom: 10px;
}
ul li:after {
	position: absolute;
	bottom: -5px;
	left: 0;
	font-family: "Font Awesome 5 Free";
	font-weight: 300;
	content: "\f111";
	height: 17px;
	width: 23px;
	background: #fff;
}
ul h2 {
	margin: 0 0 0 -1em;
	padding: 0;
}
ul li:last-of-type {
	border: none;
}
ul li > div {
	flex: 0 0 auto;
	position: absolute;
	left: 50%;
	transform: translateX(-50%);
}
<link href = "https://use.fontawesome.com/releases/v5.5.0/css/all.css" rel = "stylesheet"/>
<ul>
	<li>
		<h2>Node A</h2>
		<div>Content</div>
	</li>
	<li>
		<h2>Node B</h2>
		<div>Content</div>
	</li>
	<li>
		<h2>Node C</h2>
	</li>
</ul>

Проблемы с этим методом:

  • Все узлы имеют одинаковую ширину, из-за чего последний узел бесполезно занимает место (последний узел никогда не имеет содержимого для отображения), по сути, это не позволяет списку использовать все доступное горизонтальное пространство (или, по крайней мере, кажущееся);
  • Строка чувствительна к изменениям размера шрифта, что приводит к ее смещению;
  • Метки узлов центрируются с использованием отрицательного смещения, вероятно, это не лучший метод;
  • Элемент div содержимого вынесен из потока документа, чтобы центрировать его между узлами, что потенциально позволяет ему перекрывать метки узлов, как в этом примере.

Как я могу решить эти проблемы?

Ограничения

  • Я поддерживаю только последние версии современных браузеров, поэтому для старых браузеров совместимость не требуется;
  • Я предпочитаю подход только с HTML(5) и CSS
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
0
0
732
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Попробуйте этот код

h1, h2 {
	margin: 0;
	padding: 0;
}
ul {
	display: flex;
  align-items: center;
}
ul li {
	       position: relative;
    width: 33%;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    flex-direction: column;
    border-bottom: 1px solid #ddd;
    padding-bottom: 10px;
}
ul li:after {
	position: absolute;
    bottom: -10px;
    left: 0;
    font-family: "Font Awesome 5 Free";
    font-weight: 300;
    content: "\f111";
    height: 17px;
    width: 17px;
    background: #fff;
}
<link href = "https://use.fontawesome.com/releases/v5.5.0/css/all.css" rel = "stylesheet"/>
<ul>
	<li>
		<h2>Node A</h2>
		<div>Content</div>
	</li>
	<li>
		<h2>Node B</h2>
		<div>Content</div>
	</li>
	<li>
		<h2>Node C</h2>
		<div>Content</div>
	</li>
</ul>

Привет, спасибо за ваш вклад! Это помогло мне приблизиться к моей цели, однако теперь я столкнулся с рядом новых проблем. Я обновил свой вопрос выше, у вас есть идеи, как их решить?

Thomas 14.07.2019 11:57

Это несколько отвечает на ваш вопрос [*] [* = однако я написал большую часть этого кода до того, как прочитал ваше первое изображение, не увидев содержимое h2/div].

Основная часть ответа — это HTML/CSS, но есть небольшой фрагмент javascript, чтобы сделать класс li [узлов до выбранной точки] активным.

Запустите фрагмент и щелкните по элементам узла по очереди, чтобы увидеть рисуемые линии.

Обновлено: Re. ваши вопросы:

Что касается последнего узла, вы можете задать ему другую ширину, удалить ширину границы/поля/отступы или отобразить: нет. Если вы используете селектор :последний ребенок, вы можете присвоить последнему элементу различные значения свойств по мере необходимости, используя CSS.

Что касается разных шрифтов/смещений, я бы сказал, что то же самое верно и для большей части кода, использующего разные шрифты. Старайтесь последовательно использовать один шрифт (в данном случае я считаю это лучшей практикой). Что касается смещения, если это различные размеры изображения, которые в основном вызывают его смещение, попробуйте использовать фиксированную ширину с object-fit (содержание/уменьшение должно отображаться лучше для вас) Вы можете установить переполнение для div, и не забудьте wrap

Центрирование меток: вы пробовали просто добавить text-align: center;? Не уверен, что предложить относительно отрицательного смещения, так как это зависит/относительно других css. Нужно будет увидеть полный макет css/html.

Ре. потенциально перекрывающиеся элементы div: установите max-width для вашего контента и overflow/overflow-y, если это необходимо.

Надеюсь это поможет!

var nodelist1 = document.getElementById("connect");

var mynodes = nodelist1.getElementsByTagName("li");

for (var i = 0; i < mynodes.length; i++) {
  mynodes[i].addEventListener("click", function() {
    var currNode = document.getElementsByClassName("active");
    currNode[0].className = currNode[0].className.replace("active", "");
    this.className += "active";
  });
}
body {
  font-family: "Font Awesome 5 Free";
  /* padding: 2em;*/
}

#connect {
  font-weight: 300;
  content: "\f111";
}

h1,
h2 {
  margin: 0;
  padding: 0;
}

li {
  vertical-align: middle;
  display: inline-block;
  position: relative;
  color: white;
  width: 4em;
  height: 4em;
  text-align: center;
  margin: 0em .8em;
  line-height: 4em;
  border-radius: 1em;
  background: navy;
}

li::before {
  content: '';
  position: absolute;
  top: 2em;
  left: -3em;
  min-width: 4em;
  /*width of connecting line*/
  height: .2em;
  background: maroon;
  z-index: -1;
}

li:first-child::before {
  display: none;
  /*at pos 1, other nodes are 'disabled' line is light blue*/
}

.active {
  background: navy;
}

.active~li {
  background: lightgray;
}

.active~li::before {
  background: lightblue;
}

.content {
  display: none;
  width: 5em;
  max-height: 6em;
  overflow-y: scroll;
  overflow-x: none;
  line-height: 1em;
  color: red;
  padding: 0;
  margin: 0;
}

.active .content {
  display: block;
}
<link href = "https://use.fontawesome.com/releases/v5.5.0/css/all.css" rel = "stylesheet" />
<ul id = "connect">
  <li>1</li>
  <li class = "active">2</li>
  <li>
    <h2>Node A</h2>
    <div class = "content">Manuel: hello how are you I speak English I learn it from a book</div>
  </li>
  <li>4</li>
  <li>5</li>

</ul>

Привет, спасибо за ваш вклад! Я смог немного приблизиться к своей цели, но, к сожалению, не без проблем. Я обновил свой вопрос выше новым кодом и проблемами, перечисленными ниже. Возможно, у вас есть идея, как я могу справиться с ними?

Thomas 14.07.2019 12:16
Ответ принят как подходящий

Вот мой ответ: по сути, вы добавляете display:flex в список ul и убедитесь, что узлы имеют фиксированный размер, используя flex:0 0 auto и фиксированную ширину. Это позволит контексту между быть переменным по размеру.

Что касается соединения узлов, хотя это можно сделать с помощью псевдоэлементов :before и :after, есть более простой способ сделать это; просто используйте псевдоэлемент для всего списка (элемент ul), который идет бок о бок по ширине элемента (в примере на самом деле left и right имеют значение 30 пикселей, чтобы компенсировать произвольное боковое заполнение, которое я установил) .

HTML:

<ul>
  <li class = "node"><label>Point A</label></li>
  <li class = "context"><span>Content here Content here Content here</span></li>
  <li class = "node"><label>Point B</label></li>
  <li class = "context"><span>Content here</span></li>
  <li class = "node"><label>Point C</label></li>
</ul>

CSS:

ul {
  list-style-type: none;
  display: flex;
  width: 100%;
  margin: 50px 0 0 0;
  padding: 0 30px;
  position: relative;
}

ul:before {
  content: "";
  display: block;
  position: absolute;
  left: 30px;
  right: 30px;
  top: 50%;
  margin-top: -1px;
  height: 2px;
  background: steelblue;
}

.node {
  flex: 0 0 auto;
  display: block;
  width: 12px;
  height: 12px;
  border-radius: 12px;
  border: 2px solid steelblue;
  position: relative;
  background: #fff;
}

.node label {
  position: absolute;
  top: -30px;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
}

.context {
  flex: 1 1 auto;
}

.context span {
  display: block;
  margin-top: -15px;
  text-align: center;
}

Вот рабочая рабочий пример: https://jsfiddle.net/8ksxtz60/

Кажется, это делает то, что я хотел, спасибо! Сила гибкости до сих пор меня поражает.

Thomas 18.07.2019 19:14

@Thomas представьте себе возможности сетки. Рад, что смог помочь

scooterlord 18.07.2019 19:26

Другие вопросы по теме