Кнопки в сетке со стрелками в промежутках

У меня есть кнопки, которые отображаются в сетке CSS. Я хотел бы поставить стрелки в пробелах, которые будут похожи на блок-схему. Если невозможно использовать сетку css, можно придумать что-то, что можно реализовать с использованием другой техники. Это stackblitz, который покажет мою реализацию без стрелок между ними. https://stackblitz.com/edit/angular-wipq2r-miu8fl?file=src%2Fapp%2Fproduct-list%2Fproduct-list.component.html

вот иллюстрация: Кнопки в сетке со стрелками в промежутках

См. Как спросить. Ваш вопрос нуждается в доработке. Вам нужно показать код здесь.

isherwood 29.03.2022 04:44

Иллюстрация желаемого результата была бы полезна для понимания вопроса.

Servesh Chaturvedi 29.03.2022 04:56

@ServeshChaturvedi я добавил иллюстрацию

ddb20 29.03.2022 05:01

@isherwood Пожалуйста, посмотрите мой код в stackblitz: stackblitz.com/edit/…

ddb20 29.03.2022 05:03

Пожалуйста, проверьте свой код, он просто показывает множество стрелок. И добавьте в свой вопрос достаточно кода, а не стороннего сайта, и убедитесь, что он показывает вашу проблему. Это поможет с тем, как это сделать: stackoverflow.com/help/минимально-воспроизводимый-пример

A Haworth 29.03.2022 08:30

Как это связано с Font Awesome?

vee 29.03.2022 08:54

Вы можете использовать псевдоэлементы на кнопках и clip-path для создания необходимых форм стрелок в зависимости от того, является ли это последней кнопкой в ​​строке или нет.

A Haworth 29.03.2022 11:29
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Введение в 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. Это простой сайт, ничего вычурного. Основная цель -...
CSS: FlexBox
CSS: FlexBox
Ранее разработчики использовали макеты с помощью Position и Float. После появления flexbox сценарий полностью изменился.
0
7
69
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я бы создал классы, которые можно было бы применять к каждому «шагу» в зависимости от того, куда должна указывать стрелка (вверх, вниз, влево, вправо), а затем использовал бы псевдоселектор ::after для создания элемента стрелки в каждом классе, стилизуя по мере необходимости. .

Смотри ниже.

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  grid-gap: 20px;
}

.step {
  background-color: blue;
  color: white;
  padding: 10px;
  position: relative;
}

.arrow-right::after {
  color: black;
  content: '→';
  font-size: 20px;
  position: absolute;
  left: 100%;
  top: 50%;
  transform: translateY(-50%);
}

.arrow-down::after {
  color: black;
  content: '↓';
  font-size: 16px;
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translateX(-50%);
}

.arrow-up::after {
  color: black;
  content: '↑';
  font-size: 16px;
  position: absolute;
  left: 50%;
  bottom: 100%;
  transform: translateX(-50%);
}

.arrow-left::after {
  color: black;
  content: '←';
  font-size: 20px;
  position: absolute;
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
}
<div class = "grid">
  <div class = "step arrow-right">Step X</div>
  <div class = "step arrow-down">Step X</div>
  <div class = "step">Step X</div>
  <div class = "step">Step X</div>
  <div class = "step arrow-down">Step X</div>
  <div class = "step">Step X</div>
  <div class = "step arrow-up">Step X</div>
  <div class = "step arrow-left">Step X</div>
  <div class = "step">Step X</div>
</div>

Спасибо тебе за это. Это действительно решило мою проблему

ddb20 31.03.2022 01:39

Другой подход — использовать SVG.

**Обновление** Я забыл добавить window.scrollX и window.scrollY при вычислении путей (просто исправлено в коде и stactblitz)

Обновление 2 Когда мы вычисляем позицию, нам нужен susbstrat из element.getBoundingClientRect(), getBoundingClientRect().top и getBoundingClientRect().left "обертки"

Идея кладется вся под обертку div

<div #wrapper class = "wrapper">
  <svg [attr.width] = "size.width" [attr.height] = "size.height"
  xmlns = "http://www.w3.org/2000/svg">
    <path *ngFor = "let path of paths" [attr.d] = "path" />
  </svg>
  <div #bt *ngFor = "let item of procDesc; let i = index" class = "step">
    ..your buttons..
  </div>
</div>

Вы получаете элементы с помощью viewChild и ViewChildren и объявляете массив «путей» и объект с размером обертки

  @ViewChildren('bt') items:QueryList<ElementRef>
  @ViewChild('wrapper') wrapper:ElementRef

  paths:string[]=[]
  size = {width:0,height:0}

Затем, когда вы изменяете размер (я использую оператор fromEvent rxjs в стекблиц )

  ngOnInit()
  {
    this.subscription=fromEvent(window,'resize').pipe(
      startWith(null),
      debounceTime(200)
    ).subscribe(_=>{
      setTimeout(()=>{
        this.paths=this.createPath()
        const rect=this.wrapper.nativeElement.getBoundingClientRect()
        this.size = {width:rect.width,height:rect.height}
      })
  
    })
  }
  ngOnDestroy(){
    this.subscription.unsubscribe()
  }

