Fill flexible container with centered square component - html

What I try to achieve is shown on following pictures:
Outer rectangle is a div container that can have any size and ratio (it gets resized with browser window resizing), and inside is a component (filled on pictures) that should maintain a 1:1 ratio (square), and should be centered in the container. So its sides are described with the formula min(container_width, container_height).
Any ideas on how to do this?

This can be achieved with a combination of three things:
Flexbox
CSS variables
The calc() function
Flexbox can be used to ensure that the inner element is both horizontally and vertically centered. This is achieved with only three different rules on the container:
display: flex;
align-items: center;
justify-content: center;
The key to making the inner element stay square while the parent has a variable width is to base both thew width and height of the child off of the height of the parent.
In the following, I'm basing both the width and height of the inner square off of the height of the parent container (divided by four). Considering the height and width of the child is defined by the same --value as the height of the parent, it will always remain square and proportionate:
:root {
--value: 200px;
}
.container {
display: flex;
align-items: center;
justify-content: center;
border: 2px solid black;
height: var(--value);
}
.box {
background: black;
height: calc(var(--value) / 4);
width: calc(var(--value) / 4);
}
<div class="container">
<div class="box">
</div>
</div>
Note that this will also work if you base your CSS variable off of the viewport height with the vh unit:
:root {
--value: 50vh;
}
.container {
display: flex;
align-items: center;
justify-content: center;
border: 2px solid black;
height: var(--value);
}
.box {
background: black;
height: calc(var(--value) / 4);
width: calc(var(--value) / 4);
}
<div class="container">
<div class="box">
</div>
</div>
Hope this helps! :)

I think you can achieve your goal with the following code. You will need to set your image as the background of the inner div instead of using a <img> directly.
.wrapper {
width: 100%;
height: 300px;
padding: 10px;
box-sizing: border-box;
border: 1px solid red;
}
.inner {
background: url('http://lorempixel.com/output/abstract-q-c-300-300-7.jpg') no-repeat center center;
background-size: contain;
width: 100%;
height: 100%;
}
<div class="wrapper">
<div class="inner"></div>
</div>
Solution 2: using <img> and set the position to absolute.
.wrapper {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 300px;
border: 1px solid red;
box-sizing: border-box;
}
.wrapper img {
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
max-width: 100%;
max-height: 100%;
}
<div class='wrapper'>
<img src='http://lorempixel.com/output/abstract-q-c-300-300-7.jpg'>
</div>

You can do it like this:
html, body {width:100%;margin:0}
.container {
position: relative;
height: 300px; /* needs to be at least the height of the image */
max-height: 100vh; /* enables vertical responsiveness */
border: 1px solid Skyblue;
}
img {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%); /* perfectly centered inside the container */
display: block; /* removes bottom margin/white-space */
max-width: 100%; /* horizontal responsiveness */
max-height: 100vh; /* vertical responsiveness */
}
<div class="container">
<img src="http://lorempixel.com/300/300" alt="">
</div>

