it-swarm.com.ru

Сделайте так, чтобы гибкие элементы перекрывались

Я хотел бы показать горизонтальную серию неизвестного количества игральных карт. Для этого им придется перекрывать друг друга, если их слишком много. У меня проблемы с тем, чтобы убедить гибкую коробку перекрывать карты, не сжимая их. Пример ниже сжимает карты. Я пробовал flex-shrink: 0, но тогда max-width не соблюдали.

.cards {
  display: flex;
  max-width: 300px;
}

.card {
  width: 50px;
  height: 90px;
  border: 1px solid black;
  border-radius: 3px;
  background-color: rgba(255, 0, 0, 0.4);
}
<div class='cards'>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
</div>

7
Michael Arrison

Вы можете сделать элементы в гибком макете перекрывающимися, используя transform: translateX(-10px), но это не будет относиться к макету, который вы пытаетесь получить. Я не думаю, что вы можете сделать это во flexbox. Но вы могли бы легко сделать это с JS.

var parentEl = document.getElementById("cards");

function sortCards() {
  var cards = document.getElementsByClassName("card"),
      cw = parentEl.clientWidth,
      sw = parentEl.scrollWidth,
      diff = sw - cw,
      offset = diff / (cards.length - 1);

  for (var i = 0; i < cards.length; i++) {
    i != 0 && (cards[i].style.transform = "translateX(-" + offset * i + "px)");
  }
}

sortCards();

var b = document.getElementById("button");
b.addEventListener("click", function() {
  var div = document.createElement("div");
  div.classList.add("card");
  parentEl.appendChild(div);
  sortCards();
});
.cards {
  display: flex;
  max-width: 300px;
}

.card {
  height: 90px;
  border: 1px solid black;
  border-radius: 3px;
  background-color: rgba(255, 0, 0, 0.4);
  flex: 0 0 50px;
  background: red;
  transition: transform .25s;
}
<div><button id="button">addcards</button></div>
<div class='cards' id="cards">
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
</div>

11
Michael Coker

Вот как я могу это сделать, используя flexbox.

.cards {
  display: flex;
  align-content: center;
  max-width: 35em;
}

.cardWrapper {
  overflow: hidden;
}

.cardWrapper:last-child, .cardWrapper:hover {
    overflow: visible;
}

.card {
    width: 10em;
    min-width: 10em;
    height: 6em;
    border-radius: 0.5em;
    border: solid #666 1px;
    background-color: #ccc;
    padding: 0.25em;
  
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
<div class="cards">
  <div class="cardWrapper">
    <div class="card">card 1 blah blah blah</div>
  </div>
  <div class="cardWrapper">
    <div class="card">card 2 blah blah blah</div>
  </div>
  <div class="cardWrapper">
    <div class="card">card 3 blah blah blah</div>
  </div>
  <div class="cardWrapper">
    <div class="card">card 4 blah blah blah</div>
  </div>
  <div class="cardWrapper">
    <div class="card">card 5 blah blah blah</div>
  </div>
</div>

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

Обертывающие элементы сокращаются, чтобы соответствовать доступному пространству, и в этом пространстве отображается как можно больше карточек.

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

8
FTWinston

Гибкий контейнер предназначен для выравнивания предметов по осям X и Y. 

Вы спрашиваете о выравнивании вдоль оси Z.

Flexbox не предназначен для выравнивания по оси Z (перекрытия). 

Любое перекрытие должно происходить из-за отрицательных полей, абсолютного позиционирования, CSS Grid Layout, JavaScript или чего-то еще. Свойство z-index также может играть роль.

Вот базовый пример использования CSS Grid:

.cards {
  display: grid;
  grid-template-columns: repeat(30, 10px);
  grid-template-rows: 90px;
  max-width: 300px;
}

.card {
  grid-row-start: 1;
  background-color: lightgreen; 
  border: 1px solid black;
}

.card:nth-child(1) { grid-column: 1 / 6; }
.card:nth-child(2) { grid-column: 4 / 9; }
.card:nth-child(3) { grid-column: 7 / 12; }
.card:nth-child(4) { grid-column: 10 / 15; }
.card:nth-child(5) { grid-column: 13 / 18; }
.card:nth-child(6) { grid-column: 16 / 21; }
.card:nth-child(7) { grid-column: 19 / 24; }
.card:nth-child(8) { grid-column: 22 / 27; }
.card:nth-child(9) { grid-column: 25 / 30; }
<div class='cards'>
  <div class='card'>1</div>
  <div class='card'>2</div>
  <div class='card'>3</div>
  <div class='card'>4</div>
  <div class='card'>5</div>
  <div class='card'>6</div>
  <div class='card'>7</div>
  <div class='card'>8</div>
  <div class='card'>9</div>
</div>

Карты создаются для перекрытия с использованием линейного размещения. В этом случае свойство grid-column используется для перекрытия дорожек столбцов.

Тем не менее, некоторые сценарии были бы необходимы, если количество карточек изменяется динамически, поскольку величина перекрытия должна изменяться, чтобы все карточки точно помещались в контейнер фиксированной ширины.

3
Michael_B

Я придумал общее решение на основе CSS. Однако, с несколькими оговорками:

  1. Последняя карта переполняет контейнер .cards.
  2. Дочерний элемент .card необходим для создания эффекта перекрытия.

.cards {
  display: flex;
  max-width: 300px;
}

.card {
  position: relative;
  flex-basis: 50px;
  height: 90px;
}

.card::before {
  content: '';
  display: block;
  position: absolute;
  width: 50px;
  height: 100%;
  border: 1px solid black;
  border-radius: 3px;
  background-color: rgba(255, 0, 0, 0.4);
  box-sizing: border-box;
}
<div class='cards'>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
</div>

2
Nate Whittaker

Вы можете сделать это, используя только CSS, используя grid вместо flex.

.hand{
  width: 50%;
  margin-left: auto;
  margin-right: auto;
  justify-content: center;
  display: grid;
  grid-template-columns: repeat(auto-fit,  minmax(10px, max-content)) ;
}
.card{
  width: 3em;
  height: 2.4em;
  padding: 3px;
  margin: 2px;
  background-color: lightgreen;
  border-style: solid;
  transform: rotate(3deg);  /*makes it easier to see the overlap*/
}
<div class="hand"> 
  <div class="card"> card </div>
  <div class="card"> card </div>
  <div class="card"> card </div>
  <div class="card"> card </div>
  <div class="card"> card </div>
  <div class="card"> card </div>
  <div class="card"> card </div>
  <div class="card"> card </div>
</div>

2
Max Garber

div.card-area
{
    height: 16vh; /* whatever */
    display: flex;
}
div.card-area > div
{
    flex: 1 0 0;
    overflow-x: hidden;
}
div.card-area > div:last-of-type
{
    flex: 0 0 auto;
}
div.card-area img
{
    height: 100%;
}
<div class="card-area N">
    <div><img src="img/cards/AH.png"></div>
    <div><img src="img/cards/KH.png"></div>
    <div><img src="img/cards/QH.png"></div>
    <div><img src="img/cards/JH.png"></div>
    <div><img src="img/cards/10H.png"></div>
    <div><img src="img/cards/9H.png"></div>
    <div><img src="img/cards/8H.png"></div>
    <div><img src="img/cards/7H.png"></div>
    <div><img src="img/cards/6H.png"></div>
    <div><img src="img/cards/5H.png"></div>
    <div><img src="img/cards/4H.png"></div>
    <div><img src="img/cards/3H.png"></div>
    <div><img src="img/cards/2H.png"></div>
</div>

0
Cuse70