How to insert an image in a DIV keeping the aspect ratio of the tags? - css

I made this code:
<div id="divImage" style="background-color: skyblue;height: 200px;">
<div style="background-color: red;width: 8%;height: 60px;margin-left: 20px; position: relative;top:50%;margin-right: auto;transform: translateY(-50%);"></div>
<div style="background-color: red;width: 8%;height: 60px;margin-right: 20px; position: relative;top:50%;margin-left: auto;transform: translateY(-150%);"></div>
</div>
I need to insert an image in the divImage with a width of 100%. For this, it is necessary that the divImage height is not fixed (height: 200px;). My intention is to make this divImage adapt to any screen size (in%).

You can force your box to keep an aspect ratio using its pseudo elements. Here the before element will always have a certain padding top which makes the box take up its height in relation to its width because the 100% in the equation always refers to the container's width.
.divImage {
&:before {
// Change this line to adjust the aspect ratio
// 1px / 1px will for example give you a square box.
// The first value refers to the height-part
padding-top: 5px / 10px * 100%;
content: "";
width: 1px;
margin-left: -1px;
float: left;
height: 0;
}
&:after { /* to clear float */
content: "";
display: table;
clear: both;
}
}
If you want to use an image in the div that covers the box add also this:
.divImage {
position: relative;
img {
position:absolute;
width: 100%;//might not be necessary, just check if it works without
height: 100%;//might not be necessary, just check if it works without
object-fit:cover; //or contain if you dont want it to fill the container
}
}

Using JavaScript, you will need to adjust the ratio on a per image basis and when the page resizes.
let ratio = 1.4;
const width = containerWidth.getBoundingClientRect().width;
const imageHeight = `${width * ratio}px`;

Related

ScaleY a svg while followed by the below text divs

I need to change the height of a svg on mousewheel/scroll, but while this svg resizes, I need to make the text below follow this scaleY. I've tried implementing a position: relative but this does not work. How can I do that? Here's a PS of what I try to achieve.
Here's a PS of what I have now - images and text are just placeholder.
This is my relevant HTML code:
<div className="main_container">
<div className="main_container_inner">
<div className="img_container">
<img src={img_link} />
</div>
<div className="text_container">
<h1>fvdfv</h1>
<p>fvdfv</p>
</div>
</div>
</div>
This is my relevant CSS code:
.main_container{
display: block;
position: fixed;
width: 100vw;
}
body{
height: 400vh;
}
.main_container .main_container_inner{
display: inline-flex;
width: 33.33%;
flex-direction: column;
}
.main_container img{
width: 100%;
transform-origin: top;
}
This is what I have for now:
As you can see, when I change the scaleY value of the image, the text does not adjust to the new height.
The issue here is the flex containers do not have a setted height property.
So when you scale an image, it is quite hard to set its container height accordingly, so it "pushes" the other divs below. The image simply overflow its container.
I found a way anyway! Because I sticked (maybe for too long) on that weird challenge.
It requires a couple calculations.
I assumed you wish to scale up for the original height of the image to 100% of the viewport height. This assumption may be wrong... I this case, just play with those calculations. You have the example well commented below.
Another thing I noticed is you seem to use React. If so, I guess you should store the img height and its container height in the component state.
   I'm leaving that challenge to you ;)
