I want to make a responsive layout. But I am doing something wrong. This is how I want to make my layout look like
.row_4 {
background-color: #F9F8FD;
height: 14.87%;
width: 100%;
display: flex;
flex-flow: row;
justify-content: space-between;
}
.info {
margin-left: 4.83%;
margin-top: 2.9%;
float: left;
}
.action {
display: flex;
flex-flow: row;
margin-right: 3%;
}
<div class="row_4" id="rapper_1">
<div class="pfp">
<img src="profile_pics/eminem.jpg" alt="Eminem">
</div>
<div class="info">
<div class="name">
Eminem
</div>
<div class="number">
7867598568
</div>
<div class="designation">
RAPGOD
</div>
</div>
<div class="action">
<div class="message">
<i id="sms_logo" class="fa fa-comment-dots"></i>
</div>
<div class="call">
<i id="phone_logo" class="fa fa-phone"></i>
</div>
</div>
</div>
I never suggest using margin and % for centering stuff,
just flexbox, with their properties like justify and align
* {
/* this is important so image don't go outside the card div after writing 100% with padding */
box-sizing: border-box;
}
.row_4 {
display: flex;
background-color: #f9f8fd;
/* with this type of card, normally we try to make them responsive by width, not height. so is good having a static value here */
/* the card is 10rem (since I counted that you are using 15%, and my screen is 999px so 15% of 999px is 150px, that translate to 10rem (1rem = 16px) */
height: 10rem;
border-radius: 1rem;
}
.pfp img {
/* this 100% will only work if you added on the top box-sizing */
/* because the height then it will be (10rem - (0.5rem * 2)) */
height: 100%;
padding: 0.5rem;
border-radius: 1rem;
}
.info {
display: flex;
/* this make them like grid behaviur, but in flexbox */
flex-direction: column;
/* in the html a wrapped the first two elements in one div, so this will work */
justify-content: space-between;
padding: 1rem 0.5rem;
}
.action {
display: flex;
align-items: center;
justify-content: center;
/* so the .action can have all the width that remains, to can be centered responsivelly */
flex: 1;
gap: 1rem;
color: orange;
}
/* not important this next lines, just styling */
.info .name {
font-size: 2rem;
font-weight: 800;
}
.info .number {
opacity: 0.5;
}
/* .row_4 > * {
border: 1px dashed red;
} */
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css" integrity="sha512-1sCRPdkRXhBV2PBLUdRb4tMg1w2YPf37qatUFeS7zlBy7jJI8Lf4VHwWfZZfpXtYSLy85pkm9GaYVYMfw5BC1A==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
</head>
<body>
<div class="row_4" id="rapper_1">
<!-- 1 -->
<div class="pfp">
<img src="https://picsum.photos/200" alt="Eminem" />
</div>
<!-- 2 -->
<div class="info">
<!-- here I changed some stuff -->
<!-- basically I wrapped the first two element inside one, so we can add a space-between successfully -->
<div>
<div class="name">Eminem</div>
<div class="number">7867598568</div>
</div>
<div class="designation">RAPGOD</div>
</div>
<!-- 3 -->
<div class="action">
<div class="message">
<i id="sms_logo" class="fa fa-comment-dots"></i>
</div>
<div class="call">
<i id="phone_logo" class="fa fa-phone"></i>
</div>
</div>
</div>
</body>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
background: black;
/* ^^^ for demo purposes. because putting white on white is dumb */
}
.profile {
display: flex;
background: white;
padding: 0.25em;
border-radius: 10px;
justify-content: space-between;
max-width: 80%;
margin: 0 auto;
}
.profile__wrapper {
display: flex;
gap: .675em;
}
.profile__image {
background-size: cover;
aspect-ratio: 1;
width: 80px;
border-radius: 10px;
}
.profile__info {
display: flex;
flex-direction: column;
justify-content: space-between;
margin-block: .5em .25em;
}
.profile__name {
font-family: sans-serif;
color: hsl(0 0% 50%);
font-weight: 700;
}
.profile__number {
color: hsl(220 100% 50%);
font-size: .8rem;
}
.profile__msg>svg {
width: 1.5rem;
color: orange
}
.profile__call>svg {
width: 2rem;
color: orange;
}
.profile__buttons {
margin: auto 0;
margin-right: 1.5em;
display: flex;
gap: 1em;
justify-content: center;
align-items: center;
}
<div class="profile">
<div class="profile__wrapper">
<div class="profile__image" style="background-image: url('https://randomuser.me/api/portraits/men/83.jpg')"></div>
<div class="profile__info">
<div class="profile__info_wrapper">
<div class="profile__name">Uncle Joe</div>
<div class="profile__number">123456</div>
</div>
<div class="profile__nickname">Broseph</div>
</div>
</div>
<div class="profile__buttons">
<div class="profile__msg">
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 512 512"><defs><style>.cls-1{fill: CurrentColor;}</style></defs><path class="cls-1" d="M448,76.56A38.44,38.44,0,0,1,486.4,115v230.4a38.44,38.44,0,0,1-38.4,38.4H66.2l-7.5,7.5-33.1,33.1V115A38.44,38.44,0,0,1,64,76.56H448M448,51H64A64,64,0,0,0,0,115V443.21A17.78,17.78,0,0,0,17.92,461a17.42,17.42,0,0,0,12.45-5.25L76.8,409.36H448a64,64,0,0,0,64-64V115a64,64,0,0,0-64-64Z"/><path class="cls-1" d="M332.8,191.76H179.2a12.8,12.8,0,0,1,0-25.6H332.8a12.8,12.8,0,1,1,0,25.6Z"/><path class="cls-1" d="M332.8,243H179.2a12.8,12.8,0,1,1,0-25.6H332.8a12.8,12.8,0,1,1,0,25.6Z"/><path class="cls-1" d="M332.8,294.16H179.2a12.8,12.8,0,1,1,0-25.6H332.8a12.8,12.8,0,0,1,0,25.6Z"/></svg>
</div>
<div class="profile__call">
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 512 512"><defs>
<style xmlns="http://www.w3.org/2000/svg">
.svg__phone__call1 {
transform: rotate(-45deg);
transform-origin: center center
}
</style>
</defs><path xmlns="http://www.w3.org/2000/svg" class="svg__phone__call1" d="M258.7,80.74,236.91,101.4c-74.85,72.75-64.43,247,0,309.87l21.79,20.66c5.68,5.39,15.16,5.39,21.79,0l42.64-41.32a14.64,14.64,0,0,0,0-20.66L276.7,324.15l-50.22,3.59c-15.16-14.37-15.16-129.34,0-143.71l52.11,2.69,44.53-44a14.64,14.64,0,0,0,0-20.66L280.49,80.74C273.86,74.46,264.39,74.46,258.7,80.74Z" fill="CurrentColor"/></svg>
</div>
</div>
In this answer I used a lot of flexbox tricks to create the layout.
let's break them down 1 by 1:
I wrapped the whole profile card with a div <div class="profile"></div>. If we look at its CSS, we can see that I put display: flex and justify-content: space-between. Flexbox puts the direct children on a horizontal line and space-between stores them like this: it takes all the available space at puts it between the flex items.
inside the profile div, we have 2 sections: profile-wrapper and profile-buttons. Let's start with profile-wrapper, it's a flex container with a gap, pretty basic. Now profile-buttons, it's a flex container with justify-content: center and align-items: center, they are both used to center the content of the flex container vertically and horizontally.
profile-image: it has background-size: cover. It's used to make the background shrink or grow to match the size of the element.
profile-info: it has display: flex combined with flex-direction: column to make the elements stackup vertically.
profile-info-wrapper: this div is just used to wrap the name and the phone number fields to make them act like one element. (check layout to understand the purpose).
FOR MORE INFO ON FLEXBOX LAYOUTS: Check MDN's docs
EXTRAS:
CSS grid
Free Course by CSS Guru Kevin Powell on responsive layouts
Related
I want to make the background color fill the area so it's always the same height for the longest amount of text, and center the text vertically, regardless of how many lines it is. I don't want to set a fixed height on the parent if possible as that may change.
.flexbox {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-left: -8px;
margin-right: -8px;
}
.flexbox .sm-col-3 {
width: calc(1/3 * 100% - 16px);
}
.entry {
position: relative;
}
.entry-image {
display: block;
margin: 0 auto;
}
.entry-title {
margin: 0
}
.entry-title-link {
position: absolute;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
padding: 8px 9px 9px;
background: rgba(0, 87, 149, 1);
color: #fff;
width: 100%;
}
<div class="articles-container flexbox">
<div class="entry sm-col-3">
<div class="entry-header">
<a href="#" class="entry-image-link"><img
src="https://cdn.shopify.com/s/files/1/0533/2089/files/placeholder-images-product-6_large.png"></a>
</div>
<div class="entry-content">
<h2 class="entry-title">
Some Long Wrapping Two Line Text
</h2>
</div>
<div class="entry-footer"></div>
</div>
<div class="entry sm-col-3">
<div class="entry-header">
<a href="#" class="entry-image-link"><img
src="https://cdn.shopify.com/s/files/1/0533/2089/files/placeholder-images-product-6_large.png"></a>
</div>
<div class="entry-content">
<h2 class="entry-title">
One Line Text
</h2>
</div>
<div class="entry-footer"></div>
</div>
</div>
You should think of this problem in terms of 2 different layouts.
the first one is to put your entry divs next to each other, 3 per line, same height each. That's the flex row you are using on .flexbox
the second one is within each entry div, to put the image on top and the link on the bottom. That's what I'm proposing here with another flex layout, nested inside the first one.
So the way to do this is to apply flex and column on .sm-col-3 to create the nested flex layout. And then it's just up to you how you need to allocate the space. The most common way to do it in this type of case would be to allocate a fixed size (or at least fixed ratio) to the image on top, and then put a flex: 1 on the text at the bottom so that it will occupy everything that's left, thus occupying the same amount of space on each entry.
Now if you also need to vertically center the next in that bottom section .entry-content, that is a 3rd problem to be solved.
the box at the bottom should have its content vertically centered
Except that now that we've divided the problem into its sub-problems, that 3rd one is easy to solve (tons of tutorials online on how to vertically center something within its parent). But since we're doing flexboxes here, let's use that a third time. That's going to be display: flex and align-items on .entry-content.
.flexbox {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-left: -8px;
margin-right: -8px;
}
.flexbox .sm-col-3 {
width: calc(1/3 * 100% - 16px);
display: flex;
flex-direction: column;
}
.entry {
position: relative;
}
.entry-image {
display: block;
margin: 0 auto;
}
.entry-content {
flex: 1;
background: rgba(0, 87, 149, 1);
padding: 8px 9px 9px;
display: flex;
align-items: center;
}
.entry-title {
margin: 0;
}
.entry-title-link {
text-align: center;
color: #fff;
width: 100%;
}
<div class="articles-container flexbox">
<div class="entry sm-col-3">
<div class="entry-header">
<a href="#" class="entry-image-link"><img
src="https://cdn.shopify.com/s/files/1/0533/2089/files/placeholder-images-product-6_large.png"></a>
</div>
<div class="entry-content">
<h2 class="entry-title">
Some Long Wrapping Two Line Text
</h2>
</div>
<div class="entry-footer"></div>
</div>
<div class="entry sm-col-3">
<div class="entry-header">
<a href="#" class="entry-image-link"><img
src="https://cdn.shopify.com/s/files/1/0533/2089/files/placeholder-images-product-6_large.png"></a>
</div>
<div class="entry-content">
<h2 class="entry-title">
One Line Text
</h2>
</div>
<div class="entry-footer"></div>
</div>
</div>
I have three columns inside a div called row and each column is in a div called third-col. I want the three columns side by side (inline) and then the next div contact to be below them. Currently all of the divs are in block one after another.
Another problem I'm having is with my home image. When the browser window is not maximized I want the image to still stretch to the bottom of the page.
img {
padding: 0;
display: block;
margin: 0 auto;
max-height: 100%;
max-width: 100%;
text-align: center;
}
.row {
padding: 0 20px;
display: inline;
}
.third-col {
width: 30.3%;
font-size: 16px;
display: inline;
}
.col {
float: left;
box-sizing: border-box;
}
<img class="center" src="homepage.jpg" alt="">
<section id="skills">
<p class="header">My Skills</p>
<div class="skillsContainer">
<div id="row">
<div class="third-col">
<ul>
<li>items</li>
</ul>
</div>
</div>
</div>
</section>
For you background-image, you will want it to set it using CSS. This will allow it to stretch from side to side, top to bottom. Here is an example:
.body { margin: 0; padding: 0;}
.full-page-image {
background-image: url(https://images.unsplash.com/photo-1489914099268-1dad649f76bf?auto=format&fit=crop&w=2850&q=80);
background-size: cover; /* THIS MAKES THE IMAGE STRETCH TO ALWAYS COVER THE PAGE */
background-position: center center;
position: relative;
width: 100%;
height: 100vh; /* This is 100% of the height */
}
<div class="full-page-image"></div>
<h1>Page content goes here</h1>
For the rows, I suggest using flexbox. Here is a complete guide: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
The idea is that each row is 100% of the witdh of the page. The content inside the row will be divided by the width you want. Here is an example:
.row{
padding: 0 20px;
display: flex; /* Makes the sub-elements flex */
flex-wrap: wrap; /* Forces flexbox to respect children width */
align-items: stretch; /* Makes childs the same height */
}
.third-col{
width: 33%;
font-size: 16px;
min-height: 40px;
}
<div class="row">
<div class="third-col">Col 1</div>
<div class="third-col">Col 2</div>
<div class="third-col">Col 3</div>
</div>
<div class="row">
<div>Other page content</div>
</div>
Imagine the following layout, where the dots represent the space between the boxes:
[Left box]......[Center box]......[Right box]
When I remove the right box, I like the center box to still be in the center, like so:
[Left box]......[Center box].................
The same goes for if I would remove the left box.
................[Center box].................
Now when the content within the center box gets longer, it will take up as much available space as needed while remaining centered. The left and right box will never shrink and thus when where is no space left the overflow:hidden and text-overflow: ellipsis will come in effect to break the content;
[Left box][Center boxxxxxxxxxxxxx][Right box]
All the above is my ideal situation, but I have no idea how to accomplish this effect. Because when I create a flex structure like so:
.parent {
display : flex; // flex box
justify-content : space-between; // horizontal alignment
align-content : center; // vertical alignment
}
If the left and right box would be exactly the same size, I get the desired effect. However when one of the two is from a different size the centered box is not truly centered anymore.
Is there anyone that can help me?
Update
A justify-self would be nice, this would be ideal:
.leftBox {
justify-self : flex-start;
}
.rightBox {
justify-self : flex-end;
}
If the left and right boxes would be exactly the same size, I get the desired effect. However when one of the two is a different size the centered box is not truly centered anymore. Is there anyone that can help me?
Here's a method using flexbox to center the middle item, regardless of the width of siblings.
Key features:
pure CSS
no absolute positioning
no JS/jQuery
Use nested flex containers and auto margins:
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box:first-child > span { margin-right: auto; }
.box:last-child > span { margin-left: auto; }
/* non-essential */
.box {
align-items: center;
border: 1px solid #ccc;
background-color: lightgreen;
height: 40px;
}
p {
text-align: center;
margin: 5px 0 0 0;
}
<div class="container">
<div class="box"><span>short text</span></div>
<div class="box"><span>centered text</span></div>
<div class="box"><span>loooooooooooooooong text</span></div>
</div>
<p>↑<br>true center</p>
Here's how it works:
The top-level div (.container) is a flex container.
Each child div (.box) is now a flex item.
Each .box item is given flex: 1 in order to distribute container space equally (more details).
Now the items are consuming all space in the row and are equal width.
Make each item a (nested) flex container and add justify-content: center.
Now each span element is a centered flex item.
Use flex auto margins to shift the outer spans left and right.
You could also forgo justify-content and use auto margins exclusively.
But justify-content can work here because auto margins always have priority.
8.1. Aligning with auto
margins
Prior to alignment via justify-content and align-self, any
positive free space is distributed to auto margins in that dimension.
Use three flex items in the container
Set flex: 1 to the first and last ones. This makes them grow equally to fill the available space left by the middle one.
Thus, the middle one will tend to be centered.
However, if the first or last item has a wide content, that flex item will also grow due to the new min-width: auto initial value.
Note Chrome doesn't seem to implement this properly. However, you can set min-width to -webkit-max-content or -webkit-min-content and it will work too.
Only in that case the middle element will be pushed out of the center.
.outer-wrapper {
display: flex;
}
.item {
background: lime;
margin: 5px;
}
.left.inner-wrapper, .right.inner-wrapper {
flex: 1;
display: flex;
min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.right.inner-wrapper {
justify-content: flex-end;
}
.animate {
animation: anim 5s infinite alternate;
}
#keyframes anim {
from { min-width: 0 }
to { min-width: 100vw; }
}
<div class="outer-wrapper">
<div class="left inner-wrapper">
<div class="item animate">Left</div>
</div>
<div class="center inner-wrapper">
<div class="item">Center</div>
</div>
<div class="right inner-wrapper">
<div class="item">Right</div>
</div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item animate">Center</div></div><div class="right inner-wrapper"><div class="item">Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item">Center</div></div><div class="right inner-wrapper"><div class="item animate">Right</div></div></div>
The key is to use flex-basis. Then the solution is simple as:
.parent {
display: flex;
justify-content: space-between;
}
.left, .right {
flex-grow: 1;
flex-basis: 0;
}
CodePen is available here.
Here's an answer that uses grid instead of flexbox. This solution doesn't require extra grandchild elements in the HTML like the accepted answer does. And it works correctly even when the content on one side gets long enough to overflow into the center, unlike the grid answer from 2019.
The one thing this solution doesn't do is show an ellipsis or hide the extra content in the center box, as described in the question.
section {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
section > *:last-child {
white-space: nowrap;
text-align: right;
}
/* not essential; just for demo purposes */
section {
background-color: #eee;
font-family: helvetica, arial;
font-size: 10pt;
padding: 4px;
}
section > * {
border: 1px solid #bbb;
padding: 2px;
}
<section>
<div>left</div>
<div>center</div>
<div>right side is longer</div>
</section>
<section>
<div>left</div>
<div>center</div>
<div>right side is much, much longer</div>
</section>
<section>
<div>left</div>
<div>center</div>
<div>right side is much, much longer, super long in fact</div>
</section>
Instead of defaulting to using flexbox, using grid solves it in 2 lines of CSS without additional markup inside the top level children.
HTML:
<header class="header">
<div class="left">variable content</div>
<div class="middle">variable content</div>
<div class="right">variable content which happens to be very long</div>
</header>
CSS:
.header {
display: grid;
grid-template-columns: [first] 20% auto [last] 20%;
}
.middle {
/* use either */
margin: 0 auto;
/* or */
text-align: center;
}
Flexbox rocks but shouldn't be the answer for everything. In this case grid is clearly the cleanest option.
Even made a codepen for your testing pleasure:
https://codepen.io/anon/pen/mooQOV
You can do this like so:
.bar {
display: flex;
background: #B0BEC5;
}
.l {
width: 50%;
flex-shrink: 1;
display: flex;
}
.l-content {
background: #9C27B0;
}
.m {
flex-shrink: 0;
}
.m-content {
text-align: center;
background: #2196F3;
}
.r {
width: 50%;
flex-shrink: 1;
display: flex;
flex-direction: row-reverse;
}
.r-content {
background: #E91E63;
}
<div class="bar">
<div class="l">
<div class="l-content">This is really long content. More content. So much content.</div>
</div>
<div class="m">
<div class="m-content">This will always be in the center.</div>
</div>
<div class="r">
<div class="r-content">This is short.</div>
</div>
</div>
Here is another way to do it, using display: flex in the parents and childs:
.Layout{
display: flex;
justify-content: center;
}
.Left{
display: flex;
justify-content: flex-start;
width: 100%;
}
.Right{
display: flex;
justify-content: flex-end;
width: 100%;
}
<div class = 'Layout'>
<div class = 'Left'>I'm on the left</div>
<div class = 'Mid'>Centered</div>
<div class = 'Right'>I'm on the right</div>
</div>
A slightly more robust grid solution looks like this:
.container {
overflow: hidden;
border-radius: 2px;
padding: 4px;
background: orange;
display: grid;
grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr);
}
.item > div {
display: inline-block;
padding: 6px;
border-radius: 2px;
background: teal;
}
.item:last-child > div {
float: right;
}
<div class="container">
<div class="item"><div contenteditable>edit the text to test the layout</div></div>
<div class="item"><div contenteditable>just click me and</div></div>
<div class="item"><div contenteditable>edit</div></div>
</div>
And here you can see it in Codepen: https://codepen.io/benshope2234/pen/qBmZJWN
I wanted the exact result shown in the question, I combined answers from gamliela and Erik Martín Jordán and it works best for me.
.parent {
display: flex;
justify-content: space-between;
}
.left, .right {
flex-grow: 1;
flex-basis: 0;
}
.right {
display: flex;
justify-content: flex-end;
}
you can also use this simple way to reach exact center alignment for middle element :
.container {
display: flex;
justify-content: space-between;
}
.container .sibling {
display: flex;
align-items: center;
height: 50px;
background-color: gray;
}
.container .sibling:first-child {
width: 50%;
display: flex;
justify-content: space-between;
}
.container .sibling:last-child {
justify-content: flex-end;
width: 50%;
box-sizing: border-box;
padding-left: 100px; /* .center's width divided by 2 */
}
.container .sibling:last-child .content {
text-align: right;
}
.container .sibling .center {
height: 100%;
width: 200px;
background-color: lightgreen;
transform: translateX(50%);
}
codepen: https://codepen.io/ErAz7/pen/mdeBKLG
Althought I might be late on this one, all those solutions seems complicated and may not work depending on the cases you're facing.
Very simply, just wrap the component you want to center with position : absolute, while letting the other two with justify-content : space-between, like so :
CSS:
.container {
display: flex;
justify-content: space-between;
align-items: center;
background-color: lightgray;
}
.middle {
position: absolute;
margin-left: auto;
margin-right: auto;
/* You should adapt percentages here if you have a background ; else, left: 0 and right: 0 should do the trick */
left: 40%;
right: 40%;
text-align: center;
}
/* non-essential, copied from #Brian Morearty answer */
.element {
border: 1px solid #ccc;
background-color: lightgreen;
}
p {
margin: 5px;
padding: 5px;
}
<div class="container">
<p class="element">First block</p>
<p class="middle element">Middle block</p>
<p class="element">Third THICC blockkkkkkkkk</p>
</div>
Michael Benjamin has a decent answer but there is no reason it can't / shouldn't be simplified further:
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box:first-child { justify-content: left; }
.box:last-child { justify-content: right; }
And html
<div class="container">
<div class="box">short text</div>
<div class="box">centered tex</div>
<div class="box">loooooooooooooooong text</div>
</div>
I've got a block grid of squares with text inside each. Everything works fine when there is only one line of text. More text in a square makes it move below the others and break the grid.
The other problem is that I would like one square to have an additional line of text at the top as shown by the class="notice". But I can't get this to work either.
I've created a jsfiddle to show more clearly what the issue is. I've had a look through this guide on flexbox but can't seem to solve the issue, not sure if it is related. Any help is greatly appreciated for a newbie.
<body>
<div class="container">
<div class="products">
<div class="product">
<p>Apples</p>
<span class="link"></span>
</div>
<div class="product">
<p class="notice">You won't find cheaper</p>
<p>Best price you will find on grapes</p>
<span class="link"></span>
</div>
<div class="product">
<p>Orange</p>
<span class="link"></span>
</div>
<div class="product" id="no">
<p>Best price you will find on grapes, bananas, kiwis</p>
<span class="link"></span>
</div>
<div class="product">
<p>Orange</p>
<span class="link"></span>
</div>
<div class="product">
<p>Orange</p>
<span class="link"></span>
</div>
</div>
</div>
</body>
.products {
text-align:center;
}
.product {
background-color: red;
display: inline-flex;
height: 10em;
margin-bottom: 10px;
position: relative;
width: 10em;
justify-content:center;
align-items:center;
}
.product p {
color: black;
}
.product p.notice {
font-size: 14px;
color: yellow;
}
.link {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1;
}
.product:hover, div.product:focus {
background-color: green;
}
Not sure why you need display: inline-flex for each of your product items. You could simply make the parent a flex container with display: flex, making all product items flex items.
HTML (no changes)
CSS (adjusted sections only)
.products {
display: flex; /* establish primary flex container */
flex-wrap: wrap; /* enable flex items to wrap */
justify-content: center; /* center flex items horizontally, in this case */
}
.product {
height: 10em;
width: 10em;
margin: 5px;
position: relative;
display: flex; /* establish nested flex container */
flex-direction: column; /* stack flex items vertically */
justify-content: center; /* center flex items vertically, in this case */
align-items: center; /* center flex items horizontally, in this case */
background-color: red;
}
Revised Fiddle
inline-flex, inline-block,inline-table,inline, img, .. all of them stands on a baseline, you may use vertical-align:
.product {
background-color: red;
display: inline-flex;
vertical-align:top; /* HERE */
height: 10em;
margin-bottom: 10px;
position: relative;
width: 10em;
justify-content:center;
align-items:center;
}
https://jsfiddle.net/382m8wzg/11/
Imagine the following layout, where the dots represent the space between the boxes:
[Left box]......[Center box]......[Right box]
When I remove the right box, I like the center box to still be in the center, like so:
[Left box]......[Center box].................
The same goes for if I would remove the left box.
................[Center box].................
Now when the content within the center box gets longer, it will take up as much available space as needed while remaining centered. The left and right box will never shrink and thus when where is no space left the overflow:hidden and text-overflow: ellipsis will come in effect to break the content;
[Left box][Center boxxxxxxxxxxxxx][Right box]
All the above is my ideal situation, but I have no idea how to accomplish this effect. Because when I create a flex structure like so:
.parent {
display : flex; // flex box
justify-content : space-between; // horizontal alignment
align-content : center; // vertical alignment
}
If the left and right box would be exactly the same size, I get the desired effect. However when one of the two is from a different size the centered box is not truly centered anymore.
Is there anyone that can help me?
Update
A justify-self would be nice, this would be ideal:
.leftBox {
justify-self : flex-start;
}
.rightBox {
justify-self : flex-end;
}
If the left and right boxes would be exactly the same size, I get the desired effect. However when one of the two is a different size the centered box is not truly centered anymore. Is there anyone that can help me?
Here's a method using flexbox to center the middle item, regardless of the width of siblings.
Key features:
pure CSS
no absolute positioning
no JS/jQuery
Use nested flex containers and auto margins:
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box:first-child > span { margin-right: auto; }
.box:last-child > span { margin-left: auto; }
/* non-essential */
.box {
align-items: center;
border: 1px solid #ccc;
background-color: lightgreen;
height: 40px;
}
p {
text-align: center;
margin: 5px 0 0 0;
}
<div class="container">
<div class="box"><span>short text</span></div>
<div class="box"><span>centered text</span></div>
<div class="box"><span>loooooooooooooooong text</span></div>
</div>
<p>↑<br>true center</p>
Here's how it works:
The top-level div (.container) is a flex container.
Each child div (.box) is now a flex item.
Each .box item is given flex: 1 in order to distribute container space equally (more details).
Now the items are consuming all space in the row and are equal width.
Make each item a (nested) flex container and add justify-content: center.
Now each span element is a centered flex item.
Use flex auto margins to shift the outer spans left and right.
You could also forgo justify-content and use auto margins exclusively.
But justify-content can work here because auto margins always have priority.
8.1. Aligning with auto
margins
Prior to alignment via justify-content and align-self, any
positive free space is distributed to auto margins in that dimension.
Use three flex items in the container
Set flex: 1 to the first and last ones. This makes them grow equally to fill the available space left by the middle one.
Thus, the middle one will tend to be centered.
However, if the first or last item has a wide content, that flex item will also grow due to the new min-width: auto initial value.
Note Chrome doesn't seem to implement this properly. However, you can set min-width to -webkit-max-content or -webkit-min-content and it will work too.
Only in that case the middle element will be pushed out of the center.
.outer-wrapper {
display: flex;
}
.item {
background: lime;
margin: 5px;
}
.left.inner-wrapper, .right.inner-wrapper {
flex: 1;
display: flex;
min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.right.inner-wrapper {
justify-content: flex-end;
}
.animate {
animation: anim 5s infinite alternate;
}
#keyframes anim {
from { min-width: 0 }
to { min-width: 100vw; }
}
<div class="outer-wrapper">
<div class="left inner-wrapper">
<div class="item animate">Left</div>
</div>
<div class="center inner-wrapper">
<div class="item">Center</div>
</div>
<div class="right inner-wrapper">
<div class="item">Right</div>
</div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item animate">Center</div></div><div class="right inner-wrapper"><div class="item">Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item">Center</div></div><div class="right inner-wrapper"><div class="item animate">Right</div></div></div>
The key is to use flex-basis. Then the solution is simple as:
.parent {
display: flex;
justify-content: space-between;
}
.left, .right {
flex-grow: 1;
flex-basis: 0;
}
CodePen is available here.
Here's an answer that uses grid instead of flexbox. This solution doesn't require extra grandchild elements in the HTML like the accepted answer does. And it works correctly even when the content on one side gets long enough to overflow into the center, unlike the grid answer from 2019.
The one thing this solution doesn't do is show an ellipsis or hide the extra content in the center box, as described in the question.
section {
display: grid;
grid-template-columns: 1fr auto 1fr;
}
section > *:last-child {
white-space: nowrap;
text-align: right;
}
/* not essential; just for demo purposes */
section {
background-color: #eee;
font-family: helvetica, arial;
font-size: 10pt;
padding: 4px;
}
section > * {
border: 1px solid #bbb;
padding: 2px;
}
<section>
<div>left</div>
<div>center</div>
<div>right side is longer</div>
</section>
<section>
<div>left</div>
<div>center</div>
<div>right side is much, much longer</div>
</section>
<section>
<div>left</div>
<div>center</div>
<div>right side is much, much longer, super long in fact</div>
</section>
Instead of defaulting to using flexbox, using grid solves it in 2 lines of CSS without additional markup inside the top level children.
HTML:
<header class="header">
<div class="left">variable content</div>
<div class="middle">variable content</div>
<div class="right">variable content which happens to be very long</div>
</header>
CSS:
.header {
display: grid;
grid-template-columns: [first] 20% auto [last] 20%;
}
.middle {
/* use either */
margin: 0 auto;
/* or */
text-align: center;
}
Flexbox rocks but shouldn't be the answer for everything. In this case grid is clearly the cleanest option.
Even made a codepen for your testing pleasure:
https://codepen.io/anon/pen/mooQOV
You can do this like so:
.bar {
display: flex;
background: #B0BEC5;
}
.l {
width: 50%;
flex-shrink: 1;
display: flex;
}
.l-content {
background: #9C27B0;
}
.m {
flex-shrink: 0;
}
.m-content {
text-align: center;
background: #2196F3;
}
.r {
width: 50%;
flex-shrink: 1;
display: flex;
flex-direction: row-reverse;
}
.r-content {
background: #E91E63;
}
<div class="bar">
<div class="l">
<div class="l-content">This is really long content. More content. So much content.</div>
</div>
<div class="m">
<div class="m-content">This will always be in the center.</div>
</div>
<div class="r">
<div class="r-content">This is short.</div>
</div>
</div>
Here is another way to do it, using display: flex in the parents and childs:
.Layout{
display: flex;
justify-content: center;
}
.Left{
display: flex;
justify-content: flex-start;
width: 100%;
}
.Right{
display: flex;
justify-content: flex-end;
width: 100%;
}
<div class = 'Layout'>
<div class = 'Left'>I'm on the left</div>
<div class = 'Mid'>Centered</div>
<div class = 'Right'>I'm on the right</div>
</div>
A slightly more robust grid solution looks like this:
.container {
overflow: hidden;
border-radius: 2px;
padding: 4px;
background: orange;
display: grid;
grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr);
}
.item > div {
display: inline-block;
padding: 6px;
border-radius: 2px;
background: teal;
}
.item:last-child > div {
float: right;
}
<div class="container">
<div class="item"><div contenteditable>edit the text to test the layout</div></div>
<div class="item"><div contenteditable>just click me and</div></div>
<div class="item"><div contenteditable>edit</div></div>
</div>
And here you can see it in Codepen: https://codepen.io/benshope2234/pen/qBmZJWN
I wanted the exact result shown in the question, I combined answers from gamliela and Erik Martín Jordán and it works best for me.
.parent {
display: flex;
justify-content: space-between;
}
.left, .right {
flex-grow: 1;
flex-basis: 0;
}
.right {
display: flex;
justify-content: flex-end;
}
you can also use this simple way to reach exact center alignment for middle element :
.container {
display: flex;
justify-content: space-between;
}
.container .sibling {
display: flex;
align-items: center;
height: 50px;
background-color: gray;
}
.container .sibling:first-child {
width: 50%;
display: flex;
justify-content: space-between;
}
.container .sibling:last-child {
justify-content: flex-end;
width: 50%;
box-sizing: border-box;
padding-left: 100px; /* .center's width divided by 2 */
}
.container .sibling:last-child .content {
text-align: right;
}
.container .sibling .center {
height: 100%;
width: 200px;
background-color: lightgreen;
transform: translateX(50%);
}
codepen: https://codepen.io/ErAz7/pen/mdeBKLG
Althought I might be late on this one, all those solutions seems complicated and may not work depending on the cases you're facing.
Very simply, just wrap the component you want to center with position : absolute, while letting the other two with justify-content : space-between, like so :
CSS:
.container {
display: flex;
justify-content: space-between;
align-items: center;
background-color: lightgray;
}
.middle {
position: absolute;
margin-left: auto;
margin-right: auto;
/* You should adapt percentages here if you have a background ; else, left: 0 and right: 0 should do the trick */
left: 40%;
right: 40%;
text-align: center;
}
/* non-essential, copied from #Brian Morearty answer */
.element {
border: 1px solid #ccc;
background-color: lightgreen;
}
p {
margin: 5px;
padding: 5px;
}
<div class="container">
<p class="element">First block</p>
<p class="middle element">Middle block</p>
<p class="element">Third THICC blockkkkkkkkk</p>
</div>
Michael Benjamin has a decent answer but there is no reason it can't / shouldn't be simplified further:
.container {
display: flex;
}
.box {
flex: 1;
display: flex;
justify-content: center;
}
.box:first-child { justify-content: left; }
.box:last-child { justify-content: right; }
And html
<div class="container">
<div class="box">short text</div>
<div class="box">centered tex</div>
<div class="box">loooooooooooooooong text</div>
</div>