问题
I'd like to show a horizontal series of a unknown number of playing cards. To do this, they will have to overlap if there are too many. I'm having trouble convincing a flex box to overlap the cards without shrinking them. The example below shrinks the cards. I tried flex-shrink: 0, but then max-width wasn't respected.
.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>
回答1:
Here's how I'd do this using 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>
Note that technically speaking, the cards aren't overlapping, they're just being clipped. But they look like they're overlapping. The trick is to wrap each card in another element with overflow: hidden.
The wrapping elements are shrunk to fit the available space, and as much of the cards as is possible is displayed in that space.
I include the :hover rule just to show how you could fully display a card from the middle of the "stack", but in a real project I'd probably do this for selected cards instead of hovered ones.
回答2:
You can make elements in a flex layout overlap using transform: translateX(-10px), but that won't address the layout you're trying to get. I don't think you can do that in flexbox. But you could easily do this with 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>
回答3:
You can do it using only css by using grid instead of 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>
回答4:
A flex container is designed to align items along the X and Y axes.
You're asking about alignment along the Z axis.
Flexbox is not designed for z-axis alignment (overlapping).
Any overlapping would have to come from negative margins, absolute positioning, CSS Grid Layout, JavaScript or something else. The z-index property may also need to play a role.
Here's a basic example using 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>
Cards are made to overlap using line-based placement. In this case, the grid-column property is used to make column tracks overlap.
Still, some scripting would be necessary if the number of cards varies dynamically, as the overlap amount would need to vary in order for all cards to fit precisely in the fixed-width container.
回答5:
I came up with a generic, CSS-based solution. However, with a few caveats:
- The last card overflows the
.cardscontainer. - A child element of
.cardis needed to produce the overlapping effect.
.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>
回答6:
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>
回答7:
You can do it using margin property and apply to the items you desire by manual or JS.
.cards {
display: flex;
max-width: 300px;
}
.overl {
margin-left:-10px;
}
.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 overl'></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>
来源:https://stackoverflow.com/questions/43919067/make-flex-items-overlap