// Get the elements
let main_container = document.querySelector(".main_container")
let imgContainer = document.querySelector(".img_container")
let img = document.querySelector(".img_container img")
// Some global variables to be filled when the image has fully loaded or on window resize
let viewportHeight, scrollHeight, scrollable, currentImgHeight, maxScale
// When the img has loaded...
function imgLoaded(){
// Get some dimentions
viewportHeight = window.innerHeight
scrollHeight = document.documentElement.scrollHeight
scrollable = scrollHeight-viewportHeight
// Calculate the maxScale for an img height == 100% of the viewport
currentImgHeight = img.getBoundingClientRect().height
maxScale = viewportHeight/currentImgHeight
// Set an initial height to the .img_container - Same as the img.
imgContainer.style.height = currentImgHeight+"px"
}
// If the image has already fully loaded (cache), else wait for the load event
if(img.complete){
imgLoaded()
}else{
img.addEventListener("load", imgLoaded)
}
// On window resize
window.onresize = function(){
img.style.transform = "scale(1)"
window.scrollTo(0,0)
imgLoaded()
}
// Scroll handler
function scrollHandler(){
// update the current img height value
currentImgHeight = img.getBoundingClientRect().height
// Calculate a new scale for the img -- The +1 is to avoid a negative value at the bottom of the page
let newScale = scrollable/(scrollable + 1 - document.documentElement.scrollTop)
// Apply the newScale if less or equal to maxScale
let scale = (newScale>maxScale)?maxScale:newScale
img.style.transform = `scaleY(${scale.toFixed(3)})`
// Adjust the img_container, so it pushes the div below
imgContainer.style.height = currentImgHeight+"px"
// Just for this demo...
console.log(imgContainer.style.height,scale.toFixed(3)+"% ")
}
// Add the event listener
document.addEventListener("scroll", scrollHandler)
/* Just for this demo... Styling the SO console which is in the way! */
.as-console{
background: transparent !important;
text-align: right;
}
.as-console-wrapper{
max-height: 1em !important;
border-top: 0 !important;
}
.as-console-row-code{
padding: 0 !important;
border: 0 !important;
}
/* added to your CSS */
*{
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Your css unchanged */
.main_container {
display: block;
position: fixed;
width: 100vw;
}
body {
height: 400vh;
}
.main_container .main_container_inner {
display: inline-flex;
width: 33.33%;
flex-direction: column;
}
.main_container img {
width: 100%;
transform-origin: top;
}
<div class="main_container">
<div class="main_container_inner">
<div class="img_container">
<img src="https://via.placeholder.com/400" />
</div>
<div class="text_container">
<h1>fvdfv</h1>
<p>fvdfv</p>
</div>
</div>
</div>
Run in full screen mode! or CodePen

Evaluating percentages to pixels in SASS

Currently, I'm setting a variable to correspond to a circle's width and height, like so:
$circle-diameter: 70%;
.circle {
width: $circle-diameter;
height: $circle-diameter;
}
However, the circle's width becomes 70% of the parent element's width, and the height becomes 70% of the parent element's height, which yields an oval that is wider than it is tall. Ideally, I'd like to convert .circle-diameter to a fixed size and assign the circle's width and height to that fixed size. Is there a solution for this in CSS/SASS?
You can use padding-top instead of height, it will work because padding is relative to parent width.
.circle{
width: 70%;
padding-top: 70%;
/* height: 0; */
}
http://codepen.io/yukulele/pen/PzGgNM
What you are looking for is to have a fixed ratio between width and height. For a circle tho, the width/height ratio is 1. There's a hacky way to accomplish that task. First I'd like to write a css class that always provides us a space that has width/height ratio of 1. To do so:
See Fiddle
Why this works? Because, If you use percentage based units on padding, It always be relative to element's width. See reference
Next I always like to use absolute hack to provide myself a workaround in that nicely 1/1 ratio square that we've create.
See Fiddle 2
Using position: absolute for our own good, we've created a element that has a fixed ratio and has a working width/height properties.
After It depends on what you need to do. In your case I've created a nice circle for to examine the situation.
See Fiddle 3
Working source code
**Css**
.ratio-1 {
position: relative;
width: 100%;
padding-top: 100%;
background-color: silver;
}
.im-something-has-some-width {
width: 200px;
border: 3px solid lime;
}
.space-provider {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.yay-i-have-a-square-field {
// lets use it for our own goods!
width: 100%;
height: 100%;
background-color: skyblue;
border-radius: 50%;
}
Html
<div class="im-something-has-some-width">
<div class="ratio-1">
<div class="space-provider">
<div class="yay-i-have-a-square-field">
</div>
</div>
</div>
</div>

Resize <img> to fit available screen space in smallest dimension with pure CSS [duplicate]

I have made a div (div1), which is equal to the browser window size. Then I have made another div (div2) inside the parent div (div1). Then I have placed an image inside the second div (div2). My browser window size is 1360X638 and my image size is 1600*1200.
I want the image to fit itself according to the parent div's (div1) size. So the image (which is larger than the window size) have to fit itself to the second div (div2), which is equal to window size), and this image will fit exactly to the div's size (so, there isn't any scrolling or cropping of image in the display).
I have searched for some time. The solution I found is to set the maximum height and width to 100%. I did this.
I wrote this part:
<div style="max-width: 100%; max-height: 100%; background-color: red; margin-right: 0px; padding: 2 2 2 2; overflow:visible;">
<div style="max-height: 100%; max-width: 100%;">
<img style="max-width: 100%; max-height: 100%; overflow:visible;" src="1.jpg" />
</div>
</div>
The output is like this:
You can see there is a scroll in the right side. I don't want that there.
jQuery Solution - Proof of Concept
Suppose you have the following HTML:
<div class="container">
<img src="http://placehold.it/1600x1200" />
</div>
You can apply the following CSS rules to size an image to fit the view port (100% of browser width or height):
html, body {
height: 100%;
margin: 0;
}
.container {
height: 100%;
width: 100%;
background-color: red;
text-align: center; /* optional */
}
.container img {
vertical-align: top;
}
.portrait img {
width: 100%;
}
.landscape img {
height: 100%;
}
Use the following jQuery method to pick the correct CSS rule depending on the aspect ratio of the view port:
function resizeImg() {
var thisImg= $('.container');
var refH = thisImg.height();
var refW = thisImg.width();
var refRatio = refW/refH;
var imgH = thisImg.children("img").height();
var imgW = thisImg.children("img").width();
if ( (imgW/imgH) > refRatio ) {
thisImg.addClass("portrait");
thisImg.removeClass("landscape");
} else {
thisImg.addClass("landscape");
thisImg.removeClass("portrait");
}
}
$(document).ready(resizeImg())
$(window).resize(function(){
resizeImg();
});
Demo fiddle: http://jsfiddle.net/audetwebdesign/y2L3Q/
This may not be the entire answer but it may be a place to start.
Reference
I worked on a related problem earlier, which may be of interest:
Make image fill div completely without stretching

How can I fix errors created when using a non-exact decimal in CSS?

I've used the 'target / context = result' trick on a site I'm developing, but I've run into a fairly large issue: the equation returns a percent so long, I can't find a calculator to complete the equation without rounding. As you can see below, I've set the height to a percent instead of auto, as if the value is auto, it will chop of the bottom part of the div, which I need. So, I've set it to the nearest rounded decimal - looks fine at first, then resize and it becomes larger/smaller than I need it to be. For reference for what it should look like, it should be the same height as image next to it. I can't provide the image for copyright reasons, but the image size is 800 by 440 pixels. Just apply the second rule to it. Thanks.
#comment-1 {
width: 6.25%;
height: 30.09781790820166%;
padding: 20px;
float: left;
color: #FFF;
background-color: #CC521D;
font-family: "Lato", Arial, Helvetica, sans-serif;
font-size: 125%;
}
#image-1 {
width: 31.25%;
height: auto;
float: left;
margin-right: 20px;
}
EDIT: Just noticed, I forget to provide the context: the height is 1329px and the width is 2560px.
Height percent will be based on parent element width if parent element height was not set! That means you need another approach, one of the solutions would be: let your image container be relative, with padding left 6.25%, than your comment would be absolute with left, top, bottom: 0 (width can be calculated as 6.25/31.25*100). That way the image height would control comment height.
<style type="text/css">
.comment_and_image {
position: relative;
width: 31.25%;
padding-left: 6.25%;
float: left;
}
.comment {
width: 20%; /* 6.25/31.25*100 */
position: absolute;
left: 0;
top: 0;
bottom: 0;
}
.image {
height: auto;
width: 100%;
}
</style>
<div class="comment_and_image">
<div class="comment">text</div>
<img class="image" src="path_to_image.jpg" alt="Image" />
</div>
I've used skobaljic's answer, just a modified version. I've set the top and bottom rules to 0, as he said, but instead of leaving left at 0, I set the margin-left to 101.875, as it is the width of the image plus 15 pixels, exactly what I needed.

Maintain div aspect ratio according to height

I need to maintain the width of an element as a percentage of its height. So as the height changes, the width is updated.
The opposite is achievable by using a % value for padding-top, but padding-left as a percentage will be a percentage of the width of an object, not its height.
So with markup like this:
<div class="box">
<div class="inner"></div>
</div>
I'd like to use something like this:
.box {
position: absolute;
margin-top: 50%;
bottom: 0;
}
.inner {
padding-left: 200%;
}
To ensure the box's aspect ratio is maintained according to it's height. The height is fluid because of it's % margin - as the window's height changes, the box's height will too.
I know how to achieve this with JavaScript, just wondering if there's a clean CSS-only solution?
You can use an image that has the desired proportions as to help with proportional sizing (images can be scaled proportionally by setting one dimension to some value and other to auto). The image does not have to be visible, but it must occupy space.
.box {
position: absolute;
bottom: 0;
left: 0;
height: 50%;
}
.size-helper {
display: block;
width: auto;
height: 100%;
}
.inner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(255, 255, 153, .8);
}
<div class="box">
<img class="size-helper" src="//dummyimage.com/200x100/999/000" width="200" height="100">
<div class="inner">
1. box has fluid height<br>
2. img has 2:1 aspect ratio, 100% height, auto width, static position<br>
2.1 it thus maintains width = 200% of height<br>
2.2 it defines the dimensions of the box<br>
3. inner expands as much as box
</div>
</div>
In the above example, box, inner and helper are all same size.
You can use vh units for both height and width of your element so they both change according to the viewport height.
vh
1/100th of the height of the viewport. (MDN)
DEMO
.box {
position: absolute;
height:50vh;
width:100vh;
bottom: 0;
background:teal;
}
<div class="box"></div>
There is another, more efficient way to achieve constant aspect ratio according to height.
You can place an empty svg so you dont have to load an external image.
HTML code:
<svg xmlns="http://www.w3.org/2000/svg"
height="100"
width="200"
class='placeholder-svg'
/>
CSS code:
.placeholder-svg {
width: auto;
height: 100%;
}
Change width/height to achieve desired aspect ratio.
Keep in mind, the svg might overflow.
http://www.w3.org/2000/svg is just a namespace. It doesn't load anything.
If you change placeholder-svg class to:
.placeholder-svg {
width: 100%;
height: auto;
}
then height is adjusted according to width.
Demo 1 Width is adjusted according to height and 2:1 aspect ratio.
Demo 2 same as above, but you can resize easily (uses React)
The CSS trick you wrote, works pretty well to keep ratio width / height on an element.
It is based on the padding property that, when its value is in percent, is proportional to parent width, even for padding-top and padding-bottom.
There is no CSS property that could set an horizontal sizing proportionally to the parent height.
So I think there is no clean CSS solution.
As of 2021 there is a property called aspect-ratio.
Most browsers support it
div {
border: 1px solid;
margin: 8px;
}
.box {
width: 100px;
min-height: 100px;
resize: horizontal;
overflow: auto;
}
.inner1 {
aspect-ratio: 1/1;
}
.inner2 {
aspect-ratio: 3/1;
}
<div class="box">
<div class="inner1"></div>
<div class="inner2"></div>
</div>
Run this snippet and resize the outer div manually to see the inner divs behavior
I can't find a pure CSS solution. Here's a solution using CSS Element Queries JavaScript library.
var aspectRatio = 16/9;
var element = document.querySelector('.center');
function update() {
element.style.width = (element.clientHeight * aspectRatio) + 'px';
}
new ResizeSensor(element, update);
update();
CodePen demo!

Resources