Best way to vertically-align children in an inline-block - html

I’m trying to vertically align the content in the cyan div without using one of the following methods:
Vertical align (as it requires displaying as a table & will have knock-on effects on the parent div padding etc)
Line height (as there’s more than 1 line with 3 actual spans)
Table (due to knock-on effects like with vertical align)
Absolute positioning (as some other cyan divs will have more text than others, meaning some will have more lines than others)
Equal top & bottom padding (same reason as abs positioning)
Flexboxes (I forbid these as they have serious knock-on effects!)
The cyan div is an inline-block. What would be the best way to achieve this? I want to be able to set the padding between each of the 3 spans to space them out nicely.
NOTE:
I've updated my answer to include flex positioning but on mobile view the 2nd cyan div below is not aligned centrally
.sections {
background: #f2f2f2;
width: 100%;
height: auto;
text-align: center;
padding: 100px 10%;
box-sizing: border-box;
}
h1 {
font-size: 62px;
text-transform: uppercase;
font-weight: 400;
}
p {
font-size: 22px;
font-weight: 300;
padding-top: 10px;
}
.foster-cta {
box-sizing: border-box;
width: 250px;
height: 200px;
background: cyan;
display: inline-block;
border: 1px solid grey;
margin-top: 30px;
/* adding display flex makes the 2nd cyan div below not aligned centrally on mobile view */
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
display: inline-flex;
}
.foster-top {
display: block;
font-size: 30px;
}
.foster-middle {
display: block;
text-transform: uppercase;
font-size: 22px;
}
.foster-bottom {
display: block;
font-weight: 300;
font-size: 16px;
}
<section class="sections">
<h1>header 1 tag</h1>
<p>some random text to go here lorem ipsum sit semei geono wfnwoenfowe fwenfuowe ffe efnpi enfo wfeonwofun weofun weofnwe ofunwe foiej.</p>
<div class="foster-cta">
<span class="foster-top">icon</span>
<span class="foster-middle">some random text here</span>
<span class="foster-bottom">a load more random text goes here that will be more descriptive and longer.</span>
</div><!--
--><div class="foster-cta" style="margin-left:50px;">
<span class="foster-top">icon</span>
<span class="foster-middle">text</span>
<span class="foster-bottom"> a load more random text goes here that will be more descriptive and longer a load more random text goes here that will be more descriptive and longer.</span>
</div>
</section>

Flexbox is your best bet when doing any sort of aligning in CSS. The code is also very simple:
.div-parent {
display: flex;
}
.div-child {
align-self: center;
}
This will align vertically centered only

Related

CSS prevent smaller font sizes from not centering

I'm having trouble vertically centering 2 elements (svg + text). I used flexbox to center these elements, and they are perfectly centered if I do not precise any font-size. But when I put a smaller font-size on the text (0.8em instead of 1em), it creates a small space on top of the text instead of centering it. Horrible colors are to show the blue space on top of the text. Does anyone know how to fix this ?
I've already tried adding text-align: center; vertical-align: middle;
The parent div (blue) centers elements with flex: display: flex; align-items: center;
Thanks a lot
Edit: Here is a snippet, I somehow can't find how to link a file (the svg) ?
a {
text-decoration: none;
}
/*Parent div*/
.parent {
width: 20vw;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1vw;
background-color:skyblue;
}
/*Svg*/
.parent img {
width: auto;
height: 3vh;
margin-right: 10px;
background-color: rosybrown;
}
/*Text*/
span {
font-size: 0.8em;
background-color: seagreen;
}
<div class="parent">
<div>
<img src="https://cdn0.iconfinder.com/data/icons/feather/96/heart-512.png"><span>Favoris</span>
</div>
</div>
I would try to set the line-height of the text element to the same value as your font-size. I would also not define a height for the text element (I am not sure if you are doing this or not, since you did not provide your code).
So something of the sort:
div.container {
display: flex;
align-items: center;
padding: 10px;
background-color: #4169E1;
}
div.container img {
width: 40px;
height: 40px;
margin-right: 20px;
background-color: #BC8F8F;
}
div.container span {
font-size: 20px;
line-height: 20px;
color: #4B565C;
background-color: #2E8B57;
}
<div class="container">
<img src="https://cdn0.iconfinder.com/data/icons/feather/96/heart-512.png"/>
<span>Favoris</span>
</div>
Found the problem:
<a href="#">
<div class="parent">
<img src="img/coeur.svg">
<span>Favoris</span>
</div>
</a>
I just had to invert the <a> tag and <div> and everything is well centered.

