Динамический горизонтальный список с линиями переменной ширины и содержимым между узлами - PullRequest
0 голосов
/ 06 июля 2019

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

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

Fig 1

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

В моей первой попытке попытаться визуализировать узлы, я просто использовал вертикальный список с псевдоэлементами :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

Ответы [ 3 ]

1 голос
/ 15 июля 2019

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

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

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/

0 голосов
/ 14 июля 2019

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

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

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

РЕДАКТИРОВАТЬ: Re.Ваши вопросы:

Что касается последнего узла, вы можете выбрать для него другую ширину, удалить border-width / margin / padding или display: none.Если вы используете селектор : last-child , вы можете присвоить последнему элементу различные значения свойств по мере необходимости, используя CSS.

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

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

Re.потенциально перекрывающиеся 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>
0 голосов
/ 13 июля 2019

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

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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...