I'm trying to build a simple teaser grid for featured posts on a website using flexbox. It should look like this:
And in FF and Chrome it's all good. If i change the resolution of one image, all the others follow and update their size. But not in Safari. Whatever i do, it never fits to an equal height:
I really don't get the point why this is happening. Each image container on the right has exactly 50% of the height calculated by flexbox. And each image should be stretched to that height.
I could probably achieve this with background-size:cover but i would love to find a solution to use img tags instead.
Here's a demo: https://jsfiddle.net/7tjw8j83/1/
.featured-grid{
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
}
img{
width: 100%;
height: 100%;
display: block;
object-fit:cover;
}
.left{
width: 66.6666%;
}
.right{
width: 33.3333%;
display: flex;
flex-direction: column;
}
.right-top{
background: green;
flex: 1;
}
.right-bottom{
background: red;
flex: 1;
}
<div class="featured-grid">
<div class="left">
<img src="https://unsplash.it/600/450?image=1055">
</div>
<div class="right">
<div class="right-top">
<img src="https://unsplash.it/600/400?image=1051">
</div>
<div class="right-bottom">
<img src="https://unsplash.it/600/400?image=1057">
</div>
</div>
</div>
In addition to Michaels suggestion, you could do like this, where I used background-image instead of img (since you use a given height anyway), and how to add text at an absolute position
html, body {
margin: 0;
}
.featured-grid{
display: flex;
height: 100vh;
}
div {
position: relative;
background-position: center;
background-repeat: no-reapat;
background-size: cover;
overflow: hidden;
}
.left {
width: 66.666%;
}
.right{
width: 33.333%;
display: flex;
flex-direction: column;
}
.right-top{
flex: 1;
}
.right-bottom{
flex: 1;
}
.text {
position: absolute;
left: 10px;
bottom: 10px;
color: white;
}
.text > * {
margin: 5px;
}
<div class="featured-grid">
<div class="left" style="background-image: url(https://unsplash.it/600/450?image=1055)">
<div class="text">
<h2>Title</h2>
<h3>Text</h3>
</div>
</div>
<div class="right">
<div class="right-top" style="background-image: url(https://unsplash.it/600/400?image=1051)">
<div class="text">
<h2>Title</h2>
<h3>Text</h3>
</div>
</div>
<div class="right-bottom" style="background-image: url(https://unsplash.it/600/400?image=1057)">
<div class="text">
<h2>Title</h2>
<h3>Text</h3>
</div>
</div>
</div>
</div>
Updated based on a comment
html, body {
margin: 0;
}
.featured-grid{
display: flex;
height: 100vh;
}
div {
position: relative;
overflow: hidden;
}
img{
width: 100%;
height: 100%;
display: block;
object-fit:cover;
}
.left {
width: 66.666%;
}
.right{
width: 33.333%;
display: flex;
flex-direction: column;
}
.right-top{
flex: 1;
}
.right-bottom{
flex: 1;
}
.text {
position: absolute;
left: 10px;
bottom: 10px;
color: white;
}
.text > * {
margin: 5px;
}
<div class="featured-grid">
<div class="left">
<img src="https://unsplash.it/600/450?image=1055">
<div class="text">
<h2>Title</h2>
<h3>Text</h3>
</div>
</div>
<div class="right">
<div class="right-top">
<img src="https://unsplash.it/600/400?image=1051">
<div class="text">
<h2>Title</h2>
<h3>Text</h3>
</div>
</div>
<div class="right-bottom">
<img src="https://unsplash.it/600/400?image=1057"> <div class="text">
<h2>Title</h2>
<h3>Text</h3>
</div>
</div>
</div>
</div>
Updated (2:nd) based on a comment
html,
body {
margin: 0;
}
.featured-grid {
display: flex;
}
div {
position: relative;
overflow: hidden;
}
img {
visibility: hidden;
display: block;
}
img.show {
position: absolute;
visibility: visible;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
.left img {
max-height: 100vh;
}
.right img {
max-height: 50vh;
}
.left {
width: 66.666%;
}
.right {
width: 33.333%;
display: flex;
flex-direction: column;
}
.right-top {
flex: 1;
}
.right-bottom {
flex: 1;
}
.text {
position: absolute;
left: 10px;
bottom: 10px;
color: white;
}
.text > * {
margin: 5px;
}
<div class="featured-grid">
<div class="left">
<img src="https://unsplash.it/300/250?image=1055">
<img class="show" src="https://unsplash.it/300/250?image=1055">
<div class="text">
<h2>Title 1</h2>
<h3>Text 1</h3>
</div>
</div>
<div class="right">
<div class="right-top">
<img src="https://unsplash.it/300/200?image=1057">
<img class="show" src="https://unsplash.it/300/200?image=1057">
<div class="text">
<h2>Title 2</h2>
<h3>Text 2</h3>
</div>
</div>
<div class="right-bottom">
<img src="https://unsplash.it/300/200?image=1057">
<img class="show" src="https://unsplash.it/300/200?image=1057">
<div class="text">
<h2>Title 3</h2>
<h3>Text 3</h3>
</div>
</div>
</div>
</div>
Related
Help me adjust my code so that it will be working in Safari. Initially I used answer from here with a few adjustments. I needed my card to be responsive and has some additional elements at the bottom.
Here's my code:
.gallery {
display: grid;
gap: 15px;
grid-template-columns: repeat(2, 1fr);
}
.card {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.14);
max-width: 200px;
padding: 10px 10px 20px;
cursor: pointer;
position: relative;
}
.wrapper {
width: 100%;
position: relative;
margin-bottom: 20px;
}
.wrapper::before {
content: '';
padding-bottom: 100%;
display: block;
}
.img-grid {
display: grid;
border-radius: 4px;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 3px;
overflow: hidden;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.img-grid > div {
position: relative;
width: 100%;
height: 100%;
}
.img-grid > div:first-child {
grid-column: 1 / span 2;
}
img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}
.logo {
width: 50px;
height: 50px;
background: gainsboro;
float: left;
margin-right: 15px;
}
h4,p {
margin: 3px 0;
}
p {
font-size: 13px;
}
<div class="gallery">
<div class="card">
<div class="wrapper">
<div class="img-grid">
<div>
<img loading="lazy" src="https://cdn.pixabay.com/photo/2015/04/19/08/32/marguerite-729510_960_720.jpg"></img>
</div>
<div>
<img loading="lazy" src="https://cdn.pixabay.com/photo/2015/04/19/08/32/marguerite-729510_960_720.jpg"></img>
</div>
<div>
<img loading="lazy" src="https://cdn.pixabay.com/photo/2015/04/19/08/32/marguerite-729510_960_720.jpg"></img>
</div>
</div>
</div>
<div class="logo"></div>
<h4>Logo name</h4>
<p>Some description</p>
</div>
<div class="card">
<div class="wrapper">
<div class="img-grid">
<div>
<img loading="lazy" src="https://cdn.pixabay.com/photo/2015/04/19/08/32/marguerite-729510_960_720.jpg"></img>
</div>
<div>
<img loading="lazy" src="https://cdn.pixabay.com/photo/2015/04/19/08/32/marguerite-729510_960_720.jpg"></img>
</div>
<div>
<img loading="lazy" src="https://cdn.pixabay.com/photo/2015/04/19/08/32/marguerite-729510_960_720.jpg"></img>
</div>
</div>
</div>
<div class="logo"></div>
<h4>Logo name</h4>
<p>Some description</p>
</div>
</div>
It works fine in Chrome, but it doesn't work in Safari(current and older). It's because I needed my cards to be responsive and always maintain square grid. So I used same trick on the wrapper that's widely used to maintain responsive squares. But as a result of that height: 100% is no longer working in Safari. Is there any way to make it work? I would appreciate some your help.
.parnet{
max-width: 600px;
margin: 0 auto;
background: #f4f4f5;
}
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.cell {
position: relative;
}
.inner {
width: 80px;
height: 80px;
padding: 40px;
text-align: left;
}
.wrapper .cell:nth-child(2n):before{
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
height: 60%;
width: 1px;
background-color:red;
}
<div class="parnet">
<div class="wrapper">
<div class="cell">
<div class="inner">1</div>
</div>
<div class="cell">
<div class="inner">2</div>
</div>
<div class="cell">
<div class="inner">3</div>
</div>
<div class="cell">
<div class="inner">4</div>
</div>
<div class="cell">
<div class="inner">5</div>
</div>
<div class="cell">
<div class="inner">6</div>
</div>
</div>
</div>
I have a grid that I'm trying to add a :before Pseudo Element to create a divider line between each grid cell. I only want the divider lines to show in the center cells and not the outside left and right.
I'm able to achieve this using border-right and then using nth-child(3n) to remove borders. But having trouble trying to do the same using a Pseudo Element
.parent {
background: white;
max-width: 600px;
margin: 0 auto;
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
.cell {
position: relative;
&:before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
height: 60%;
width: 1px;
background-color:red;
}
&:nth-child(3n):before {
width: 0;
}
.inner {
max-width: 320px;
width: 320px;
height: 200px;
padding: 57px 43px 40px;
text-align: left;
}
}
}
}
.parnet{
max-width: 600px;
margin: 0 auto;
background: #f4f4f5;
}
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.cell {
position: relative;
}
.inner {
width: 80px;
height: 80px;
padding: 40px;
text-align: left;
}
.wrapper .cell:before{
content: "";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
height: 60%;
width: 1px;
background-color:red;
}
.wrapper .cell:nth-child(3n):before {
width: 0;
}
<div class="parnet">
<div class="wrapper">
<div class="cell">
<div class="inner">1</div>
</div>
<div class="cell">
<div class="inner">2</div>
</div>
<div class="cell">
<div class="inner">3</div>
</div>
<div class="cell">
<div class="inner">4</div>
</div>
<div class="cell">
<div class="inner">5</div>
</div>
<div class="cell">
<div class="inner">6</div>
</div>
</div>
</div>
So the clue was to set right: 0; on the cell instead of left:0;
Then uses
.wrapper .cell:nth-child(3n):before {
width: 0;
}
Thanks Keith i'm going to score your answer for giving me that great clue.
This is my answer. I'm using the .cell:nth-child(3n):before for the horizontal lines. I hope this is what you need.
.parent {
background: white;
max-width: 600px;
margin: 0 auto;
font-size:2em;
}
.parent .wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.parent .wrapper .cell {
position: relative;
}
.parent .wrapper .cell:before {
content: "";
position: absolute;
right: 50%;
top:.2em;
height: 60%;
width: 1px;
background-color: red;
}
.parent .wrapper .cell:nth-child(3n):before {
width: 300%;
height:1px;
top:100%
}
<div class="parent">
<div class="wrapper">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
<div class="cell">7</div>
<div class="cell">8</div>
<div class="cell">9</div>
</div>
</div>
Instead of having my columns from stacking when the browser viewport shrinks, I want the columns to remain as they are but have a horizontal scroll bar to appear so people on smaller devices can just swipe right to scroll.
Is this possible since I am using flex?
body {
color: #333;
font-family: Helvetica Neue,Arial,Helvetica,sans-serif;
font-size: 14px;
line-height: 20px;
font-weight: 400;
}
.board-container {
background-color: rgb(0, 121, 191);
height: 100%;
position: relative;
background-size: cover;
overflow: hidden;
}
#board-surface {
display: flex;
flex-direction: column;
}
#board-surface, body, html {
height: 100%;
}
#content {
flex-grow: 1;
overflow-y: auto;
outline: none;
}
.board-wrapper {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.board-main-content {
height: 100%;
display: flex;
flex-direction: column;
margin-right: 0;
transition: margin .1s ease-in;
}
.board-canvas {
position: relative;
flex-grow: 1;
}
/*#board {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
margin-bottom: 8px;
overflow-x: auto;
overflow-y: hidden;
padding-bottom: 8px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}*/
.list-wrapper {
width: 272px;
margin: 0 4px;
height: 100%;
box-sizing: border-box;
display: inline-block;
vertical-align: top;
white-space: nowrap;
background-color: #cccccc;
}
.list {
background: #e2e4e6;
border-radius: 3px;
box-sizing: border-box;
display: flex;
flex-direction: column;
max-height: 100%;
position: relative;
white-space: normal;
}
.list-card {
background-color: #fff;
border-radius: 3px;
box-shadow: 0 1px 0 #ccc;
cursor: pointer;
display: block;
margin-bottom: 8px;
max-width: 300px;
min-height: 20px;
position: relative;
text-decoration: none;
z-index: 0;
}
<html>
<head>
<title></title>
</head>
<body>
<div class="board-container">
<div class="board-inner">
<div id="board-surface">
<div id="header">
main header goes here
</div>
<div id="content">
<div class="board-wrapper">
<div class="board-main-content">
<div class="board-header">board header</div>
<div class="board-canvas">
<div id="board">
<div class="list-wrapper">
<div class="list">
<div class="list-header">list header</div>
<div class="list-cards">
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
</div>
</div>
</div> <!-- /list-wrapper -->
<div class="list-wrapper">
<div class="list">
<div class="list-header">list header</div>
<div class="list-cards">
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
</div>
</div>
</div> <!-- /list-wrapper -->
<div class="list-wrapper">
<div class="list">
<div class="list-header">list header</div>
<div class="list-cards">
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
</div>
</div>
</div> <!-- /list-wrapper -->
<div class="list-wrapper">
<div class="list">
<div class="list-header">list header</div>
<div class="list-cards">
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
<div class="list-card">
this is a list card
</div>
</div>
</div>
</div> <!-- /list-wrapper -->
</div> <!-- /board-->
</div>
</div>
</div>
</div>
<div id="footer">
</div>
</div>
</div>
</div>
</body>
</html>
DEMO: https://codepen.io/anon/pen/wxJGMx?editors=0110
I was able to achieve a horizontal scroll on flex container. I've given min-width to .list-wrapper and have added the below styles to #board item:
.list-wrapper {
min-width: 272px;
width: 272px;
margin: 0 4px;
height: 100%;
box-sizing: border-box;
display: inline-block;
vertical-align: top;
white-space: nowrap;
background-color: #cccccc;
}
#board {
display: flex;
overflow: scroll;
}
I have container with div elemenents
.container {
display: flex;
justify-content: space-between;
}
How to make one element positioned at the center on this block, and others to be space-between.
.container {
display: flex;
justify-content: space-between;
}
.container div {
height: 50px;
}
.one,
.four,
.seven {
background-color: red;
width: 200px;
}
.two,
.six {
background-color: green;
width: 100px;
}
.three,
.five {
background-color: yellow;
width: 150px;
}
.center {
width: 300px;
background-color: black;
}
<div class="container">
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
<div class="center"></div>
<div class="four"></div>
<div class="five"></div>
<div class="six"></div>
<div class="seven"></div>
</div>
jsFiddle
Based on how dynamic you want this to be, here is a suggestion where the items on the left and on the right side of the center element are wrapped.
The left and right get 50% each minus the width of the center (150px for each side), which will put the center in the middle.
Updated fiddle
Stack snippet
.container {
display: flex;
justify-content: space-between;
}
.container div {
height: 50px;
}
.left, .right {
display: flex;
justify-content: space-between;
flex-basis: calc(50% - 150px);
}
.one,
.four,
.seven {
background-color: red;
flex-basis: 200px;
}
.two,
.six {
background-color: green;
flex-basis: 100px;
}
.three,
.five {
background-color: yellow;
flex-basis: 150px;
}
.center {
flex-basis: 300px;
background-color: black;
}
<div class="container">
<div class="left">
<div class="one">
</div>
<div class="two">
</div>
<div class="three">
</div>
</div>
<div class="center">
</div>
<div class="right">
<div class="four">
</div>
<div class="five">
</div>
<div class="six">
</div>
<div class="seven">
</div>
</div>
</div>
By adding a pseudo to each side wrapper, we can also make it behave similar to how space-between work without the wrappers (though still with center centered).
In this fiddle demo (and below Stack snippet) I changed the width's so one easier can see how it behaves in full screen.
.container {
display: flex;
justify-content: space-between;
}
.container div {
height: 50px;
}
.left, .right {
display: flex;
justify-content: space-between;
flex-basis: calc(50% - 100px);
}
.left::after,
.right::before {
content: '';
}
.one,
.four,
.seven {
background-color: red;
flex-basis: 125px;
}
.two,
.six {
background-color: green;
flex-basis: 25px;
}
.three,
.five {
background-color: yellow;
flex-basis: 75px;
}
.center {
flex-basis: 200px;
background-color: black;
}
<div class="container">
<div class="left">
<div class="one">
</div>
<div class="two">
</div>
<div class="three">
</div>
</div>
<div class="center">
</div>
<div class="right">
<div class="four">
</div>
<div class="five">
</div>
<div class="six">
</div>
<div class="seven">
</div>
</div>
</div>
I have a problem, i want to set 3 floated divs and on the bottom I would like to have a footer. So I got these two solutions, but it does not work. Please check out the image:
Here the problem is that the content is not not cleared, so the footer does not change position:
<div class="container">
<div class="left"><div class="content"><div class="right">
<div style="clear:left;"></div>
</div>
<div class="footer"></div>
.container {
height: auto !important;
min-height: 100%;
}
.left {
float: left;
width: 20%;
max-width: 200px;
}
.center {
float: left;
width: 80%;
max-width: 500px;
}
.right {
width: auto;
}
.content {
height: auto !important;
height: 100%;
min-height: 100%;
}
.footer {
height: 202px;
margin: -202px auto 0;
position: relative;
}
If i clear the content, I get the result that the right div goes to the next line:
thanks!
I played around a little bit. I think your html structure wasn't right for the effect you were trying to create.
Here is a new example:
HTML
<div class="container">
<div class="left">
</div>
<div class="center">
</div>
<div class="right">
</div>
<div style="clear">
<div class="content">
</div>
<div class="footer">
</div>
</div>
CSS
.container {
height: auto !important;
min-height: 100%;
}
.left {
float: left;
width: 20%;
max-width: 200px;
min-height: 100px;
background: red;
}
.center {
float: left;
width: 80%;
max-width: 500px;
min-height: 100px;
background: blue;
}
.right {
width: auto;
min-height: 100px;
background: green;
}
.content {
height: auto !important;
height: 100%;
min-height: 100px;
width: 80%;
max-width: 500px;
margin: 0 auto;
background: yellow;
}
.footer {
height: 202px;
margin: 0 auto;
position: relative;
background: purple;
}
I rearanged everything in this fiddle:
http://jsfiddle.net/LJQCx/2/
I hope this is what you trying to achiev.
Here is the code hope it will help check the fiddle
<div class="page-wrap">
<div class="container">
<div class="left">
<p>I am Left</p>
</div>
<div class="center">
<p>I am Center</p>
</div>
<div class="right">
<p>I am Right</p>
</div>
<div class="clear"></div>
</div>
</div>
<div class="footer">
<p>I am Footer</p>
</div>
* { margin: 0;}
html, body { height: 100%;}
.page-wrap {min-height: 100%;/* equal to footer height */margin-bottom: -142px; }
.page-wrap:after { content: ""; display: block;}
.footer, .page-wrap:after { /* .push must be the same height as footer */ height: 142px;}
.site-footer {}
.container{ width:100%;}
.left{ float:left; width:25%;}
.center{float:left; width:50%;}
.right{float:left; width:25%;}