How to TRULY vertically center text with flexbox?

So vertically centering text seemed simple enough with justify-content and align-items center but when I looked closely I can see that the text isn't truly centered. It has less spacing at the top of the character. I tried to investigate further by searching online and I found this https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align but there must be a simpler solution to this.
Example
https://jsfiddle.net/z7cy487o/
html,
body {
height: 100%;
}
.box {
height: 10%;
width: 400px;
background: #000;
font-size: 11vh;
color: #FFF;
text-align: center;
padding: 0 20px;
margin: 20px;
display: flex;
justify-content: center; /* align horizontal */
align-items: center; /* align vertical */
}
<div class="box">
C
</div>
The way you perceive that depends on which characters you are using. I copied your example twice to show different situations:
In the second version I only used the letter "y", which has a descender, i.e. a part that extends below the baseline, to the lower border of the area which is defined as line-height. On the other hand, it doesn't go up the whole way, so it seems exactly the opposite of the first version (letter "C") concerning vertical alignment.
In the third version I used both of those letters combined in a word. Here you can see that the different characters/letters together indeed do extend across the whole width, so the vertical centering is correct as it is.
Line-height (and in relation to that, vertical alignment of letters) does not depend on which letters are used - it always applies to all possible letters/characters, even if they are not used in that particular situation.
html, body { height: 100%; }
.box
{
height: 10%;
width: 400px;
background: #000;
font-size: 11vh;
color: #FFF;
text-align: center;
padding: 0 20px;
margin: 20px;
display: flex;
justify-content: center; /* align horizontal */
align-items: center; /* align vertical */
}
<div class="box">
C
</div>
<div class="box">
y
</div>
<div class="box">
Cyborg
</div>
This solution based off a modified version of Center text character ☢ vertically and horizontally within a circle (CSS)
It seems to work with dynamic heights, but as Johannes mentions in the comment of his answer. I believe the solution will only work well with my situation.
html,
body {
height: 100%;
}
.box {
height: 10%;
width: 400px;
background: #000;
font-size: 11vh;
color: #FFF;
text-align: center;
padding: 0 20px;
margin: 20px;
display: flex;
justify-content: center; /* align horizontal */
align-items: center; /* align vertical */
}
.char {
line-height: 1px;
font-family: sans-serif;
font-weight: 500;
position: relative;
top: 0.05em;
}
<div class="box">
<span class="char">C</span>
</div>

Which magic CSS causes the difference of text-vertical-align between <button> and <div>?

