align-items: center distorts height of parent - html

I want to build, something like a carousel, that you can slide using a scrollbar. In each of the slides, there's a single line of text that should be both horizontally and vertically centered.
Setting align-items: center changes height of the parent div.
.carousel {
width: 100%;
background-color: #dbdbdb;
overflow-y: visible;
overflow-x: auto;
white-space: nowrap;
}
.carousel .slide {
display: inline-flex;
width: 250px;
height: 150px;
margin: 10px 10px 10px 10px;
background-color: #FFF;
font-weight: bolder;
font-size: 15px;
white-space: pre-wrap;
align-items: center;
justify-content: center;
text-align: center;
text-align-last: center;
}
<div class="carousel">
<div class="slide">Lorem ipsum dolor</div>
<div class="slide">quisquam est qui dolorem ipsum quia dolor sit amet lorem ipsum</div>
<div class="slide">consectetur, adipisci</div>
</div>
Comment out the align-items and it fits alright. How should I resolve this issue?

The problem is not align-items: center. That's all good.
The problem is that your flex container is an inline-level box (display: inline-flex), which activates the vertical-align: baseline default setting.
Since your middle item has two lines of text, the box adjusts its baseline to line-up with its siblings. (Notice how all boxes line up when they each have a single line of text.)
Just override the default with vertical-align: bottom.
.carousel .slide {
vertical-align: bottom;
}
.carousel {
width: 100%;
background-color: #dbdbdb;
overflow-y: visible;
overflow-x: auto;
white-space: nowrap;
}
.carousel .slide {
display: inline-flex;
width: 250px;
height: 150px;
margin: 10px 10px 10px 10px;
background-color: #FFF;
font-weight: bolder;
font-size: 15px;
white-space: pre-wrap;
align-items: center;
justify-content: center;
text-align: center;
text-align-last: center;
vertical-align: bottom; /* NEW */
}
<div class="carousel">
<div class="slide">Lorem ipsum dolor</div>
<div class="slide">quisquam est qui dolorem ipsum quia dolor sit amet lorem ipsum</div>
<div class="slide">consectetur, adipisci</div>
</div>
Also note:
the problem doesn't exist when you remove align-items: center because the default value is stretch, which allows the text to align at the baseline (i.e., first line) across boxes regardless of the number of lines (demo)
flex-start would also work (demo)
flex-end would not (demo)
More details about vertical-align: baseline:
Why is there a vertical scroll bar if parent and child have the same height?

Related

How do you make a flex item break to the next line?

I have a basic html markup, where i am trying to use minimal html wrappers to achieve the design.
The button on the bottom should't align, it should always stay in the bottom.
So my goal is without adding more html wrappers, using flex, force a flex item(button) to drop to the next line. and the block title stay next to the image.
You can see what i mean checking it on mobile breakpoints.
Here are the screenshots with flex-wrap: wrap
And here is with flex-wrap: nowrap
As you see, in first example button is in the bottom as it should be, but block title is dropped to the next line, And in the second example (flex-wrap: wrap) block title is positioned correct, but the button is not in the bottom.
Here is the sandbox link and code example
body {
margin: 0;
padding: 0;
}
.container {
background-color: grey;
overflow: auto;
padding: 20px;
align-items: center;
display: flex;
position: relative;
column-gap: 15px;
flex-wrap: wrap;
/* //try nowrap */
width: 100%;
}
.logo-image {
align-self: flex-start;
}
.headline {
color: white;
}
.text {
color: white;
font-size: 16px;
margin-bottom: 20px;
}
.btn {
display: flex;
width: 100%;
}
button {
align-items: center;
background-color: black;
color: white;
flex: 0 0 100%;
justify-content: center;
margin: 0;
}
<div class="container">
<img src="download.png" width="50px" class="logo-image" alt="img" />
<span class="content">
<h4 class="headline">
Block Title
</h4>
<p class="text">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente
aliquid sit, cupiditate
</p>
</span>
<div class="btn">
<button>link</button>
</div>
</div>
Any help will be appreciated
You can make your span a block level element and set flex-grow to 1 but set flex-basis to something small, like 50% so it tries to be 50% of the width but will grow to fit the width. It then means when shrinking it will try to stay on the same line.
body {
margin: 0;
padding: 0;
}
.container {
background-color: grey;
overflow: auto;
padding: 20px;
align-items: center;
display: flex;
position: relative;
column-gap: 15px;
flex-wrap: wrap;
width: 100%;
}
/* added this --v */
.content {
display: block;
flex: 1 0 50%;
}
.logo-image {
align-self: flex-start;
}
.headline {
color: white;
}
.text {
color: white;
font-size: 16px;
margin-bottom: 20px;
}
.btn {
display: flex;
width: 100%;
}
button {
align-items: center;
background-color: black;
color: white;
flex: 0 0 90%;
justify-content: center;
margin: 0;
}
<div class="container">
<img src="https://www.fillmurray.com/200/200" width="50px" class="logo-image" alt="img" />
<span class="content">
<h4 class="headline">
Block Title
</h4>
<p class="text">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente
aliquid sit, cupiditate
</p>
</span>
<div class="btn">
<button>link</button>
</div>
</div>