If the square is an image in this case you can do something like this :
.container {
position:relative;
text-align: center;
border: 1px solid;
background:#f2f2f5;
}
img {
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
max-height: 100%;
max-width: 100%;
}
<div class="container" style="width:400px;height:100px;">
<img src="https://lorempixel.com/400/400/" />
</div>
<div class="container" style="width:200px;height:400px;">
<img src="https://lorempixel.com/400/400/" />
</div>
<div class="container" style="width:400px;height:400px;">
<img src="https://lorempixel.com/400/400/" />
</div>
<div class="container" style="width:50px;height:600px;">
<img src="https://lorempixel.com/400/400/" />
</div>
<div class="container" style="width:600px;height:50px;">
<img src="https://lorempixel.com/400/400/" />
</div>
You need to pay attention when using 100% with height as this will depend on the parent of the container and if nothing specified the height will be 0 and thus the image too :
.container {
position: relative;
text-align: center;
border: 1px solid;
background: #f2f2f5;
}
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-height: 100%;
max-width: 100%;
}
<!-- this one will not show -->
<div class="container" style="height:100%;">
<img src="https://lorempixel.com/400/400/" />
</div>
<div style="height:200px">
<!-- this one will show -->
<div class="container" style="height:100%;">
<img src="https://lorempixel.com/400/400/" />
</div>
</div>
if you want to use a div instead of image you can consider the image inside the div and use fit-content value for the width/height and the trick is to make the image not visible and add another div for text content (or anything else).
Pay attention as fit-content is not a standard so not supported by all browser. So you can consider this solution as a pseudo-solution than a generic one
.container {
position: relative;
text-align: center;
border: 1px solid;
background: #f2f2f5;
}
.content {
display: block;
background: red;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-height: 100%;
max-width: 100%;
height: fit-content;
width: fit-content;
}
.content img {
visibility: hidden;
z-index: -999;
position: relative;
max-height: 100%;
max-width: 100%;
}
.text {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
<div class="container" style="width:400px;height:100px;">
<div class="content">
<img src="https://lorempixel.com/400/400/" />
<div class="text"> lorem ipsum lorem ipsum </div>
</div>
</div>
<div class="container" style="width:200px;height:400px;">
<div class="content">
<img src="https://lorempixel.com/400/400/" />
<div class="text"> lorem ipsum lorem ipsum </div>
</div>
</div>
<div class="container" style="width:400px;height:400px;">
<div class="content">
<img src="https://lorempixel.com/400/400/" />
<div class="text"> lorem ipsum lorem ipsum </div>
</div>
</div>
<div class="container" style="width:50px;height:600px;">
<div class="content">
<img src="https://lorempixel.com/400/400/" />
<div class="text"> lorem ipsum lorem ipsum </div>
</div>
</div>
<div class="container" style="width:600px;height:50px;">
<div class="content">
<img src="https://lorempixel.com/400/400/" />
<div class="text"> lorem ipsum lorem ipsum </div>
</div>
</div>

Related

CSS: Make image fit the proper area with the absolutely positioned label on the picture

On my webpage there is an area and I'd like to add a image to it. I don't know the image's size and orientation (portrait or landscape). But I want it to fit the area as it is displayed in the picture:
So, if an image has a landscape orientation it must fill the whole width of the area. See picture 1. If the image's width is bigger that the area's width the image's width must be constrained and if its width is smaller - the image must be widened. However if the image's height is bigger than the area's one the image's height must be constrained. See picture 2.
The similar I want for the portrait image. See picture 2.
In short, what I want can be easily done with object-fit: contain;.
.wrapper {
width: 30%;
height: 400px;
overflow: hidden;
border: 1px solid black;
position: relative;
}
.img {
width: 100%;
height: 100%;
object-fit: contain;
}
.label {
position: absolute;
top: 0;
right: 0;
padding: 15px;
background-color: #cccccc;
}
<div class="wrapper">
<img class="img" src="https://images.unsplash.com/photo-1500622944204-b135684e99fd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80" alt="">
<span class="label">Label</span>
</div>
Here is the CodePen: see the code
But the problem is that I have a label to each picture and I want it to be on the top-right corner of the picture and not the area.
Is there any way to do this with CSS only?
Any help would appreciated! Thank you in advance!
instead of the object-fit: contain; replace it with background-size:cover in the img selector css file.
You can wrap the image with a div that has a display: inline-block rule, that will force the div to fit the image scale, then, in this div add another div for the label and position it with absolute.
.cont {
width: 300px;
height: 250px;
background-size: contain;
background-repeat: no-repeat;
margin: 20px;
border: 3px solid black;
display: flex;
align-items: center;
justify-content: center;
}
div .image-cont {
display: inline-block;
position: relative;
}
img {
max-width: 300px;
max-height: 250px;
width: auto;
height: auto;
}
.label {
background-color: yellow;
padding: 5px;
position: absolute;
top: 0;
right: 0;
}
<div class="cont">
<div class="image-cont">
<img src="https://image.shutterstock.com/image-photo/beautiful-abstract-grunge-decorative-navy-260nw-539880832.jpg" />
<div class="label">Label</div>
</div>
</div>
<div class="cont">
<div class="image-cont">
<img src="https://i.pinimg.com/originals/1b/30/80/1b30806bed30a7d071752948d00e75f8.jpg" />
<div class="label">Label</div>
</div>
</div>
You can do the following:
Wrap image and .label span with another span with class e.g. .inner-wrapper and add to its css
position: relative;
height: 100%;
Remove from .wrapper css position: relative; and add
display: flex;
justify-content: center;
Replace in .img css width: 100%;height: 100%; with max-width: 100%;max-height: 100%;
Look in the snippet in full page mode and resize the window.
.wrapper,
.wrapper200 {
width: 30%;
height: 400px;
overflow: hidden;
border: 1px solid black;
/*position: relative;*/
display: flex;
justify-content: center;
}
.wrapper200 {
height: 200px;
}
.inner-wrapper {
position: relative;
height: 100%;
}
.img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.label {
position: absolute;
top: 0;
right: 0;
padding: 15px;
background-color: #cccccc;
}
/* for visual illustration */
.container {
display: flex;
justify-content: space-evenly;
padding: 10px;
outline: dashed red 1px;
margin-bottom: 25px;
}
<h1>Heigth: 200px</h1>
<div class="container">
<div class="wrapper200">
<span class="inner-wrapper">
<img class="img" src="https://images.unsplash.com/photo-1500622944204-b135684e99fd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80" alt="">
<span class="label">Label</span>
</span>
</div>
<div class="wrapper200">
<span class="inner-wrapper">
<img class="img" src="https://images.unsplash.com/photo-1581622634376-ff17d073c4f7?ixlib=rb-1.2.1&auto=format&fit=crop&w=1832&q=80" alt="">
<span class="label">Label</span>
</span>
</div>
</div>
<h1>Heigth: 400px</h1>
<div class="container">
<div class="wrapper">
<span class="inner-wrapper">
<img class="img" src="https://images.unsplash.com/photo-1500622944204-b135684e99fd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80" alt="">
<span class="label">Label</span>
</span>
</div>
<div class="wrapper">
<span class="inner-wrapper">
<img class="img" src="https://images.unsplash.com/photo-1581622634376-ff17d073c4f7?ixlib=rb-1.2.1&auto=format&fit=crop&w=1832&q=80" alt="">
<span class="label">Label</span>
</span>
</div>
</div>
You should try to use background-image instead of a single image
.wrapper {
width: 30%;
height: 400px;
overflow: hidden;
border: 1px solid black;
position: relative;
}
.img {
width: 100%;
height: 100%;
object-fit: contain;
background-size: contain;
background-repeat: no-repeat;
position: absolute;
top: 10%;
}
.label {
position: absolute;
top: 0;
right: 0;
padding: 15px;
background-color: #cccccc;
}
<div class="wrapper">
<div class="img" style="background-image:url(https://images.unsplash.com/photo-1500622944204-b135684e99fd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80)" alt="">
<span class="label">Label</span>
</div>
</div>

How to split web page screen horizontally into 3 equal pieces?

I am trying to split the screen horizontally into 3 equal pieces so I can place separate images into each piece. I have split the screen somewhat equally, but I am running into some issues with a white space and not being split equally.
Here is what I have:
HTML:
<div class="split left">
<div class="centered">
<img src="img_avatar2.png" alt="Avatar woman">
</div>
</div>
<div class="split center">
<div class="centered">
<img src="img_avatar.png" alt="Avatar man">
</div>
</div>
<div class="split right">
<div class="centered">
<img src="golf_course.jpg" alt="Finished Terrain Golf Course">
</div>
</div>
CSS:
/* Split the screen into thirds*/
.split {
height: 100%;
width: 33.3333%;
position: fixed;
z-index: 1;
top: 0;
overflow-x: hidden;
padding-top: 20px;
}
/* Control the left side */
.left {
left: 0;
background-color: #111;
}
/* Control the right side */
.right {
right: 0;
background-color: red;
}
.center {
right:auto;
left:auto;
background-color:wheat;
}
/* If you want the content centered horizontally and vertically */
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
/* Style the image inside the centered container, if needed */
.centered img {
width: 150px;
border-radius: 50%;
}
Image:
You can use flexbox:
.container {
display: flex;
justify-content: space-between;
}
.container div {
width: 100%;
padding: 5px;
border: 1px solid black;
}
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
You can use grid :
https://css-tricks.com/snippets/css/complete-guide-grid/
in grid you can divide your grid.
*doesn"t work with older browsers like ie11
First, width: available is not valid property. if you want to use all available space you should set width: 100%. anyway, for solving your issue you should use height: 100% also for body and html. see this example:
body, html {
width: 100%;
height: 100%;
margin: 0;
}
.container {
width: 100%;
height: 100%;
}
.leftpane {
width: 33%;
height: 100%;
float: left;
background-color: rosybrown;
border-collapse: collapse;
}
.middlepane {
width: 33%;
height: 100%;
float: left;
background-color: royalblue;
border-collapse: collapse;
}
.rightpane {
width: 33%;
height: 100%;
position: relative;
float: right;
background-color: yellow;
border-collapse: collapse;
}
<div class="container">
<div class="leftpane">
<h1>Test Page</h1></div>
<div class="middlepane">Test Page</div>
<div class="rightpane">
<h1>Test Page</h1></div>
</div>

Image halfway on top of DIV

In my application I have a centered main div. Now I would like to get my logo halfway on top of the DIV. As shown in the picture:
I got this working, however, when my screensize changes, the image is located on the wrong place.
<div class="is-vertical-center">
<div class="box">
<div class="text-center">
<img class="img-on-top" src="assets/logo.png">
</div>
<div class="router-outlet">
<div class="pure-g">
<div class="pure-u-1-1">
<h5>Start</h5>
</div>
</div>
<div class="pure-g">
<div class="pure-u-1-1">
<p>
Welcome Lorem ipsum
</p>
</div>
</div>
</div>
</div>
</div>
CSS:
.is-vertical-center {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.box {
background-color: $color-ts-main-flat;
border: 1px solid $color-ts-main-border;
border-radius: 4px;
max-width: 30%;
padding: 20px;
}
.text-center {
text-align: center !important;
}
.img-on-top {
top:0;
margin-top:5%;
position:absolute;
right: 50%;
}
.router-outlet {
flex: 1 0 100px;
background-color:blue;
/* stretch element immediately following the router-outlet element within the same parent element.
* This is the element injected by angular (Assumption)
*/
router-outlet + * {
height: 100%;
width: 100%;
}
}
I made a fiddle, can someone point me in the right direction?
https://jsfiddle.net/x78a3oyj/
Thanks in advance.
add transform3d the the child element
.img-on-top {
top: 0;
transform: translate3d(-50%, -50%, 0);
position: absolute;
left: 50%;/*change to left*/
width: 60px; /*set a width*/
background: hsl(106, 100%, 34%);
}
then on the parent element, set position relative
.box {
background-color: $color-ts-main-flat;
border: 1px solid $color-ts-main-border;
border-radius: 4px;
max-width: 30%;
padding: 20px;
position: relative;/*add this*/
background: hsl(0, 100%, 50%);
margin-top: 3rem;
}
you here is the final code:
.is-vertical-center {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.box {
background-color: $color-ts-main-flat;
border: 1px solid $color-ts-main-border;
border-radius: 4px;
max-width: 30%;
padding: 20px;
position: relative;
background: hsl(0, 100%, 50%);
margin-top: 3rem;
}
.text-center {
text-align: center !important;
}
.img-on-top {
top: 0;
transform: translate3d(-50%, -50%, 0);
position: absolute;
left: 50%;
width: 60px;
height: 60px;
background: hsl(106, 100%, 34%);
}
.router-outlet {
flex: 1 0 100px;
background-color:blue;
/* stretch element immediately following the router-outlet element within the same parent element.
* This is the element injected by angular (Assumption)
*/
router-outlet + * {
height: 100%;
width: 100%;
}
}
<div class="is-vertical-center">
<div class="box">
<div class="text-center">
<img class="img-on-top" src="assets/logo.png">
</div>
<div class="router-outlet">
<div class="pure-g">
<div class="pure-u-1-1">
<h5>Start</h5>
</div>
</div>
<div class="pure-g">
<div class="pure-u-1-1">
<p>
Welcome Lorem ipsum
</p>
</div>
</div>
</div>
</div>
</div>
You can use this code - top image
body {
margin: 0;
}
.is-vertical-center {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.box {
background-color: $color-ts-main-flat;
border: 1px solid $color-ts-main-border;
border-radius: 4px;
max-width: 30%;
padding: 20px;
}
.text-center {
text-align: center !important;
}
.img-on-top {
top: 10px;
margin-top: 0;
position: absolute;
right: 50%;
}
.router-outlet {
flex: 1 0 100px;
background-color: blue;
/* stretch element immediately following the router-outlet element within the same parent element.
* This is the element injected by angular (Assumption)
*/
}
.router-outlet+* {
height: 100%;
width: 100%;
}
<div class="is-vertical-center">
<div class="box">
<div class="text-center">
<img class="img-on-top" src="assets/logo.png">
</div>
<div class="router-outlet">
<div class="pure-g">
<div class="pure-u-1-1">
<h5>Start</h5>
</div>
</div>
<div class="pure-g">
<div class="pure-u-1-1">
<p>
Welcome Lorem ipsum
</p>
</div>
</div>
</div>
</div>
</div>

Centered text overlay on image that is object-fit & object-position (CSS GRID)

I'm wondering if it's possible to have a centered text overlay (caption) on an image that is object-fit: contain; AND object-position: left top; (ie. not centered)
Image is being displayed in CSS Grid. (Display: Grid;)
Example of what I'm trying to do:
.container {
height: 40vw;
width: 40vw;
border: 1px solid black;
display:grid;
}
img {
max-width: 100%;
max-height:100%;
height: 100%;
width: 100%;
object-fit: contain;
object-position: left top;
}
<div class="container">
<img src="https://ichef.bbci.co.uk/news/660/cpsprodpb/A825/production/_103954034_gettyimages-990971906.jpg">
</div>
Thank you in advance!
object-fit controls how replaced content fits within its container. You do not have access to the replaced content in terms of layout and positioning. A way to achieve the effect you're wanting within a grid would be to add a new container, set some width/height attributes on your image based on the container values and then position your text relative to that image, avoiding the use of Object Fit.
.container {
align-items: start;
height: 40vw;
width: 40vw;
border: 1px solid black;
display:grid;
}
img {
display: block;
height: auto;
margin: 0 auto;
max-height: 40vw;
max-width: 40vw;
}
.textcontainer {
position: relative;
}
.textcontainer-x-text {
color: limegreen;
font-family: sans-serif;
font-weight: bold;
left: 50%;
position: absolute;
text-align: center;
text-transform: uppercase;
top: 50%;
transform: translate(-50%, -50%);
}
<p>Portrait</p>
<div class="container">
<div class="textcontainer">
<div class="textcontainer-x-text">Example Text Which Could Be Long</div>
<img src="http://placehold.it/150x400">
</div>
</div>
<p>Landscape</p>
<div class="container">
<div class="textcontainer">
<div class="textcontainer-x-text">Example Text Which Could Be Long</div>
<img src="http://placehold.it/300x150">
</div>
</div>
<p>Square</p>
<div class="container">
<div class="textcontainer">
<div class="textcontainer-x-text">Example Text Which Could Be Long</div>
<img src="http://placehold.it/300x300">
</div>
</div>
Here's one of the many solutions:
Use the position: relative; on the .container, then position: absolute; on the text (here I used a h3) to relocate it, using a -10vh from top.
HTML:
<div class="container">
<img src="https://ichef.bbci.co.uk/news/660/cpsprodpb/A825/production/_103954034_gettyimages-990971906.jpg">
<h3>LOREM IMPSUM</h3>
</div>
CSS:
.container {
height: 40vw;
width: 40vw;
border: 1px solid black;
display:grid;
position: relative;
}
img {
max-width: 100%;
max-height:100%;
height: 100%;
width: 100%;
object-fit: contain;
object-position: left top;
}
h3 {
position: absolute;
left: 50%;
transform: translate(-50%, -10vw);
top: 20vw;
}

Extend one div (among others) beyond parent container

I have a certaing layout of nested divs. One of them I would like to expand beyond its parent. However, with this nesting it's not that simple - I think.
Html:
<div class="wrapper">
<div class="gridcontent">
<div class="gcrow single-column">
<div class="gccolumn">
<div class="gccolumn-inner">
<div class="gcitem">
<p>Extend to .wrapper width</p>
</div>
</div>
</div>
</div>
</div>
</div>
I can't change the html, and there may be other .gcrows that need to stay inside the container. Is this possible to to at all?
Fiddle here.
I hope my question makes sense.
For your current HTML structure you can use .gcrow:first-child and set min-width: 100vw which is same as wrapper width if you remove default margin and padding from html, body.
You can use position: relative, left: 50% and to make it center just add transform: translateX(-50%), here is Fiddle
body,
html {
margin: 0;
padding: 0;
}
* {
box-sizing: border-box;
}
.wrapper {
width: 100%;
padding-left: 20px!important;
padding-right: 20px!important;
border: 1px solid pink;
}
.gridcontent {
width: 100%;
max-width: 1018px;
border: 1px solid #333;
margin: 0 auto;
}
.gcrow {
max-width: 100%;
width: 100%;
border: 1px solid #f00;
}
.gcrow:first-child {
min-width: 100vw;
position: relative;
left: 50%;
transform: translateX(-50%);
}
<div class="wrapper">
<div class="gridcontent">
<div class="gcrow single-column">
<div class="gccolumn">
<div class="gccolumn-inner">
<div class="gcitem">
<p>Extend to .wrapper width</p>
</div>
</div>
</div>
</div>
<div class="gcrow single-column">
<div class="gccolumn">
<div class="gccolumn-inner">
<div class="gcitem">
<p>Leave me alone</p>
</div>
</div>
</div>
</div>
</div>
</div>
Also its box-sizing: border-box not box-border
try something like this
.gcrow {
position: relative;
overflow: visible;
}
.gcitem {
position: absolute;
right: 0;
top: 0;
}