I found that the text inside of <button> is automatically vertically centered, while text inside of <div> is top aligned.
I tried to find out which CSS rule made the difference but failed.
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
}
div {
text-align: center;
display: inline-block;
cursor: default;
box-sizing: border-box;
}
<div>text text</div>
<button>text text</button>
<div>text text text text</div>
<button>text text text text</button>
<div>text text text text text text</div>
<button>text text text text text text</button>
As for the above example, comparing all the computed CSS rules from Chrome, I could only find one different pair -- align-items: stretch for <div> while align-items: flex-start for <button>.
But assigning align-items: flex-start doesn't help. So I got totally confused.
what confused me is that the text-vertical-alignment is different between <div> and <button> even if you set all the CSS rules with the same corresponding value. In other words, with the same CSS rules, <div> and <button> behave differently. Why?
What is the magic under the hood?
I can vertically center text inside of <div> (example below). I'm just curious about what causes the difference between the text-vertical-alignment.
Maybe it's not caused by a particular CSS rule, but because the layout algorithms for the two elements are different in browser?
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
}
div { /* basic CSS rules to button-fy */
text-align: center;
display: inline-block;
cursor: default;
box-sizing: border-box;
}
/* Magic */
div, button {
vertical-align: middle;
}
div span {
display: inline-block;
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
<div><span>text text</span></div>
<button>text text</button>
<div><span>text text text text</span></div>
<button>text text text text</button>
<div><span>text text text text text text</span></div>
<button>text text text text text text</button>
Since you are using inline-block, you need to use vertical-align as the default is baseline:
Magic CSS:
vertical-align: middle;
The above will fix it:
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
vertical-align: middle;
}
div {
text-align: center;
display: inline-block;
cursor: default;
box-sizing: border-box;
}
<div>text</div>
<button>text</button>
And for the text inside the div to be centred, you need to use line-height to the height of the div.
Magic CSS:
line-height: 4em;
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
vertical-align: middle;
line-height: 4em;
}
div {
text-align: center;
display: inline-block;
cursor: default;
box-sizing: border-box;
}
<div>text</div>
<button>text</button>
If you look at Chrome source code you can kind of see how it works, at least for Chrome. It seems there's an anonymous flex box created with a specific style applied. It's not that straightforward — at least not for me — but still, you can deduce what style is applied to this anonymous element. You can see here:
https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/layout/LayoutButton.cpp?sq=package:chromium
The interesting part:
void LayoutButton::updateAnonymousChildStyle(const LayoutObject& child,
ComputedStyle& childStyle) const {
ASSERT(!m_inner || &child == m_inner);
childStyle.setFlexGrow(1.0f);
// min-width: 0; is needed for correct shrinking.
childStyle.setMinWidth(Length(0, Fixed));
// Use margin:auto instead of align-items:center to get safe centering, i.e.
// when the content overflows, treat it the same as align-items: flex-start.
childStyle.setMarginTop(Length());
childStyle.setMarginBottom(Length());
childStyle.setFlexDirection(style()->flexDirection());
childStyle.setJustifyContent(style()->justifyContent());
childStyle.setFlexWrap(style()->flexWrap());
// TODO (lajava): An anonymous box must not be used to resolve children's auto
// values.
childStyle.setAlignItems(style()->alignItems());
childStyle.setAlignContent(style()->alignContent());
}
This gives something like this :
div span {
display: flex;
text-align: center;
min-width: 0px;
flex-grow: 1;
justify-content: center;
cursor: default;
margin: 0 auto;
height: 100%;
align-items: center;
align-content: center;
}
Then you just need to wrap the div content in that span and apply the style. All these rules are probably not all necessary or accurate but the result seems ok:
div,
button {
width: 4em;
height: 4em;
background-color: red;
padding: 0;
border: 0;
margin: 1em;
font-size: 1em;
font-family: Arial;
float: left;
}
div span {
display: flex;
text-align: center;
min-width: 0px;
flex-grow: 1;
justify-content: center;
cursor: default;
margin: 0 auto;
width: 100%;
height: 100%;
align-items: center;
align-content: center;
}
<div><span>text text</span>
</div>
<button>text text</button>
<div><span>text text text text</span>
</div>
<button>text text text text</button>
<div><span>text text text text text text</span>
</div>
<button>text text text text text text</button>
I think you may consider one of the following solutions
Solution #1
Add these to the div style
display: table-cell;
vertical-align: middle;
If you still need to use inline-block display, you can use nested div, the parent div will be displayed as (inline-block), the child div will be displayed as (table-cell) and that's where you middle the text.
Solution #2
You can set the div padding and line height dynamically using jQuery .. and this will be done on the run time, and will be adjusted based on the size of the content inside the div. you can check this question jquery set line-height equal to parent container height

How to implement this notification design and have it sensibly responsive