Prevent child element from stretching parent: portable solution for both Chrome & Safari?

I have a text-containing element where the text can be very long. I want to hide overflow text and I don't want the text to increase the size of the element or its parents/ancestors.
Adding the following to the element CSS seemed to work at first (from this question, but height not width):
height: 0;
min-height: 100%;
This works on Chrome; however, it doesn't quite seem to work on Safari (mobile or desktop).
Here is an example:
The image shows a side-by-side comparison of Chrome (left) and Safari (right).
The text should be vertically centered but as can be seen, the Safari text is not.
Eventually, if the page height gets too small, the text disappears completely.
The HTML is at the foot of this post (sorry I couldn't get it shorter).
Inspecting via devtools on Chrome (Version 88.0.4324.146) and Safari (Version 13.1.3), both on a Mac, the problem seems to be that the inner element is oversized on Safari.
This seems to be directly caused by the height:0;min-height:100% trick, in that replacing these lines with height:100% causes the centering problem to go away in Safari (but then the layout is perturbed in Chrome when the text is longer).
As I understand it, the min-height:100% should set the inner element's height to the height of the containing block, which (since inner has position:relative and its parent card has display:flex), should be the content box of the parent card element, as described here.
This appears to work as described in Chrome, but not Safari. I am not sure where Safari is getting the height of the inner element from, but it's clearly taller than card.
For context, here is what the original problem that I was having looks like (layout messed up in Chrome when there's a lot of text in the cyan box). This is the problem that I was trying to solve with the height:0;min-height:100%. For this screenshot I removed those lines and just put height:100%. Here's what that looks like (again, Chrome on left and Safari on right)
As you can see, the orange box has disappeared in Chrome (left).
Adding the height:0;min-height:100% back in causes this to render correctly (but with the problem described above, that the text is not vertically centered in Safari - it looks centered here, but that's only because the overflow is hidden so the card appears full of text):
Any insights appreciated. Is this just a bug in Safari? Is there a workaround? Or (more likely) am I just a CSS klutz...
Update: here's what it looks like in Safari devtools. The parent card element has height 938px, but the inner has height 1121px and pushes the bottombar off the screen.
<html>
<head>
<style>
html, body {
height: 100%;
overflow: hidden;
margin: 0;
padding: 0;
}
body {
position: relative;
}
.page {
background: midnightblue;
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
justify-content: center;
}
.central-column {
display: flex;
flex-direction: column;
}
.bottombar {
background: orange;
height: 80px;
z-index: 30;
display: flex;
flex-direction: column;
justify-content: space-around;
font-size: 2vh;
text-align: center;
}
.foo {
background: pink;
position: relative;
flex-grow: 1;
display: flex;
flex-direction: column;
}
.foo,
.central-column {
width: 800px;
max-width: 800px;
height: 100%;
}
.foo .topbar {
background: red;
position: relative;
display: flex;
flex-direction: row;
justify-content: space-around;
min-height: 90px;
height: 15vh;
max-height: 90px;
}
.foo .cardbar {
position: relative;
flex-grow: 1;
display: flex;
flex-direction: column;
padding: 4px 20px;
}
.foo .cardtable {
background: green;
position: relative;
flex-grow: 1;
display: flex;
flex-direction: column;
padding: 4px;
}
.foo .stack {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: space-around;
z-index: 6;
position: relative;
padding: 4px 20px;
}
.foo .stack .card {
background: cyan;
position:relative;
max-height: 160vw;
flex-grow: 1;
display: flex;
flex-direction: column;
overflow: hidden;
border-radius: 2vh;
border-width: 1px;
border-style: solid;
}
.foo .stack .card .inner {
position: relative;
display: flex;
flex-direction: column;
justify-content: space-evenly;
height: 0;
min-height: 100%;
/*
Replacing the previous two lines with this line fixes the centering on Safari,
but then longer text (that would overflow the cyan box) breaks the layout in Chrome
height: 100%;
*/
text-align: center;
overflow: hidden;
margin: 4px;
}
</style>
</head>
<body>
<div class="page">
<div class="central-column">
<div class="foo">
<div class="topbar">
</div>
<div class="cardbar">
<div class="cardtable">
<div class="stack">
<div class="card">
<div class="inner">
<div class="content">
this text should be vertically centered in the cyan box
</div>
</div>
</div>
</div>
</div>
</div>
<div class="bottombar"></div>
</div>
</div>
</div>
</body>
</html>
Here is a simplified example (I removed a couple elements from your code just to make it easier to read). The scroll element needs two things: a parent with overflow:hidden, and an ancestor with a height property (can't be auto). Then to center the non-overflowing content, just use flexbox on the parent, and margin:auto on the content element.
*** UPDATE
A better explanation of what is going on with your code:
You want to center a content block while making the parent hide its overflow if any.
For overflow to work it needs a parent with a height otherwise it will not know where to cut off the content.
To vertically center the content box within the available space, set the parent to display:flex.
The important part: the content block has to be centered using margin:auto otherwise when there is overflow, it will remain centered with its top and bottom parts being cut-off by the parent's overflow:hidden.
body,
html {
margin: 0;
padding: 0;
height: 100%;
}
.page {
/* Set height for overflow element ancestor */
height: 100%;
max-height: 100vh;
display: flex;
background: blue;
justify-content: center;
}
.central-column {
flex-basis: 100%;
max-width: 90%;
display: flex;
flex-direction: column;
height: 100%;
}
.topbar {
height: 20%;
flex-shrink: 0;
background: red;
}
.cardbar {
flex-grow: 1;
display: flex;
/* Parent of the scroll element hide overflow */
overflow: hidden;
}
.cardtable {
padding: 20px;
background: white;
display: flex;
flex-basis: 100%;
}
.card {
background: cyan;
padding: 30px;
/* Margin auto to center the content */
margin: auto;
text-align: center;
}
.bottombar {
height: 20%;
flex-shrink: 0;
background: red;
}
<div class="page">
<div class="central-column">
<div class="topbar">
</div>
<div class="cardbar">
<div class="cardtable">
<div class="card">
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
</div>
</div>
<div class="bottombar"></div>
</div>
</div>
*** UPDATE 2
Here it is with your HTML.
body,
html {
padding: 0;
margin: 0;
min-height: 100%;
}
.page {
width: 100%;
display: flex;
justify-content: center;
background: navy;
height: 100vh;
}
.central-column {
flex-basis: 100%;
max-width: 900px;
display: flex;
flex-direction: column;
align-items: stretch;
}
.foo {
display: flex;
flex-direction: column;
flex-grow: 1;
align-items: stretch;
height: 100%;
}
.topbar,
.bottombar {
height: 20%;
background: coral;
flex-shrink: 0;
}
.cardbar {
display: flex;
flex-direction: column;
align-items: stretch;
padding: 10px 20px;
background: pink;
flex-grow: 1;
overflow: hidden;
}
.cardtable {
display: flex;
flex-direction: column;
align-items: stretch;
padding: 10px 20px;
background: forestgreen;
flex-grow: 1;
overflow: hidden;
}
.stack {
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: stretch;
background: lightblue;
flex-grow: 1;
overflow: hidden;
}
.card {
display: flex;
flex-direction: column;
align-items: stretch;
flex-grow: 1;
}
.inner {
display: flex;
flex-direction: column;
align-items: center;
flex-grow: 1;
}
.content {
margin: auto;
padding: 10px;
text-align: center;
}
<div class="page">
<div class="central-column">
<div class="foo">
<div class="topbar">
</div>
<div class="cardbar">
<div class="cardtable">
<div class="stack">
<div class="card">
<div class="inner">
<div class="content">
this text should be vertically centered in the cyan box
</div>
</div>
</div>
</div>
</div>
</div>
<div class="bottombar"></div>
</div>
</div>
</div>

Ensure Flex Container Inner Div Maintains Its Dimension On Window Resize - CSS [duplicate]

This question already has an answer here:
Why is a flex item limited to parent size?
(1 answer)
Closed 2 years ago.
I have a flex container which contains an inner div (red square) and some text in a separate paragraph tag.
When the window size is reduced to mobile sizes, the inner div (red square) reduces in size despite having width and height properties set in CSS.
How do I make it so the inner div (red square) keeps its dimensions on smaller window sizes (via the text wrapping on to other lines ?).
CodePen
body {
margin: 0;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.adbox-center {
background: lightgrey;
display: flex;
padding: 1rem;
align-items: center;
width 50%;
}
.redsquare {
margin-right: 1rem;
height: 50px;
width: 50px;
background: red;
}
<div class="adbox-center">
<div class="redsquare"></div>
<p><b>Word</b> — Lorem ipsum dolor sit amet, consectetur adipiscing elit</p>
</div>
Use min-width and min-height instead of using height and width this will not let the div's width and height to go under the adjusted measurement
body {
margin: 0;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.adbox-center {
background: lightgrey;
display: flex;
padding: 1rem;
align-items: center;
width 50%;
}
.redsquare {
margin-right: 1rem;
min-height: 50px;
min-width: 50px;
background: red;
}
<div class="adbox-center">
<div class="redsquare"></div>
<p><b>Word</b> — Lorem ipsum dolor sit amet, consectetur adipiscing elit</p>
</div>

Vertically centered text in a dynamic height wrapper

I'd normally just use line-height for vertical centering, but on this occasion the layout I'm working to is a little trickier.
I've put together this jsfiddle to show where I'm at so far. All the CSS hacks suggest using table-cell trickery for this but I can only get it to work if the wrapper has an absolute height, so for me this text isn't vertically centered:
<div class="wrap">
<a href="#">
<img src="http://www.thekrausemouse.com/wp-content/uploads/2016/03/sample-1.jpg" />
<span class="text"><span>Text that might span multiple lines</span></span>
</a>
</div>
https://jsfiddle.net/fdtbvmcw/
What I basically need is for the text, regardless of how many lines it spans, to sit in the middle of the image. The image can't be a background-image and I can't attach fixed widths or heights to the wrapper.
The wrapper is simulating a responsive column within a bigger page template and I need the image to retain full width of that column you see. Other HTML can be added within the column if need be.
Thoughts?
Flexbox can do that...
.wrap {
height: auto;
position: relative;
width: 50%;
}
.wrap a img {
height: auto;
width: 100%;
}
.wrap a span.text {
height: 100%;
left: 0;
position: absolute;
text-align: center;
top: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.wrap a span.text span {
color: #fff;
font-size: 20px;
font-weight: bold;
line-height: 1.25
}
<div class="wrap">
<a href="#">
<img src="http://www.thekrausemouse.com/wp-content/uploads/2016/03/sample-1.jpg" />
<span class="text"><span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Id praesentium nihil iure amet dolore nulla totam modi </span></span>
</a>
</div>
I think is better use translateY, it works in more devices
//CSS
.wrap {
height: auto;
position: relative;
width: 50%;
}
.wrap a img {
height: auto;
width: 100%;
}
.wrap span {
color: #fff;
font-size: 26px;
font-weight: bold;
line-height: 30px;
vertical-align: middle;
top: 50%;
transform: translateY(-50%);
display:block;
position:absolute;
text-align:center;
}
//HTML
<div class="wrap">
<a href="#">
<img src="http://www.thekrausemouse.com/wp-content/uploads/2016/03/sample-1.jpg" />
<span>Text that might span multiple lines</span>
</a>
</div>
https://jsfiddle.net/MAXXALANDER/fdtbvmcw/2/
I would also use flex for your solution.
.wrap a .text {
height: 100%;
left: 0;
position: absolute;
text-align: center;
top:0;
display: flex;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
justify-content: center;
align-items: center;
}

Bottom vertical align div in parent

Im having an issue with vertical aligning a button inside of its parent.
The button should be aligned to the bottom of the "info" div but I cannot get it to stick.
I cannot use "position: absolute" in this situation.
And i do not know the height of the main parent div beforehand.
HTML:
<div class="container">
<img src="http://placekitten.com/g/200/400" alt="" />
<div class="info">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus rem tenetur temporibus voluptas repellendus.</p>
<button>Button</button>
</div>
</div>
CSS:
* { box-sizing: border-box; }
.container {
width: 200px;
height: 700px; /* The height is variable!!! */
background: #ccc;
padding: 1em;
overflow: hidden;
}
a { display: block; height: 50%; }
a img { display: block; width: 100%; max-width: 100%; }
.info {
background: #fa0;
display: block;
height: calc(50% - 1em);
margin-top: 1em;
text-align: center;
}
.info p {
display: inline-block;
width: 100%;
vertical-align: top;
background: #a0f;
margin: 0;
}
.info button {
display: inline-block;
vertical-align: bottom;
}
As mentioned in some of the comments, position: absolute is the easiest way to do this. However, you said you're restricted on this factor, so here's an alternative using flexbox!
You need to see three properties on the parent element: display, flex-direction, and justify-content. Then put a margin on the child element to make sure its centered at the bottom. Here's an updated fiddle. No absolute position required : ) https://jsfiddle.net/jg8egtb1/
.info {
background: #fa0;
display: block;
height: calc(50% - 1em);
margin-top: 1em;
text-align: center;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.info button {
margin: 0 auto;
}