Функция createPath похожа на

  createPath()
  {
    const path:string[]=[]
    const add=.5; //if stroke-width is even use add=.5 else use add=0
    //get the position of "wrapper"
    const wrapper=this.wrapper.nativeElement.getBoundingClientRect()
    this.items.forEach((x,i)=>{
      if (i)
      {
        /*   replace this lines
        const ini=this.items.find((_,index)=>index==i-1)
                   .nativeElement.getBoundingClientRect()
        const fin=x.nativeElement.getBoundingClientRect()
        */
        //by
       const _ini=this.items.find((_,index)=>index==i-1)
                   .nativeElement.getBoundingClientRect()
       const _fin=x.nativeElement.getBoundingClientRect()
    
       const ini = {width:_ini.width,height:_ini.height,
             left:_ini.left+window.scrollX,top:_ini.top+window.scrollY}
       const fin = {width:_fin.width,height:_fin.height,
             left:_fin.left+window.scrollX,top:_fin.top+window.scrollY}
       const _ini=this.items.find((_,index)=>index==i-1)
                   .nativeElement.getBoundingClientRect()
       const _fin=x.nativeElement.getBoundingClientRect()
    
       const ini = {width:_ini.width,height:_ini.height,
                  left:_ini.left-wrapper.left,top:_ini.top-wrapper.top}
       const fin = {width:_fin.width,height:_fin.height,
                  left:_fin.left-wrapper.left,top:_fin.top-wrapper.top}

       if (ini.top==fin.top)
       {
         path.push(`M${ini.left+ini.width+add} ${ini.top+ini.height/2+add}
                    H${fin.left-add}
                    M${fin.left-7-add} ${fin.top+fin.height/2-4-add} 
                    L${fin.left-add} ${fin.top+fin.height/2+add}
                    M${fin.left-7-add} ${fin.top+fin.height/2+4+add}
                    L${fin.left-add} ${fin.top+fin.height/2+add}`)
       }
       else
       {
         const step=6; //(fin.top-ini.top-ini.height)/2
         path.push(`M${ini.left+ini.width/2+add} ${ini.top+ini.height+add}
                    V${ini.top+ini.height+step+add} 
                    H${fin.left+fin.width/2+add}
                    V${fin.top-add}
                    M${fin.left+fin.width/2+4+add} ${fin.top-7-add}
                    L${fin.left+fin.width/2+add} ${fin.top-add}
                    M${fin.left+fin.width/2-4-add} ${fin.top-7-add}
                    L${fin.left+fin.width/2+add} ${fin.top-add}`
         )
       }
      }
    })
    return path
  }

Поскольку стрелки — это просто визуальные подсказки, мы можем использовать псевдоэлементы для их изображения.

Вы можете «нарисовать» линии и наконечники стрелок, поместив псевдоэлемент after на элемент с черным цветом фона и обрезав его с помощью clip-path.

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

В этом фрагменте используются настройки некоторых переменных CSS, чтобы упростить их изменение в соответствии с конкретным вариантом использования.

Вот результат:

* {
  margin: 0;
  padding;
  0;
  box-sizing: border-box;
}

.container {
  --gap: 10vmin;
  /* set this to what you want the gap to be - absolute units */
  display: grid;
  gap: var(--gap);
  grid-template-columns: 1fr 1fr 1fr;
  width: 100vw;
  /* set this to whatever you want */
  padding: var(--gap);
}

.container>* {
  border: solid 1px black;
  width: 100%;
  --ar: 3 / 1;
  /* set this to what you want the aspect ratio of a button to be */
  aspect-ratio: var(--ar);
  position: relative;
}

.container>*::after {
  content: '';
  width: var(--gap);
  --arrow: 20px;
  /* set this to the height of the arrowhead  */
  --ha: calc(var(--arrow) / 2);
  /* half the height of an arrowhead */
  --line: 2px;
  /* set this to the width (height) of the lines */
  --hl: calc(var(--line) / 2);
  /* half the height of a line */
  height: var(--arrow);
  background-color: black;
  clip-path: polygon(0 calc(var(--ha) - var(--hl)), calc(100% - var(--ha)) calc(var(--ha) - var(--hl)), calc(100% - var(--ha)) 0, 100% 50%, calc(100% - var(--ha)) 100%, calc(100% - var(--ha)) calc(var(--ha) + var(--hl)), 0 calc(var(--ha) + var(--hl)));
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  right: calc(-1 * var(--gap));
}

.container>*:nth-child(3n)::after {
  width: calc(200% + (2 * var(--gap)) + var(--line));
  height: var(--gap);
  transform: translateY(0);
  top: 100%;
  right: calc(50% - (var(--hl)));
  clip-path: polygon( 100% 0, 100% calc(50% + var(--hl)), calc(var(--ha) + var(--hl)) calc(50% + var(--hl)), calc(var(--ha) + var(--hl)) calc(100% - var(--ha)), var(--arrow) calc(100% - var(--ha)), var(--ha) 100%, 0 calc(100% - var(--ha)), calc(var(--ha) - var(--hl)) calc(100% - var(--ha)), calc(var(--ha) - var(--hl)) calc(50% - var(--hl)), calc(100% - var(--line)) calc(50% - var(--hl)), calc(100% - var(--line)) 0);
}

.container>*:last-child::after {
  display: none;
}
<div class = "container">
  <button></button><button></button><button></button><button></button><button></button><button></button><button></button><button></button><button></button>
</div>

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