I am attempting to implement this, simple enough design for a notification block.
Including the ability to respond by wrapping the text block on smaller screens, similar to the below;
The intention here is to center align the notification to the parent row, and preferably when the viewport is too small, have the text wrap and height of the horizontal banner on which it sits increase in height accordingly. This will be included in a bootstrap project (may affect floats etc).
Here is a pen showing one of the more simple approaches (and probably closest so far) I've been trying to achieve this.
*,
html {
font-family: arial;
font-size: 20px;
}
.extra-row {
text-align: center;
padding: 1em;
border: 1px solid #eee;
background-color: #ccc;
}
.notification {
text-align: center;
color: #fff;
white-space: nowrap;
}
.notification-circle {
width: 150px;
height: 150px;
background-color: #3D7A1A;
-moz-border-radius: 75px;
-webkit-border-radius: 75px;
border-radius: 75px;
position: relative;
display: -webkit-flexbox;
display: -ms-flexbox;
display: -webkit-flex;
display: inline-flex;
-webkit-flex-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
justify-content: center;
}
.notification-icon {
font-size: 5em;
}
.notification-block {
min-height: 150px;
line-height: 150px;
display: inline-block;
margin-left: -30px;
vertical-align: top
}
.notification-block span {
background-color: #54A127;
padding: 1em;
padding-left: 50px;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container">
<div class="row extra-row">
<div class="col-lg-12">
<p>This is a row above</p>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="notification">
<div class="notification-circle"><span class="notification-icon">i</span>
</div>
<p class="notification-block"><span>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </span>
</p>
</div>
</div>
</div>
<div class="row extra-row">
<div class="col-lg-12">
<p>This is a row below</p>
</div>
</div>
</div>
There's quite a few suggestions for vertically centering text in this manner, most appear to rely on line-height which is an issue here with wrapping the text.
This may not be the best approach due to using line-height, but the problems here are;
Preventing the circular container and text container from
wrapping.
Wrapping the text within the container while still
maintaining the overall height/vertically centered position of the text block.
Wrapping the text with a sensible line-height.
Adding white-space: nowrap; to the .notification element does prevent #1, but prevents the text from wrapping, which simply extends past the viewport.
Can anyone shed any light on a better approach? Any thoughts would be appreciated.
Many thanks,
Baps.
Hopefully this sets you on the right path.
I've removed a lot of unnecessary code. I've also removed the prefixes for the demo.
This adjustment may be all you need:
.notification {
display: flex; /* 1 */
align-items: center; /* 2 */
color:#fff;
}
.notification-circle {
flex: 0 0 150px; /* 3 */
height: 150px;
background-color: #3D7A1A;
border-radius: 75px;
display: flex;
align-items: center;
justify-content: center;
}
.notification-block {
margin-left: -50px; /* 4 */
background-color: #54A127; /* 5 */
padding: 1em; /* 5 */
padding-left: 75px; /* 5 */
z-index: -1; /* 6 */
}
.notification-block span { }
.notification-icon { font-size: 5em; }
Revised Codepen
Notes:
Make wrapper a flex container
Vertically center both flex children (.notification-circle and .notification-block)
Don't grow. Don't shrink. Remain fixed at 150px width.
Changed from margin-left: -30px
Relocated code from span child
Ensure .notification-block doesn't overlap .notification-circle

Vertical-align on h1 just won't work?

I'm trying to align the text in a h1 vertically to the middle, seeing as the text might wrap it needs to look nice whether it's 1 line or 2.
This is the css I use:
h1 {
font-size: 12pt;
line-height: 10pt;
min-height: 30px;
vertical-align: middle;
}
The html is quite simply:
<h1>title</h1>
No matter what value I enter for vertical-align, the text is always at the top of the h1 element.
Am I miss-understanding the vertical-align property?
No CSS hacks needed. If I understand you correctly, then you can use this CSS:
h1 {
font-size: 12pt;
line-height: 10px;
padding: 10px 0;
}
See demo fiddle which equals a minimum height of 30px;
A note about vertical-align: that style only works in conjunction with - and is calculated with regard to - the line-height style. So setting line-height at 10px, putting text with height 12pt leaves no space to align at all. But setting line-height to 30px would result in too much space between more lines of text. This shows a trick for vertical aligning several lines of text, but that is only needed when you have a fixed height container. In this case the container's height (the h1 element) is fluid, so you can use this simple padding solution.
I dont know about vertical align, but if you add height property and set height and line-height properties same you get the vertical align: center effect
h1
{
font-size: 12pt;
line-height: 50px;
height: 50px;
}
Center the H1 title using flexbox align items center and justify content center, see this example:
div {
padding: 1em;
border: 1px dashed purple;
}
h1 {
display: flex;
align-items: center;
justify-content: center;
}
<div>
<h1>Center this h1</h1>
</div>
Just add a float property and use padding-top: 50% for example:
h1 {
font-size: 12pt;
line-height: 10pt;
min-height: 30px;
position: absolute;
float: center; /* If you want it to be centered */
padding-top: 50%;
}
I used a CSS custom property (variable) and calc
:root {
--header-height: 100px;
}
* {
margin: 0;
padding: 0;
}
header {
font-size: 16px;
height: var(--header-height);
justify-content: space-evenly;
display: flex;
border-bottom: 1px solid #000;
}
h1,i {
font-size: 1.2rem;
display: inline-block;
padding-top: calc(var(--header-height) - 1.2rem);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" rel="stylesheet"/>
<header>
<img src="https://placekitten.com/100/100" alt="logo" height="100">
<h1>
Kitten Stories
</h1>
<i class="fas fa-lock"></i>
</header>